diff options
70 files changed, 1642 insertions, 630 deletions
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index e44e7768724e..5147f12018cf 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -104,6 +104,7 @@ import android.debug.IAdbManager; import android.devicelock.DeviceLockFrameworkInitializer; import android.graphics.fonts.FontManager; import android.hardware.ConsumerIrManager; +import android.hardware.ISensorPrivacyManager; import android.hardware.ISerialManager; import android.hardware.SensorManager; import android.hardware.SensorPrivacyManager; @@ -707,8 +708,12 @@ public final class SystemServiceRegistry { registerService(Context.SENSOR_PRIVACY_SERVICE, SensorPrivacyManager.class, new CachedServiceFetcher<SensorPrivacyManager>() { @Override - public SensorPrivacyManager createService(ContextImpl ctx) { - return SensorPrivacyManager.getInstance(ctx); + public SensorPrivacyManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + IBinder b = ServiceManager.getServiceOrThrow( + Context.SENSOR_PRIVACY_SERVICE); + return SensorPrivacyManager.getInstance( + ctx, ISensorPrivacyManager.Stub.asInterface(b)); }}); registerService(Context.STATUS_BAR_SERVICE, StatusBarManager.class, diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 60d1b0d45365..e895d7be1102 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -3141,14 +3141,6 @@ public class IntentFilter implements Parcelable { for (int i = 0; i < N; i++) { mUriRelativeFilterGroups.add(new UriRelativeFilterGroup(source)); } - if (source.dataAvail() > 0) { - Log.e(TAG, "Parcel data not fully consumed after completed reading" - + " UriRelativeFilterGroup data"); - } - } - if (source.dataAvail() > 0) { - Log.e(TAG, "Parcel data not fully consumed when unparceling intent filter", - new Exception()); } } diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java index 4cdaaddd05bf..a4c0e87c965b 100644 --- a/core/java/android/hardware/SensorPrivacyManager.java +++ b/core/java/android/hardware/SensorPrivacyManager.java @@ -797,7 +797,7 @@ public final class SensorPrivacyManager { public void setSensorPrivacy(@Sensors.Sensor int sensor, boolean enable) { setSensorPrivacy(resolveSourceFromCurrentContext(), sensor, enable, - UserHandle.USER_CURRENT); + mContext.getUserId()); } private @Sources.Source int resolveSourceFromCurrentContext() { @@ -837,6 +837,8 @@ public final class SensorPrivacyManager { @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor, boolean enable) { + // TODO(b/348510106): Replace USER_CURRENT with Context user and fix any tests that may be + // affected. setSensorPrivacy(source, sensor, enable, UserHandle.USER_CURRENT); } @@ -894,7 +896,7 @@ public final class SensorPrivacyManager { @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacyForProfileGroup(@Sources.Source int source, @Sensors.Sensor int sensor, boolean enable) { - setSensorPrivacyForProfileGroup(source , sensor, enable, UserHandle.USER_CURRENT); + setSensorPrivacyForProfileGroup(source , sensor, enable, mContext.getUserId()); } /** @@ -950,7 +952,7 @@ public final class SensorPrivacyManager { @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) public void suppressSensorPrivacyReminders(int sensor, boolean suppress) { - suppressSensorPrivacyReminders(sensor, suppress, UserHandle.USER_CURRENT); + suppressSensorPrivacyReminders(sensor, suppress, mContext.getUserId()); } /** diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl index 360b2ac4f3ca..73cdd5682f31 100644 --- a/core/java/android/os/IHintManager.aidl +++ b/core/java/android/os/IHintManager.aidl @@ -33,7 +33,7 @@ interface IHintManager { * if creation is supported but fails. */ IHintSession createHintSessionWithConfig(in IBinder token, in int[] threadIds, - in long durationNanos, in SessionTag tag, out @nullable SessionConfig config); + in long durationNanos, in SessionTag tag, out SessionConfig config); /** * Get preferred rate limit in nanoseconds. @@ -48,6 +48,6 @@ interface IHintManager { * * Throws IllegalStateException if FMQ channel creation fails. */ - ChannelConfig getSessionChannel(in IBinder token); + @nullable ChannelConfig getSessionChannel(in IBinder token); oneway void closeSessionChannel(); } diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index 435770326880..39bd15c968d7 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -107,14 +107,6 @@ flag { } flag { - name: "adpf_fmq_eager_send" - namespace: "game" - description: "Guards the use of an eager-sending optimization in FMQ for low-latency messages" - is_fixed_read_only: true - bug: "315894228" -} - -flag { name: "adpf_hwui_gpu" namespace: "game" description: "Guards use of the FMQ channel for ADPF" diff --git a/core/java/android/os/vibrator/VibrationConfig.java b/core/java/android/os/vibrator/VibrationConfig.java index bc6c5706f6fd..e6e5a27bd731 100644 --- a/core/java/android/os/vibrator/VibrationConfig.java +++ b/core/java/android/os/vibrator/VibrationConfig.java @@ -30,17 +30,13 @@ import static android.os.VibrationAttributes.USAGE_UNKNOWN; import android.annotation.Nullable; import android.content.res.Resources; -import android.os.SystemProperties; import android.os.VibrationAttributes; import android.os.Vibrator; import android.os.Vibrator.VibrationIntensity; import android.util.IndentingPrintWriter; -import com.android.internal.annotations.VisibleForTesting; - import java.io.PrintWriter; import java.util.Arrays; -import java.util.function.Function; /** * List of device-specific internal vibration configuration loaded from platform config.xml. @@ -54,37 +50,6 @@ import java.util.function.Function; public class VibrationConfig { /** - * The default gain to be applied between vibration scale levels. - * - * <p>Scale levels are defined as the difference between the user vibration intensity setting - * and the device default config for each usage. The intensity values are defined as one of - * Vibrator.VIBRATION_INTENSITY_*. - * - * <p>A user setting HIGH set on a device with default value LOW will cause the vibration - * intensity to be scaled up 2 levels, i.e. scale with a factor of gain^2. A system with 3 - * intensities LOW, MEDIUM and HIGH has the following 5 scale levels: - * - * <ol> - * <li>VERY_HIGH: user(HIGH) - device(LOW) - * <li>HIGH: user(HIGH) - device(MEDIUM) / user(MEDIUM) - device(LOW) - * <li>NONE: user == device - * <li>LOW: user(MEDIUM) - device(HIGH) / user(LOW) - device(MEDIUM) - * <li>VERY_LOW: user(LOW) - device(HIGH) - * </ol> - * - * <p>A device will only ever apply 3 out of these 5 levels based on the default intensity - * config set for each usage (e.g. config_default[Alarm|Ring|Notification]VibrationIntensity). - * - * <p>This value must be greater than 1. The {@link #DEFAULT_SCALE_LEVEL_GAIN} will be used if - * this property is undefined or invalid. - * - * @hide - */ - @VisibleForTesting - static final String SCALE_LEVEL_GAIN_SYSTEM_PROPERTY = - "vendor.vibrator.scale.level.gain"; - - /** * Hardcoded default scale level gain to be applied between each scale level to define their * scale factor value. * @@ -104,7 +69,7 @@ public class VibrationConfig { private final int mRampDownDurationMs; private final int mRequestVibrationParamsTimeoutMs; private final int[] mRequestVibrationParamsForUsages; - private final float mDefaultVibrationScaleLevelGain; + private final boolean mIgnoreVibrationsOnWirelessCharger; @VibrationIntensity @@ -124,18 +89,8 @@ public class VibrationConfig { /** @hide */ public VibrationConfig(@Nullable Resources resources) { - this(resources, SystemProperties::get); - } - - /** @hide */ - @VisibleForTesting - public VibrationConfig(@Nullable Resources resources, - Function<String, String> systemPropertiesGetter) { - mDefaultVibrationAmplitude = loadInteger(resources, - com.android.internal.R.integer.config_defaultVibrationAmplitude, - DEFAULT_AMPLITUDE); - mDefaultVibrationScaleLevelGain = loadFloat(systemPropertiesGetter, - SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, DEFAULT_SCALE_LEVEL_GAIN); + mDefaultVibrationAmplitude = resources.getInteger( + com.android.internal.R.integer.config_defaultVibrationAmplitude); mHapticChannelMaxVibrationAmplitude = loadFloat(resources, com.android.internal.R.dimen.config_hapticChannelMaxVibrationAmplitude); mRampDownDurationMs = loadInteger(resources, @@ -180,15 +135,6 @@ public class VibrationConfig { return res != null ? res.getFloat(resId) : 0f; } - private static float loadFloat(Function<String, String> systemPropertiesGetter, - String propertyKey, float defaultValue) { - try { - return Float.parseFloat(systemPropertiesGetter.apply(propertyKey)); - } catch (Exception e) { - return defaultValue; - } - } - private static int loadInteger(@Nullable Resources res, int resId, int defaultValue) { return res != null ? res.getInteger(resId) : defaultValue; } @@ -230,10 +176,8 @@ public class VibrationConfig { * for each level. */ public float getDefaultVibrationScaleLevelGain() { - if (mDefaultVibrationScaleLevelGain <= 1) { - return DEFAULT_SCALE_LEVEL_GAIN; - } - return mDefaultVibrationScaleLevelGain; + // TODO(b/356407380): add device config for this + return DEFAULT_SCALE_LEVEL_GAIN; } /** @@ -326,7 +270,6 @@ public class VibrationConfig { return "VibrationConfig{" + "mIgnoreVibrationsOnWirelessCharger=" + mIgnoreVibrationsOnWirelessCharger + ", mDefaultVibrationAmplitude=" + mDefaultVibrationAmplitude - + ", mDefaultVibrationScaleLevelGain=" + mDefaultVibrationScaleLevelGain + ", mHapticChannelMaxVibrationAmplitude=" + mHapticChannelMaxVibrationAmplitude + ", mRampStepDurationMs=" + mRampStepDurationMs + ", mRampDownDurationMs=" + mRampDownDurationMs @@ -353,7 +296,6 @@ public class VibrationConfig { pw.increaseIndent(); pw.println("ignoreVibrationsOnWirelessCharger = " + mIgnoreVibrationsOnWirelessCharger); pw.println("defaultVibrationAmplitude = " + mDefaultVibrationAmplitude); - pw.println("defaultVibrationScaleLevelGain = " + mDefaultVibrationScaleLevelGain); pw.println("hapticChannelMaxAmplitude = " + mHapticChannelMaxVibrationAmplitude); pw.println("rampStepDurationMs = " + mRampStepDurationMs); pw.println("rampDownDurationMs = " + mRampDownDurationMs); diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index 6c486dbfd7a2..991611a1af10 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -249,3 +249,11 @@ flag { description: "This flag is used to enabled the Wallet Role s icon fetching from manifest property" bug: "349942654" } + +flag { + name: "replace_body_sensors_permission_enabled" + is_exported: true + namespace: "android_health_services" + description: "This flag is used to enable replacing permission BODY_SENSORS(and BODY_SENSORS_BACKGROUND) with granular health permission READ_HEART_RATE(and READ_HEALTH_DATA_IN_BACKGROUND)" + bug: "364638912" +} diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp index c1022a54207d..664d54d374b4 100644 --- a/core/tests/bugreports/Android.bp +++ b/core/tests/bugreports/Android.bp @@ -43,3 +43,10 @@ filegroup { name: "bugreport_artifacts", srcs: ["config/test-sysconfig.xml"], } + +test_module_config { + name: "BugreportManagerTestCases_android_server_os", + base: "BugreportManagerTestCases", + test_suites: ["general-tests"], + exclude_annotations: ["androidx.test.filters.LargeTest"], +} diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 5111d2d1e044..d98836f8ce20 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -303,6 +303,7 @@ test_module_config { name: "FrameworksCoreTests_Presubmit", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -313,6 +314,7 @@ test_module_config { name: "FrameworksCoreTests_inputmethod", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -327,6 +329,7 @@ test_module_config { name: "FrameworksCoreTests_context", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -337,6 +340,7 @@ test_module_config { name: "FrameworksCoreTests_keyguard_manager", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -347,6 +351,7 @@ test_module_config { name: "FrameworksCoreTests_property_invalidated_cache", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -357,6 +362,7 @@ test_module_config { name: "FrameworksCoreTests_android_content", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -371,6 +377,7 @@ test_module_config { name: "FrameworksCoreTests_sqlite", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -381,6 +388,7 @@ test_module_config { name: "FrameworksCoreTests_android_net", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -392,6 +400,7 @@ test_module_config { name: "FrameworksCoreTests_battery_stats", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -403,6 +412,7 @@ test_module_config { name: "FrameworksCoreTests_environment", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -413,6 +423,7 @@ test_module_config { name: "FrameworksCoreTests_util_data_charset", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -426,6 +437,7 @@ test_module_config { name: "FrameworksCoreTests_xml", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -439,6 +451,7 @@ test_module_config { name: "FrameworksCoreTests_util_apk", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -449,6 +462,7 @@ test_module_config { name: "FrameworksCoreTests_textclassifier", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -460,6 +474,7 @@ test_module_config { name: "FrameworksCoreTests_internal_app", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -474,6 +489,7 @@ test_module_config { name: "FrameworksCoreTests_internal_content", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -484,6 +500,7 @@ test_module_config { name: "FrameworksCoreTests_internal_infra", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -494,6 +511,7 @@ test_module_config { name: "FrameworksCoreTests_internal_jank", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -504,6 +522,7 @@ test_module_config { name: "FrameworksCoreTests_internal_os_binder", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -515,6 +534,7 @@ test_module_config { name: "FrameworksCoreTests_internal_os_kernel", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -531,6 +551,7 @@ test_module_config { name: "FrameworksCoreTests_server_power", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -541,6 +562,7 @@ test_module_config { name: "FrameworksCoreTests_internal_security", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -552,6 +574,7 @@ test_module_config { name: "FrameworksCoreTests_internal_util_latency_tracker", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -562,6 +585,7 @@ test_module_config { name: "FrameworksCoreTests_content_capture_options", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -572,6 +596,7 @@ test_module_config { name: "FrameworksCoreTests_android_content_integrity", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -582,6 +607,7 @@ test_module_config { name: "FrameworksCoreTests_android_content_pm_PreSubmit", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -593,6 +619,7 @@ test_module_config { name: "FrameworksCoreTests_android_content_pm_PostSubmit", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -604,6 +631,7 @@ test_module_config { name: "FrameworksCoreTests_android_content_res", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -620,6 +648,7 @@ test_module_config { name: "FrameworksCoreTests_android_content_res_PostSubmit", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -631,6 +660,7 @@ test_module_config { name: "FrameworksCoreTests_android_service", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -650,6 +680,7 @@ test_module_config { name: "FrameworksCoreTests_android_view_contentcapture", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -660,6 +691,7 @@ test_module_config { name: "FrameworksCoreTests_android_view_contentprotection", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -670,6 +702,7 @@ test_module_config { name: "FrameworksCoreTests_com_android_internal_content_Presubmit", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -681,6 +714,7 @@ test_module_config { name: "FrameworksCoreTests_drawable", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -691,6 +725,7 @@ test_module_config { name: "FrameworksCoreTests_accessibility", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -705,6 +740,7 @@ test_module_config { name: "FrameworksCoreTests_usage", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -715,6 +751,7 @@ test_module_config { name: "FrameworksCoreTests_fastdata", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -725,6 +762,7 @@ test_module_config { name: "FrameworksCoreTests_hardware_input", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -735,6 +773,7 @@ test_module_config { name: "FrameworksCoreTests_view_verified", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -745,9 +784,34 @@ test_module_config { } test_module_config { + name: "FrameworksCoreTests_android_net_Presubmit", + base: "FrameworksCoreTests", + test_suites: [ + "automotive-tests", + "device-platinum-tests", + "device-tests", + ], + include_filters: ["android.net"], + include_annotations: ["android.platform.test.annotations.Presubmit"], +} + +test_module_config { + name: "FrameworksCoreTests_content_pm_Postsubmit", + base: "FrameworksCoreTests", + test_suites: [ + "automotive-tests", + "device-platinum-tests", + "device-tests", + ], + include_filters: ["android.content.pm."], + include_annotations: ["android.platform.test.annotations.Postsubmit"], +} + +test_module_config { name: "FrameworksCoreTests_jank", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], @@ -762,6 +826,7 @@ test_module_config { name: "FrameworksCoreTests_Platinum", base: "FrameworksCoreTests", test_suites: [ + "automotive-tests", "device-tests", "device-platinum-tests", ], diff --git a/core/tests/vibrator/src/android/os/vibrator/VibrationConfigTest.java b/core/tests/vibrator/src/android/os/vibrator/VibrationConfigTest.java deleted file mode 100644 index a2ff9d77674a..000000000000 --- a/core/tests/vibrator/src/android/os/vibrator/VibrationConfigTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os.vibrator; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.when; - -import android.content.res.Resources; - -import com.android.internal.R; - -import org.junit.Rule; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; - -import java.util.HashMap; -import java.util.Map; - -public class VibrationConfigTest { - - @Rule - public MockitoRule rule = MockitoJUnit.rule(); - - @Mock - private Resources mResourcesMock; - - private final Map<String, String> mSystemProperties = new HashMap<>(); - - @Test - public void getDefaultVibrationAmplitude_returnsConfiguredAmplitude() { - when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(1); - assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(1); - - when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(123); - assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(123); - - when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(255); - assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(255); - } - - @Test - public void getDefaultVibrationAmplitude_invalidValue_returnsMaxAmplitude() { - when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(-1); - assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(255); - - when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(0); - assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(255); - - when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(500); - assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(255); - } - - @Test - public void getDefaultVibrationScaleLevelGain_returnsConfiguredGain() { - mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "1.2"); - assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.2f); - - mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "2"); - assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(2f); - } - - @Test - public void getDefaultVibrationScaleLevelGain_invalidValue_returnsFixedScaleGain() { - mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, ""); - assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f); - - mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "invalid"); - assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f); - - mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "-1"); - assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f); - - mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "0.5"); - assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f); - - mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "1.0"); - assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f); - } - - private VibrationConfig createConfig() { - return new VibrationConfig(mResourcesMock, mSystemProperties::get); - } -} diff --git a/libs/WindowManager/Jetpack/tests/unittest/Android.bp b/libs/WindowManager/Jetpack/tests/unittest/Android.bp index bc46b70793cd..bd430c0e610b 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/Android.bp +++ b/libs/WindowManager/Jetpack/tests/unittest/Android.bp @@ -62,3 +62,10 @@ android_test { enabled: false, }, } + +test_module_config { + name: "WMJetpackUnitTests_Presubmit", + base: "WMJetpackUnitTests", + test_suites: ["device-tests"], + include_annotations: ["android.platform.test.annotations.Presubmit"], +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithm.java index 133242d15822..a27caf879e8a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithm.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithm.java @@ -57,6 +57,12 @@ public class PhonePipKeepClearAlgorithm implements PipKeepClearAlgorithmInterfac Rect startingBounds = pipBoundsState.getBounds().isEmpty() ? pipBoundsAlgorithm.getEntryDestinationBoundsIgnoringKeepClearAreas() : pipBoundsState.getBounds(); + // If IME is not showing and restore bounds (pre-IME bounds) is not empty, we should set PiP + // bounds to the restore bounds. + if (!pipBoundsState.isImeShowing() && !pipBoundsState.getRestoreBounds().isEmpty()) { + startingBounds.set(pipBoundsState.getRestoreBounds()); + pipBoundsState.clearRestoreBounds(); + } Rect insets = new Rect(); pipBoundsAlgorithm.getInsetBounds(insets); if (pipBoundsState.isImeShowing()) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java index 140d7765e5c1..c487f7543dcf 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java @@ -86,6 +86,7 @@ public class PipBoundsState { @NonNull private final Rect mExpandedBounds = new Rect(); @NonNull private final Rect mNormalMovementBounds = new Rect(); @NonNull private final Rect mExpandedMovementBounds = new Rect(); + @NonNull private final Rect mRestoreBounds = new Rect(); @NonNull private final PipDisplayLayoutState mPipDisplayLayoutState; private final Point mMaxSize = new Point(); private final Point mMinSize = new Point(); @@ -404,6 +405,10 @@ public class PipBoundsState { public void setImeVisibility(boolean imeShowing, int imeHeight) { mIsImeShowing = imeShowing; mImeHeight = imeHeight; + // If IME is showing, save the current PiP bounds in case we need to restore it later. + if (mIsImeShowing) { + mRestoreBounds.set(getBounds()); + } } /** Returns whether the IME is currently showing. */ @@ -411,6 +416,16 @@ public class PipBoundsState { return mIsImeShowing; } + /** Returns the bounds to restore PiP to (bounds before IME was expanded). */ + public Rect getRestoreBounds() { + return mRestoreBounds; + } + + /** Sets mRestoreBounds to (0,0,0,0). */ + public void clearRestoreBounds() { + mRestoreBounds.setEmpty(); + } + /** Returns the IME height. */ public int getImeHeight() { return mImeHeight; @@ -521,6 +536,10 @@ public class PipBoundsState { /** Set whether the user has resized the PIP. */ public void setHasUserResizedPip(boolean hasUserResizedPip) { mHasUserResizedPip = hasUserResizedPip; + // If user resized PiP while IME is showing, clear the pre-IME restore bounds. + if (hasUserResizedPip && isImeShowing()) { + clearRestoreBounds(); + } } /** Returns whether the user has moved the PIP. */ @@ -531,6 +550,10 @@ public class PipBoundsState { /** Set whether the user has moved the PIP. */ public void setHasUserMovedPip(boolean hasUserMovedPip) { mHasUserMovedPip = hasUserMovedPip; + // If user moved PiP while IME is showing, clear the pre-IME restore bounds. + if (hasUserMovedPip && isImeShowing()) { + clearRestoreBounds(); + } } /** diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java index 8c7b47ea7d84..e3798e92c092 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java @@ -109,6 +109,7 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { final Rect pipBounds = new Rect(0, 0, 100, 100); final Rect keepClearRect = new Rect(50, 50, 150, 150); when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds); + when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0)); when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect)); doAnswer(invocation -> { Rect arg0 = invocation.getArgument(0); @@ -127,6 +128,7 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { final Rect pipBounds = new Rect(0, 0, 100, 100); final Rect keepClearRect = new Rect(100, 100, 150, 150); when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds); + when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0)); when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect)); doAnswer(invocation -> { Rect arg0 = invocation.getArgument(0); @@ -145,6 +147,7 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { final Rect pipBounds = new Rect(0, 0, 100, 100); final Rect keepClearRect = new Rect(50, 50, 150, 150); when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds); + when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0)); when(mMockPipBoundsState.isStashed()).thenReturn(true); when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect)); doAnswer(invocation -> { @@ -164,6 +167,7 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { final Rect pipBounds = new Rect(0, 0, 100, 100); final Rect keepClearRect = new Rect(100, 100, 150, 150); when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds); + when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0)); when(mMockPipBoundsState.isStashed()).thenReturn(true); when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect)); doAnswer(invocation -> { @@ -185,6 +189,7 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { final Rect expected = new Rect( 0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom); when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds); + when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0)); doAnswer(invocation -> { Rect arg0 = invocation.getArgument(0); arg0.set(DISPLAY_BOUNDS); @@ -205,6 +210,7 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { final Rect expected = new Rect( 0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom); when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds); + when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0)); doAnswer(invocation -> { Rect arg0 = invocation.getArgument(0); arg0.set(DISPLAY_BOUNDS); @@ -227,6 +233,7 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { DISPLAY_BOUNDS.right - 100, DISPLAY_BOUNDS.bottom - 100, DISPLAY_BOUNDS.right, DISPLAY_BOUNDS.bottom); when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds); + when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0)); doAnswer(invocation -> { Rect arg0 = invocation.getArgument(0); arg0.set(DISPLAY_BOUNDS); @@ -249,6 +256,7 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { DISPLAY_BOUNDS.right - 100, DISPLAY_BOUNDS.bottom - 100, DISPLAY_BOUNDS.right, DISPLAY_BOUNDS.bottom); when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds); + when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0)); doAnswer(invocation -> { Rect arg0 = invocation.getArgument(0); arg0.set(DISPLAY_BOUNDS); @@ -269,6 +277,7 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { final Rect expected = new Rect( 0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom); when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds); + when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0)); when(mMockPipBoundsState.isStashed()).thenReturn(true); doAnswer(invocation -> { Rect arg0 = invocation.getArgument(0); @@ -289,6 +298,7 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { final Rect expected = new Rect( 0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom); when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds); + when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0)); when(mMockPipBoundsState.isStashed()).thenReturn(true); doAnswer(invocation -> { Rect arg0 = invocation.getArgument(0); @@ -301,4 +311,40 @@ public class PhonePipKeepClearAlgorithmTest extends ShellTestCase { assertEquals(expected, outBounds); } + + @Test + public void adjust_restoreBoundsPresent_appliesRestoreBounds() { + final Rect pipBounds = new Rect(0, 0, 100, 100); + final Rect restoreBounds = new Rect(50, 50, 150, 150); + when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds); + when(mMockPipBoundsState.getRestoreBounds()).thenReturn(restoreBounds); + when(mMockPipBoundsState.hasUserMovedPip()).thenReturn(true); + doAnswer(invocation -> { + Rect arg0 = invocation.getArgument(0); + arg0.set(DISPLAY_BOUNDS); + return null; + }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class)); + + final Rect outBounds = mPipKeepClearAlgorithm.adjust( + mMockPipBoundsState, mMockPipBoundsAlgorithm); + assertEquals(restoreBounds, outBounds); + } + + @Test + public void adjust_restoreBoundsCleared_boundsUnchanged() { + final Rect pipBounds = new Rect(0, 0, 100, 100); + final Rect restoreBounds = new Rect(0, 0, 0, 0); + when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds); + when(mMockPipBoundsState.getRestoreBounds()).thenReturn(restoreBounds); + when(mMockPipBoundsState.hasUserMovedPip()).thenReturn(true); + doAnswer(invocation -> { + Rect arg0 = invocation.getArgument(0); + arg0.set(DISPLAY_BOUNDS); + return null; + }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class)); + + final Rect outBounds = mPipKeepClearAlgorithm.adjust( + mMockPipBoundsState, mMockPipBoundsAlgorithm); + assertEquals(pipBounds, outBounds); + } } diff --git a/media/tests/LoudnessCodecApiTest/Android.bp b/media/tests/LoudnessCodecApiTest/Android.bp index 5ca0fc9661c2..5d1153d93b4f 100644 --- a/media/tests/LoudnessCodecApiTest/Android.bp +++ b/media/tests/LoudnessCodecApiTest/Android.bp @@ -25,3 +25,10 @@ android_test { resource_dirs: ["res"], test_suites: ["device-tests"], } + +test_module_config { + name: "LoudnessCodecApiTest_Presubmit", + base: "LoudnessCodecApiTest", + test_suites: ["device-tests"], + include_annotations: ["android.platform.test.annotations.Presubmit"], +} diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index 346c87daec87..25c063d6ccd8 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -367,6 +367,7 @@ LIBANDROID_PLATFORM { APerformanceHint_sendHint; APerformanceHint_getThreadIds; APerformanceHint_createSessionInternal; + APerformanceHint_setUseFMQForTesting; extern "C++" { ASurfaceControl_registerSurfaceStatsListener*; ASurfaceControl_unregisterSurfaceStatsListener*; diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp index e91c7a9ecda8..095d7d1145ae 100644 --- a/native/android/performance_hint.cpp +++ b/native/android/performance_hint.cpp @@ -16,10 +16,14 @@ #define LOG_TAG "perf_hint" +#include <aidl/android/hardware/power/ChannelConfig.h> +#include <aidl/android/hardware/power/ChannelMessage.h> +#include <aidl/android/hardware/power/SessionConfig.h> #include <aidl/android/hardware/power/SessionHint.h> #include <aidl/android/hardware/power/SessionMode.h> #include <aidl/android/hardware/power/SessionTag.h> #include <aidl/android/hardware/power/WorkDuration.h> +#include <aidl/android/hardware/power/WorkDurationFixedV1.h> #include <aidl/android/os/IHintManager.h> #include <aidl/android/os/IHintSession.h> #include <android-base/stringprintf.h> @@ -28,6 +32,8 @@ #include <android/binder_status.h> #include <android/performance_hint.h> #include <android/trace.h> +#include <android_os.h> +#include <fmq/AidlMessageQueue.h> #include <inttypes.h> #include <performance_hint_private.h> #include <utils/SystemClock.h> @@ -45,6 +51,10 @@ using namespace std::chrono_literals; // Namespace for AIDL types coming from the PowerHAL namespace hal = aidl::android::hardware::power; +using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite; +using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents; +using HalMessageQueue = ::android::AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>; +using HalFlagQueue = ::android::AidlMessageQueue<int8_t, SynchronizedReadWrite>; using android::base::StringPrintf; struct APerformanceHintSession; @@ -54,18 +64,60 @@ struct AWorkDuration : public hal::WorkDuration {}; // Shared lock for the whole PerformanceHintManager and sessions static std::mutex sHintMutex = std::mutex{}; +class FMQWrapper { +public: + bool isActive(); + bool isSupported(); + bool startChannel(IHintManager* manager); + void stopChannel(IHintManager* manager); + // Number of elements the FMQ can hold + bool reportActualWorkDurations(std::optional<hal::SessionConfig>& config, + hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex); + bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config, + int64_t targetDurationNanos) REQUIRES(sHintMutex); + bool sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) REQUIRES(sHintMutex); + bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled) + REQUIRES(sHintMutex); + void setToken(ndk::SpAIBinder& token); + void attemptWake(); + void setUnsupported(); + +private: + template <HalChannelMessageContents::Tag T, bool urgent = false, + class C = HalChannelMessageContents::_at<T>> + bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1) + REQUIRES(sHintMutex); + template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>> + void writeBuffer(C* message, hal::SessionConfig& config, size_t count) REQUIRES(sHintMutex); + + bool isActiveLocked() REQUIRES(sHintMutex); + bool updatePersistentTransaction() REQUIRES(sHintMutex); + std::shared_ptr<HalMessageQueue> mQueue GUARDED_BY(sHintMutex) = nullptr; + std::shared_ptr<HalFlagQueue> mFlagQueue GUARDED_BY(sHintMutex) = nullptr; + // android::hardware::EventFlag* mEventFlag GUARDED_BY(sHintMutex) = nullptr; + android::hardware::EventFlag* mEventFlag = nullptr; + int32_t mWriteMask; + ndk::SpAIBinder mToken = nullptr; + // Used to track if operating on the fmq consistently fails + bool mCorrupted = false; + // Used to keep a persistent transaction open with FMQ to reduce latency a bit + size_t mAvailableSlots GUARDED_BY(sHintMutex) = 0; + bool mHalSupported = true; + HalMessageQueue::MemTransaction mFmqTransaction GUARDED_BY(sHintMutex); +}; struct APerformanceHintManager { public: static APerformanceHintManager* getInstance(); - APerformanceHintManager(std::shared_ptr<IHintManager> service, int64_t preferredRateNanos); + APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos); APerformanceHintManager() = delete; - ~APerformanceHintManager() = default; + ~APerformanceHintManager(); APerformanceHintSession* createSession(const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos, hal::SessionTag tag = hal::SessionTag::APP); int64_t getPreferredRateNanos() const; + FMQWrapper& getFMQWrapper(); private: // Necessary to create an empty binder object @@ -83,6 +135,7 @@ private: std::shared_ptr<IHintManager> mHintManager; ndk::SpAIBinder mToken; const int64_t mPreferredRateNanos; + FMQWrapper mFMQWrapper; }; struct APerformanceHintSession { @@ -121,40 +174,57 @@ private: std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex); // Cached samples std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex); - std::string mSessionName GUARDED_BY(sHintMutex); + std::string mSessionName; static int64_t sIDCounter GUARDED_BY(sHintMutex); // The most recent set of thread IDs std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex); std::optional<hal::SessionConfig> mSessionConfig GUARDED_BY(sHintMutex); // Tracing helpers void traceThreads(std::vector<int32_t>& tids) REQUIRES(sHintMutex); - void tracePowerEfficient(bool powerEfficient) REQUIRES(sHintMutex); - void traceActualDuration(int64_t actualDuration) REQUIRES(sHintMutex); - void traceBatchSize(size_t batchSize) REQUIRES(sHintMutex); - void traceTargetDuration(int64_t targetDuration) REQUIRES(sHintMutex); + void tracePowerEfficient(bool powerEfficient); + void traceActualDuration(int64_t actualDuration); + void traceBatchSize(size_t batchSize); + void traceTargetDuration(int64_t targetDuration); }; static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr; -static APerformanceHintManager* gHintManagerForTesting = nullptr; +static std::shared_ptr<APerformanceHintManager> gHintManagerForTesting = nullptr; + +static std::optional<bool> gForceFMQEnabled = std::nullopt; + // Start above the int32 range so we don't collide with config sessions int64_t APerformanceHintSession::sIDCounter = INT32_MAX; +static FMQWrapper& getFMQ() { + return APerformanceHintManager::getInstance()->getFMQWrapper(); +} + // ===================================== APerformanceHintManager implementation -APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager> manager, +APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager, int64_t preferredRateNanos) : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) { static AIBinder_Class* tokenBinderClass = AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy, tokenStubOnTransact); mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr)); + if (mFMQWrapper.isSupported()) { + mFMQWrapper.setToken(mToken); + mFMQWrapper.startChannel(mHintManager.get()); + } +} + +APerformanceHintManager::~APerformanceHintManager() { + mFMQWrapper.stopChannel(mHintManager.get()); } APerformanceHintManager* APerformanceHintManager::getInstance() { - if (gHintManagerForTesting) return gHintManagerForTesting; + if (gHintManagerForTesting) { + return gHintManagerForTesting.get(); + } if (gIHintManagerForTesting) { - APerformanceHintManager* manager = create(*gIHintManagerForTesting); - gIHintManagerForTesting = nullptr; - return manager; + gHintManagerForTesting = + std::shared_ptr<APerformanceHintManager>(create(*gIHintManagerForTesting)); + return gHintManagerForTesting.get(); } static APerformanceHintManager* instance = create(nullptr); return instance; @@ -178,7 +248,7 @@ APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintMa if (preferredRateNanos <= 0) { preferredRateNanos = -1L; } - return new APerformanceHintManager(std::move(manager), preferredRateNanos); + return new APerformanceHintManager(manager, preferredRateNanos); } APerformanceHintSession* APerformanceHintManager::createSession( @@ -187,15 +257,20 @@ APerformanceHintSession* APerformanceHintManager::createSession( std::vector<int32_t> tids(threadIds, threadIds + size); std::shared_ptr<IHintSession> session; ndk::ScopedAStatus ret; - std::optional<hal::SessionConfig> sessionConfig; + hal::SessionConfig sessionConfig{.id = -1}; ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos, tag, &sessionConfig, &session); if (!ret.isOk() || !session) { + ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage()); return nullptr; } auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos, - initialTargetWorkDurationNanos, sessionConfig); + initialTargetWorkDurationNanos, + sessionConfig.id == -1 + ? std::nullopt + : std::make_optional<hal::SessionConfig>( + std::move(sessionConfig))); std::scoped_lock lock(sHintMutex); out->traceThreads(tids); out->traceTargetDuration(initialTargetWorkDurationNanos); @@ -207,8 +282,15 @@ int64_t APerformanceHintManager::getPreferredRateNanos() const { return mPreferredRateNanos; } +FMQWrapper& APerformanceHintManager::getFMQWrapper() { + return mFMQWrapper; +} + // ===================================== APerformanceHintSession implementation +constexpr int kNumEnums = + ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin(); + APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager, std::shared_ptr<IHintSession> session, int64_t preferredRateNanos, @@ -220,14 +302,11 @@ APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> h mTargetDurationNanos(targetDurationNanos), mFirstTargetMetTimestamp(0), mLastTargetMetTimestamp(0), + mLastHintSentTimestamp(std::vector<int64_t>(kNumEnums, 0)), mSessionConfig(sessionConfig) { if (sessionConfig->id > INT32_MAX) { ALOGE("Session ID too large, must fit 32-bit integer"); } - std::scoped_lock lock(sHintMutex); - constexpr int numEnums = - ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin(); - mLastHintSentTimestamp = std::vector<int64_t>(numEnums, 0); int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter; mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId); } @@ -244,19 +323,18 @@ int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNano ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__); return EINVAL; } - { - std::scoped_lock lock(sHintMutex); - if (mTargetDurationNanos == targetDurationNanos) { - return 0; - } + std::scoped_lock lock(sHintMutex); + if (mTargetDurationNanos == targetDurationNanos) { + return 0; } - ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos); - if (!ret.isOk()) { - ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__, - ret.getMessage()); - return EPIPE; + if (!getFMQ().updateTargetWorkDuration(mSessionConfig, targetDurationNanos)) { + ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos); + if (!ret.isOk()) { + ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__, + ret.getMessage()); + return EPIPE; + } } - std::scoped_lock lock(sHintMutex); mTargetDurationNanos = targetDurationNanos; /** * Most of the workload is target_duration dependent, so now clear the cached samples @@ -292,11 +370,13 @@ int APerformanceHintSession::sendHint(SessionHint hint) { return 0; } - ndk::ScopedAStatus ret = mHintSession->sendHint(hint); + if (!getFMQ().sendHint(mSessionConfig, hint)) { + ndk::ScopedAStatus ret = mHintSession->sendHint(hint); - if (!ret.isOk()) { - ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage()); - return EPIPE; + if (!ret.isOk()) { + ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage()); + return EPIPE; + } } mLastHintSentTimestamp[hint] = now; return 0; @@ -369,10 +449,10 @@ int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuratio int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) { int64_t actualTotalDurationNanos = workDuration->durationNanos; + traceActualDuration(workDuration->durationNanos); int64_t now = uptimeNanos(); workDuration->timeStampNanos = now; std::scoped_lock lock(sHintMutex); - traceActualDuration(workDuration->durationNanos); mActualWorkDurations.push_back(std::move(*workDuration)); if (actualTotalDurationNanos >= mTargetDurationNanos) { @@ -396,20 +476,177 @@ int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* wor mLastTargetMetTimestamp = now; } - ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations); - if (!ret.isOk()) { - ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__, - ret.getMessage()); - mFirstTargetMetTimestamp = 0; - mLastTargetMetTimestamp = 0; - traceBatchSize(mActualWorkDurations.size()); - return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE; + if (!getFMQ().reportActualWorkDurations(mSessionConfig, mActualWorkDurations.data(), + mActualWorkDurations.size())) { + ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations); + if (!ret.isOk()) { + ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__, + ret.getMessage()); + mFirstTargetMetTimestamp = 0; + mLastTargetMetTimestamp = 0; + traceBatchSize(mActualWorkDurations.size()); + return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE; + } } + mActualWorkDurations.clear(); traceBatchSize(0); return 0; } + +// ===================================== FMQ wrapper implementation + +bool FMQWrapper::isActive() { + std::scoped_lock lock{sHintMutex}; + return isActiveLocked(); +} + +bool FMQWrapper::isActiveLocked() { + return mQueue != nullptr; +} + +void FMQWrapper::setUnsupported() { + mHalSupported = false; +} + +bool FMQWrapper::isSupported() { + if (!mHalSupported) { + return false; + } + // Used for testing + if (gForceFMQEnabled.has_value()) { + return *gForceFMQEnabled; + } + return android::os::adpf_use_fmq_channel_fixed(); +} + +bool FMQWrapper::startChannel(IHintManager* manager) { + if (isSupported() && !isActive()) { + std::optional<hal::ChannelConfig> config; + auto ret = manager->getSessionChannel(mToken, &config); + if (ret.isOk() && config.has_value()) { + std::scoped_lock lock{sHintMutex}; + mQueue = std::make_shared<HalMessageQueue>(config->channelDescriptor, true); + if (config->eventFlagDescriptor.has_value()) { + mFlagQueue = std::make_shared<HalFlagQueue>(*config->eventFlagDescriptor, true); + android::hardware::EventFlag::createEventFlag(mFlagQueue->getEventFlagWord(), + &mEventFlag); + mWriteMask = config->writeFlagBitmask; + } + updatePersistentTransaction(); + } else if (ret.isOk() && !config.has_value()) { + ALOGV("FMQ channel enabled but unsupported."); + setUnsupported(); + } else { + ALOGE("%s: FMQ channel initialization failed: %s", __FUNCTION__, ret.getMessage()); + } + } + return isActive(); +} + +void FMQWrapper::stopChannel(IHintManager* manager) { + { + std::scoped_lock lock{sHintMutex}; + if (!isActiveLocked()) { + return; + } + mFlagQueue = nullptr; + mQueue = nullptr; + } + manager->closeSessionChannel(); +} + +template <HalChannelMessageContents::Tag T, class C> +void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t) { + new (mFmqTransaction.getSlot(0)) hal::ChannelMessage{ + .sessionID = static_cast<int32_t>(config.id), + .timeStampNanos = ::android::uptimeNanos(), + .data = HalChannelMessageContents::make<T, C>(std::move(*message)), + }; +} + +template <> +void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages, + hal::SessionConfig& config, + size_t count) { + for (size_t i = 0; i < count; ++i) { + hal::WorkDuration& message = messages[i]; + new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{ + .sessionID = static_cast<int32_t>(config.id), + .timeStampNanos = + (i == count - 1) ? ::android::uptimeNanos() : message.timeStampNanos, + .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration, + hal::WorkDurationFixedV1>({ + .durationNanos = message.cpuDurationNanos, + .workPeriodStartTimestampNanos = message.workPeriodStartTimestampNanos, + .cpuDurationNanos = message.cpuDurationNanos, + .gpuDurationNanos = message.gpuDurationNanos, + }), + }; + } +} + +template <HalChannelMessageContents::Tag T, bool urgent, class C> +bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count) { + if (!isActiveLocked() || !config.has_value() || mCorrupted) { + return false; + } + // If we didn't reserve enough space, try re-creating the transaction + if (count > mAvailableSlots) { + if (!updatePersistentTransaction()) { + return false; + } + // If we actually don't have enough space, give up + if (count > mAvailableSlots) { + return false; + } + } + writeBuffer<T, C>(message, *config, count); + mQueue->commitWrite(count); + mEventFlag->wake(mWriteMask); + // Re-create the persistent transaction after writing + updatePersistentTransaction(); + return true; +} + +void FMQWrapper::setToken(ndk::SpAIBinder& token) { + mToken = token; +} + +bool FMQWrapper::updatePersistentTransaction() { + mAvailableSlots = mQueue->availableToWrite(); + if (mAvailableSlots > 0 && !mQueue->beginWrite(mAvailableSlots, &mFmqTransaction)) { + ALOGE("ADPF FMQ became corrupted, falling back to binder calls!"); + mCorrupted = true; + return false; + } + return true; +} + +bool FMQWrapper::reportActualWorkDurations(std::optional<hal::SessionConfig>& config, + hal::WorkDuration* durations, size_t count) { + return sendMessages<HalChannelMessageContents::workDuration>(config, durations, count); +} + +bool FMQWrapper::updateTargetWorkDuration(std::optional<hal::SessionConfig>& config, + int64_t targetDurationNanos) { + return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos); +} + +bool FMQWrapper::sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) { + return sendMessages<HalChannelMessageContents::hint>(config, + reinterpret_cast<hal::SessionHint*>( + &hint)); +} + +bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode, + bool enabled) { + hal::ChannelMessage::ChannelMessageContents::SessionModeSetter modeObj{.modeInt = mode, + .enabled = enabled}; + return sendMessages<HalChannelMessageContents::mode, true>(config, &modeObj); +} + // ===================================== Tracing helpers void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) { @@ -585,7 +822,12 @@ void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration, } void APerformanceHint_setIHintManagerForTesting(void* iManager) { - delete gHintManagerForTesting; - gHintManagerForTesting = nullptr; + if (iManager == nullptr) { + gHintManagerForTesting = nullptr; + } gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager); } + +void APerformanceHint_setUseFMQForTesting(bool enabled) { + gForceFMQEnabled = enabled; +} diff --git a/native/android/tests/performance_hint/Android.bp b/native/android/tests/performance_hint/Android.bp index 608d5d8a923a..f6f1da1eed79 100644 --- a/native/android/tests/performance_hint/Android.bp +++ b/native/android/tests/performance_hint/Android.bp @@ -36,10 +36,13 @@ cc_test { srcs: ["PerformanceHintNativeTest.cpp"], shared_libs: [ + "android.hardware.common.fmq-V1-ndk", "libandroid", - "liblog", "libbinder", "libbinder_ndk", + "libcutils", + "libfmq", + "liblog", "libpowermanager", "libutils", ], @@ -56,8 +59,8 @@ cc_test { ], cflags: [ - "-Werror", "-Wall", + "-Werror", ], header_libs: [ diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp index d19fa98f1171..9de3a6f525e6 100644 --- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp @@ -24,6 +24,7 @@ #include <android/binder_manager.h> #include <android/binder_status.h> #include <android/performance_hint.h> +#include <fmq/AidlMessageQueue.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <performance_hint_private.h> @@ -31,11 +32,16 @@ #include <memory> #include <vector> +using namespace std::chrono_literals; namespace hal = aidl::android::hardware::power; using aidl::android::os::IHintManager; using aidl::android::os::IHintSession; using ndk::ScopedAStatus; using ndk::SpAIBinder; +using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents; + +using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite; +using HalFlagQueue = ::android::AidlMessageQueue<int8_t, SynchronizedReadWrite>; using namespace android; using namespace testing; @@ -44,7 +50,7 @@ class MockIHintManager : public IHintManager { public: MOCK_METHOD(ScopedAStatus, createHintSessionWithConfig, (const SpAIBinder& token, const ::std::vector<int32_t>& tids, int64_t durationNanos, - hal::SessionTag tag, std::optional<hal::SessionConfig>* config, + hal::SessionTag tag, hal::SessionConfig* config, std::shared_ptr<IHintSession>* _aidl_return), (override)); MOCK_METHOD(ScopedAStatus, getHintSessionPreferredRate, (int64_t * _aidl_return), (override)); @@ -56,7 +62,9 @@ public: (const std::shared_ptr<IHintSession>& hintSession, ::std::vector<int32_t>* tids), (override)); MOCK_METHOD(ScopedAStatus, getSessionChannel, - (const ::ndk::SpAIBinder& in_token, hal::ChannelConfig* _aidl_return), (override)); + (const ::ndk::SpAIBinder& in_token, + std::optional<hal::ChannelConfig>* _aidl_return), + (override)); MOCK_METHOD(ScopedAStatus, closeSessionChannel, (), (override)); MOCK_METHOD(SpAIBinder, asBinder, (), (override)); MOCK_METHOD(bool, isRemote, (), (override)); @@ -92,10 +100,12 @@ public: } APerformanceHintManager* createManager() { + APerformanceHint_setUseFMQForTesting(mUsingFMQ); ON_CALL(*mMockIHintManager, getHintSessionPreferredRate(_)) .WillByDefault(DoAll(SetArgPointee<0>(123L), [] { return ScopedAStatus::ok(); })); return APerformanceHint_getManager(); } + APerformanceHintSession* createSession(APerformanceHintManager* manager, int64_t targetDuration = 56789L, bool isHwui = false) { mMockSession = ndk::SharedRefBase::make<NiceMock<MockIHintSession>>(); @@ -106,8 +116,7 @@ public: ON_CALL(*mMockIHintManager, createHintSessionWithConfig(_, Eq(tids), Eq(targetDuration), _, _, _)) - .WillByDefault(DoAll(SetArgPointee<4>(std::make_optional<hal::SessionConfig>( - {.id = sessionId})), + .WillByDefault(DoAll(SetArgPointee<4>(hal::SessionConfig({.id = sessionId})), SetArgPointee<5>(std::shared_ptr<IHintSession>(mMockSession)), [] { return ScopedAStatus::ok(); })); @@ -133,8 +142,47 @@ public: return APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration); } + void setFMQEnabled(bool enabled) { + mUsingFMQ = enabled; + if (enabled) { + mMockFMQ = std::make_shared< + AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>>(kMockQueueSize, + true); + mMockFlagQueue = + std::make_shared<AidlMessageQueue<int8_t, SynchronizedReadWrite>>(1, true); + hardware::EventFlag::createEventFlag(mMockFlagQueue->getEventFlagWord(), &mEventFlag); + + ON_CALL(*mMockIHintManager, getSessionChannel(_, _)) + .WillByDefault([&](ndk::SpAIBinder, std::optional<hal::ChannelConfig>* config) { + config->emplace( + hal::ChannelConfig{.channelDescriptor = mMockFMQ->dupeDesc(), + .eventFlagDescriptor = + mMockFlagQueue->dupeDesc(), + .readFlagBitmask = + static_cast<int32_t>(mReadBits), + .writeFlagBitmask = + static_cast<int32_t>(mWriteBits)}); + return ::ndk::ScopedAStatus::ok(); + }); + } + } + uint32_t mReadBits = 0x00000001; + uint32_t mWriteBits = 0x00000002; std::shared_ptr<NiceMock<MockIHintManager>> mMockIHintManager = nullptr; std::shared_ptr<NiceMock<MockIHintSession>> mMockSession = nullptr; + std::shared_ptr<AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>> mMockFMQ; + std::shared_ptr<AidlMessageQueue<int8_t, SynchronizedReadWrite>> mMockFlagQueue; + hardware::EventFlag* mEventFlag; + int kMockQueueSize = 20; + bool mUsingFMQ = false; + + template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>> + void expectToReadFromFmq(C expected) { + hal::ChannelMessage readData; + mMockFMQ->readBlocking(&readData, 1, mReadBits, mWriteBits, 1000000000, mEventFlag); + C got = static_cast<C>(readData.data.get<T>()); + ASSERT_EQ(got, expected); + } }; bool equalsWithoutTimestamp(hal::WorkDuration lhs, hal::WorkDuration rhs) { @@ -306,7 +354,7 @@ TEST_F(PerformanceHintTest, TestAPerformanceHint_reportActualWorkDuration2) { actualWorkDurations.push_back(pair.duration); EXPECT_CALL(*mMockSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations))) - .Times(Exactly(1)); + .Times(Exactly(pair.expectedResult == OK)); result = APerformanceHint_reportActualWorkDuration2(session, reinterpret_cast<AWorkDuration*>( &pair.duration)); @@ -327,3 +375,48 @@ TEST_F(PerformanceHintTest, TestAWorkDuration) { AWorkDuration_setActualGpuDurationNanos(aWorkDuration, 8); AWorkDuration_release(aWorkDuration); } + +TEST_F(PerformanceHintTest, TestCreateUsingFMQ) { + setFMQEnabled(true); + APerformanceHintManager* manager = createManager(); + APerformanceHintSession* session = createSession(manager); + ASSERT_TRUE(session); +} + +TEST_F(PerformanceHintTest, TestUpdateTargetWorkDurationUsingFMQ) { + setFMQEnabled(true); + APerformanceHintManager* manager = createManager(); + APerformanceHintSession* session = createSession(manager); + APerformanceHint_updateTargetWorkDuration(session, 456); + expectToReadFromFmq<HalChannelMessageContents::Tag::targetDuration>(456); +} + +TEST_F(PerformanceHintTest, TestSendHintUsingFMQ) { + setFMQEnabled(true); + APerformanceHintManager* manager = createManager(); + APerformanceHintSession* session = createSession(manager); + APerformanceHint_sendHint(session, SessionHint::CPU_LOAD_UP); + expectToReadFromFmq<HalChannelMessageContents::Tag::hint>(hal::SessionHint::CPU_LOAD_UP); +} + +TEST_F(PerformanceHintTest, TestReportActualUsingFMQ) { + setFMQEnabled(true); + APerformanceHintManager* manager = createManager(); + APerformanceHintSession* session = createSession(manager); + hal::WorkDuration duration{.timeStampNanos = 3, + .durationNanos = 999999, + .workPeriodStartTimestampNanos = 1, + .cpuDurationNanos = 999999, + .gpuDurationNanos = 999999}; + + hal::WorkDurationFixedV1 durationExpected{ + .durationNanos = duration.durationNanos, + .workPeriodStartTimestampNanos = duration.workPeriodStartTimestampNanos, + .cpuDurationNanos = duration.cpuDurationNanos, + .gpuDurationNanos = duration.gpuDurationNanos, + }; + + APerformanceHint_reportActualWorkDuration2(session, + reinterpret_cast<AWorkDuration*>(&duration)); + expectToReadFromFmq<HalChannelMessageContents::Tag::workDuration>(durationExpected); +} diff --git a/packages/SettingsLib/src/com/android/settingslib/media/OWNERS b/packages/SettingsLib/src/com/android/settingslib/media/OWNERS index 7467ee1c1a7c..d58add4bb5eb 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/OWNERS +++ b/packages/SettingsLib/src/com/android/settingslib/media/OWNERS @@ -2,7 +2,6 @@ ethibodeau@google.com michaelmikhil@google.com apotapov@google.com -shaoweishen@google.com #Android Media - For minor changes and renames only. aquilescanta@google.com #{LAST_RESORT_SUGGESTION} diff --git a/packages/Shell/tests/Android.bp b/packages/Shell/tests/Android.bp index 6399ffdfdf2f..082a58942059 100644 --- a/packages/Shell/tests/Android.bp +++ b/packages/Shell/tests/Android.bp @@ -26,3 +26,10 @@ android_test { instrumentation_for: "Shell", certificate: "platform", } + +test_module_config { + name: "ShellTests_android_server_os", + base: "ShellTests", + test_suites: ["device-tests"], + exclude_annotations: ["androidx.test.filters.LargeTest"], +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt index 480e4e47ecf0..1287993081fa 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt @@ -17,6 +17,7 @@ package com.android.systemui.bouncer.ui.composable import android.view.HapticFeedbackConstants +import android.view.MotionEvent import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.AnimationSpec @@ -49,6 +50,7 @@ import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.input.pointer.pointerInteropFilter import androidx.compose.ui.platform.LocalView import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -110,6 +112,7 @@ fun PinPad( onClicked = viewModel::onPinButtonClicked, scaling = buttonScaleAnimatables[index]::value, isAnimationEnabled = isDigitButtonAnimationEnabled, + onPointerDown = viewModel::onDigitButtonDown, ) } @@ -133,6 +136,7 @@ fun PinPad( onClicked = viewModel::onPinButtonClicked, scaling = buttonScaleAnimatables[10]::value, isAnimationEnabled = isDigitButtonAnimationEnabled, + onPointerDown = viewModel::onDigitButtonDown ) ActionButton( @@ -155,6 +159,7 @@ private fun DigitButton( digit: Int, isInputEnabled: Boolean, onClicked: (Int) -> Unit, + onPointerDown: () -> Unit, scaling: () -> Float, isAnimationEnabled: Boolean, ) { @@ -164,6 +169,7 @@ private fun DigitButton( backgroundColor = MaterialTheme.colorScheme.surfaceVariant, foregroundColor = MaterialTheme.colorScheme.onSurfaceVariant, isAnimationEnabled = isAnimationEnabled, + onPointerDown = onPointerDown, modifier = Modifier.graphicsLayer { val scale = if (isAnimationEnabled) scaling() else 1f @@ -235,6 +241,7 @@ private fun PinPadButton( isAnimationEnabled: Boolean, modifier: Modifier = Modifier, onLongPressed: (() -> Unit)? = null, + onPointerDown: (() -> Unit)? = null, content: @Composable (contentColor: () -> Color) -> Unit, ) { val interactionSource = remember { MutableInteractionSource() } @@ -303,11 +310,17 @@ private fun PinPadButton( .clip(CircleShape) .thenIf(isEnabled) { Modifier.combinedClickable( - interactionSource = interactionSource, - indication = indication, - onClick = onClicked, - onLongClick = onLongPressed - ) + interactionSource = interactionSource, + indication = indication, + onClick = onClicked, + onLongClick = onLongPressed + ) + .pointerInteropFilter { motionEvent -> + if (motionEvent.action == MotionEvent.ACTION_DOWN) { + onPointerDown?.let { it() } + } + false + } }, ) { content(contentColor::value) diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt index 062d351100d6..a1d944b403d3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt @@ -34,9 +34,11 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollector import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.haptics.msdl.bouncerHapticPlayer import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository import com.android.systemui.res.R import com.android.systemui.statusbar.policy.DevicePostureController +import com.android.systemui.testKosmos import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.mockito.mock @@ -86,6 +88,7 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() { @Mock private lateinit var postureController: DevicePostureController @Mock private lateinit var mUserActivityNotifier: UserActivityNotifier @Captor private lateinit var keyListenerArgumentCaptor: ArgumentCaptor<View.OnKeyListener> + private val kosmos = testKosmos() private lateinit var keyguardPasswordViewController: KeyguardPasswordViewController @@ -132,8 +135,8 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() { fakeFeatureFlags, mSelectedUserInteractor, keyguardKeyboardInteractor, - null, - mUserActivityNotifier + kosmos.bouncerHapticPlayer, + mUserActivityNotifier, ) } @@ -194,7 +197,7 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() { keyListenerArgumentCaptor.value.onKey( keyguardPasswordView, KeyEvent.KEYCODE_SPACE, - KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE) + KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE), ) assertFalse("Unlock attempted.", eventHandled) @@ -213,7 +216,7 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() { keyListenerArgumentCaptor.value.onKey( keyguardPasswordView, KeyEvent.KEYCODE_ENTER, - KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER) + KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER), ) assertTrue("Unlock not attempted.", eventHandled) diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt index bb152086cdab..d63e728cf443 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt @@ -30,7 +30,7 @@ import com.android.systemui.classifier.FalsingCollector import com.android.systemui.classifier.FalsingCollectorFake import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags -import com.android.systemui.haptics.msdl.msdlPlayer +import com.android.systemui.haptics.msdl.bouncerHapticPlayer import com.android.systemui.res.R import com.android.systemui.statusbar.policy.DevicePostureController import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED @@ -92,7 +92,7 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { @Captor lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback> private val kosmos = testKosmos() - private val msdlPlayer = kosmos.msdlPlayer + private val bouncerHapticHelper = kosmos.bouncerHapticPlayer @Before fun setup() { @@ -118,7 +118,7 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { mPostureController, fakeFeatureFlags, mSelectedUserInteractor, - msdlPlayer, + bouncerHapticHelper, ) mKeyguardPatternView.onAttachedToWindow() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java index 1076d9089d79..4d1660e71c0a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java @@ -34,10 +34,12 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor; import com.android.systemui.SysuiTestCase; +import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository; +import com.android.systemui.kosmos.KosmosJavaAdapter; import com.android.systemui.res.R; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; @@ -93,6 +95,9 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { private KeyguardPinBasedInputViewController mKeyguardPinViewController; + private KosmosJavaAdapter mKosmosJavaAdapter = new KosmosJavaAdapter(this); + private BouncerHapticPlayer mBouncerHapticPlayer = mKosmosJavaAdapter.getBouncerHapticHelper(); + @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -119,7 +124,8 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener, mEmergencyButtonController, mFalsingCollector, featureFlags, - mSelectedUserInteractor, keyguardKeyboardInteractor, null, mUserActivityNotifier) { + mSelectedUserInteractor, keyguardKeyboardInteractor, mBouncerHapticPlayer, + mUserActivityNotifier) { @Override public void onResume(int reason) { super.onResume(reason); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt index 8d82e972bdaa..2ee4aee2abab 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt @@ -16,6 +16,8 @@ package com.android.systemui.bouncer.ui.viewmodel +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags import android.view.KeyEvent.KEYCODE_0 import android.view.KeyEvent.KEYCODE_4 import android.view.KeyEvent.KEYCODE_A @@ -31,6 +33,7 @@ import com.android.systemui.authentication.data.repository.fakeAuthenticationRep import com.android.systemui.authentication.domain.interactor.authenticationInteractor import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.bouncer.data.repository.fakeSimBouncerRepository +import com.android.systemui.classifier.fakeFalsingCollector import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn @@ -41,6 +44,7 @@ import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlin.random.Random import kotlin.random.nextInt +import kotlin.test.assertTrue import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.map @@ -60,12 +64,13 @@ class PinBouncerViewModelTest : SysuiTestCase() { private val testScope = kosmos.testScope private val sceneInteractor by lazy { kosmos.sceneInteractor } private val authenticationInteractor by lazy { kosmos.authenticationInteractor } - private val underTest = + private val underTest by lazy { kosmos.pinBouncerViewModelFactory.create( isInputEnabled = MutableStateFlow(true), onIntentionalUserInput = {}, authenticationMethod = AuthenticationMethodModel.Pin, ) + } @Before fun setUp() { @@ -475,6 +480,18 @@ class PinBouncerViewModelTest : SysuiTestCase() { assertThat(pin).containsExactly(*expectedPin) } + @Test + @EnableFlags(com.android.systemui.Flags.FLAG_COMPOSE_BOUNCER) + @DisableFlags(com.android.systemui.Flags.FLAG_SCENE_CONTAINER) + fun onDigitButtonDown_avoidGesture_invoked() = + testScope.runTest { + lockDeviceAndOpenPinBouncer() + + underTest.onDigitButtonDown() + + assertTrue(kosmos.fakeFalsingCollector.wasLastGestureAvoided()) + } + private fun TestScope.switchToScene(toScene: SceneKey) { val currentScene by collectLastValue(sceneInteractor.currentScene) val bouncerHidden = currentScene == Scenes.Bouncer && toScene != Scenes.Bouncer diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt index 3253edfb5fca..d90d58b8d25c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt @@ -19,6 +19,7 @@ package com.android.systemui.deviceentry.domain.interactor import android.testing.TestableLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.compose.animation.scene.ObservableTransitionState import com.android.compose.animation.scene.SceneKey import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository @@ -42,11 +43,16 @@ import com.android.systemui.keyguard.data.repository.fakeTrustRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.domain.startable.sceneContainerStartable import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.statusbar.sysuiStatusBarStateController import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before @@ -66,10 +72,14 @@ class DeviceEntryInteractorTest : SysuiTestCase() { private val trustRepository by lazy { kosmos.fakeTrustRepository } private val sceneInteractor by lazy { kosmos.sceneInteractor } private val authenticationInteractor by lazy { kosmos.authenticationInteractor } + private val sceneBackInteractor by lazy { kosmos.sceneBackInteractor } + private val sceneContainerStartable by lazy { kosmos.sceneContainerStartable } + private val sysuiStatusBarStateController by lazy { kosmos.sysuiStatusBarStateController } private lateinit var underTest: DeviceEntryInteractor @Before fun setUp() { + sceneContainerStartable.start() underTest = kosmos.deviceEntryInteractor } @@ -423,8 +433,37 @@ class DeviceEntryInteractorTest : SysuiTestCase() { assertThat(isUnlocked).isTrue() } - private fun switchToScene(sceneKey: SceneKey) { + @Test + fun isDeviceEntered_unlockedWhileOnShade_emitsTrue() = + testScope.runTest { + val isDeviceEntered by collectLastValue(underTest.isDeviceEntered) + assertThat(isDeviceEntered).isFalse() + val currentScene by collectLastValue(sceneInteractor.currentScene) + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + + // Navigate to shade and bouncer: + switchToScene(Scenes.Shade) + assertThat(currentScene).isEqualTo(Scenes.Shade) + // Simulating a "leave it open when the keyguard is hidden" which means the bouncer will + // be + // shown and successful authentication should take the user back to where they are, the + // shade scene. + sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true) + switchToScene(Scenes.Bouncer) + assertThat(currentScene).isEqualTo(Scenes.Bouncer) + + assertThat(isDeviceEntered).isFalse() + // Authenticate with PIN to unlock and dismiss the lockscreen: + authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN) + runCurrent() + + assertThat(isDeviceEntered).isTrue() + } + + private fun TestScope.switchToScene(sceneKey: SceneKey) { sceneInteractor.changeScene(sceneKey, "reason") + sceneInteractor.setTransitionState(flowOf(ObservableTransitionState.Idle(sceneKey))) + runCurrent() } private suspend fun givenCanShowAlternateBouncer() { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt index 2d42c4247ab7..a0cafcbd5ad1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt @@ -161,9 +161,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { val upDestinationSceneKey = (actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene assertThat(upDestinationSceneKey).isEqualTo(Scenes.Bouncer) - kosmos.emulateUserDrivenTransition( - to = upDestinationSceneKey, - ) + kosmos.emulateUserDrivenTransition(to = upDestinationSceneKey) kosmos.fakeSceneDataSource.pause() kosmos.enterPin() @@ -226,16 +224,14 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { (actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene assertThat(upDestinationSceneKey).isEqualTo(SceneFamilies.Home) assertThat(homeScene).isEqualTo(Scenes.Gone) - kosmos.emulateUserDrivenTransition( - to = homeScene, - ) + kosmos.emulateUserDrivenTransition(to = homeScene) } @Test fun withAuthMethodNone_deviceWakeUp_skipsLockscreen() = testScope.runTest { kosmos.setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = false) - kosmos.putDeviceToSleep(instantlyLockDevice = false) + kosmos.putDeviceToSleep() kosmos.assertCurrentScene(Scenes.Lockscreen) kosmos.wakeUpDevice() @@ -246,7 +242,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { fun withAuthMethodSwipe_deviceWakeUp_doesNotSkipLockscreen() = testScope.runTest { kosmos.setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true) - kosmos.putDeviceToSleep(instantlyLockDevice = false) + kosmos.putDeviceToSleep() kosmos.assertCurrentScene(Scenes.Lockscreen) kosmos.wakeUpDevice() @@ -302,7 +298,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { testScope.runTest { kosmos.unlockDevice() kosmos.assertCurrentScene(Scenes.Gone) - kosmos.putDeviceToSleep(instantlyLockDevice = false) + kosmos.putDeviceToSleep() kosmos.assertCurrentScene(Scenes.Lockscreen) // Pretend like the timeout elapsed and now lock the device. @@ -318,9 +314,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { val upDestinationSceneKey = (actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene assertThat(upDestinationSceneKey).isEqualTo(Scenes.Bouncer) - kosmos.emulateUserDrivenTransition( - to = upDestinationSceneKey, - ) + kosmos.emulateUserDrivenTransition(to = upDestinationSceneKey) kosmos.fakeSceneDataSource.pause() kosmos.dismissIme() @@ -388,7 +382,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { kosmos.emulatePendingTransitionProgress(expectedVisible = true) kosmos.enterSimPin( authMethodAfterSimUnlock = AuthenticationMethodModel.None, - enableLockscreen = false + enableLockscreen = false, ) kosmos.assertCurrentScene(Scenes.Gone) @@ -434,7 +428,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { /** Updates the current authentication method and related states in the data layer. */ private fun Kosmos.setAuthMethod( authMethod: AuthenticationMethodModel, - enableLockscreen: Boolean = true + enableLockscreen: Boolean = true, ) { if (authMethod.isSecure) { assert(enableLockscreen) { @@ -538,24 +532,27 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { kosmos.fakeSceneDataSource.pause() sceneInteractor.changeScene(to, "reason") - emulatePendingTransitionProgress( - expectedVisible = to != Scenes.Gone, - ) + emulatePendingTransitionProgress(expectedVisible = to != Scenes.Gone) } /** - * Locks the device immediately (without delay). + * Locks the device. * * Asserts the device to be lockable (e.g. that the current authentication is secure). * - * Not to be confused with [putDeviceToSleep], which may also instantly lock the device. + * Internally emulates a power button press that puts the device to sleep, followed by another + * power button press that wakes up the device but is then expected to be in the locked state. */ private suspend fun Kosmos.lockDevice() { val authMethod = authenticationInteractor.getAuthenticationMethod() assertWithMessage("The authentication method of $authMethod is not secure, cannot lock!") .that(authMethod.isSecure) .isTrue() - sceneInteractor.changeScene(Scenes.Lockscreen, "") + + powerInteractor.setAsleepForTest() + testScope.runCurrent() + + powerInteractor.setAwakeForTest() testScope.runCurrent() } @@ -569,9 +566,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { fakeSceneDataSource.pause() enterPin() - emulatePendingTransitionProgress( - expectedVisible = false, - ) + emulatePendingTransitionProgress(expectedVisible = false) } /** @@ -645,9 +640,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { } /** Changes device wakefulness state from awake to asleep, going through intermediary states. */ - private suspend fun Kosmos.putDeviceToSleep( - instantlyLockDevice: Boolean = true, - ) { + private suspend fun Kosmos.putDeviceToSleep() { val wakefulnessModel = powerInteractor.detailedWakefulness.value assertWithMessage("Cannot put device to sleep as it's already asleep!") .that(wakefulnessModel.isAwake()) @@ -655,10 +648,6 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { powerInteractor.setAsleepForTest() testScope.runCurrent() - - if (instantlyLockDevice) { - lockDevice() - } } /** Emulates the dismissal of the IME (soft keyboard). */ diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt index 1f3454de14d7..405cfd38d49a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt @@ -28,6 +28,8 @@ import com.android.systemui.authentication.domain.interactor.authenticationInter import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.data.model.asIterable +import com.android.systemui.scene.data.model.sceneStackOf import com.android.systemui.scene.domain.startable.sceneContainerStartable import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos @@ -173,12 +175,32 @@ class SceneBackInteractorTest : SysuiTestCase() { ) } + @Test + @EnableSceneContainer + fun updateBackStack() = + testScope.runTest { + underTest.onSceneChange(from = Scenes.Lockscreen, to = Scenes.Shade) + underTest.onSceneChange(from = Scenes.Shade, to = Scenes.QuickSettings) + underTest.onSceneChange(from = Scenes.QuickSettings, to = Scenes.Bouncer) + assertThat(underTest.backStack.value.asIterable().toList()) + .isEqualTo(listOf(Scenes.QuickSettings, Scenes.Shade, Scenes.Lockscreen)) + + underTest.updateBackStack { stack -> + // Reverse the stack, just to see if it can be done: + sceneStackOf(*stack.asIterable().reversed().toTypedArray()) + } + + assertThat(underTest.backStack.value.asIterable().toList()) + .isEqualTo(listOf(Scenes.Lockscreen, Scenes.Shade, Scenes.QuickSettings)) + } + private suspend fun TestScope.assertRoute(vararg route: RouteNode) { val currentScene by collectLastValue(sceneInteractor.currentScene) val backScene by collectLastValue(underTest.backScene) route.forEachIndexed { index, node -> sceneInteractor.changeScene(node.changeSceneTo, "") + runCurrent() assertWithMessage("node at index $index currentScene mismatch") .that(currentScene) .isEqualTo(node.changeSceneTo) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt index d1804608d130..763a1a943bf8 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt @@ -33,7 +33,9 @@ import com.android.internal.policy.IKeyguardDismissCallback import com.android.keyguard.AuthInteractionProperties import com.android.systemui.Flags import com.android.systemui.SysuiTestCase +import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository +import com.android.systemui.authentication.domain.interactor.authenticationInteractor import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.biometrics.shared.model.FingerprintSensorType @@ -82,7 +84,9 @@ import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.se import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.power.shared.model.WakeSleepReason import com.android.systemui.power.shared.model.WakefulnessState +import com.android.systemui.scene.data.model.asIterable import com.android.systemui.scene.data.repository.Transition +import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.fakeSceneDataSource @@ -131,6 +135,7 @@ class SceneContainerStartableTest : SysuiTestCase() { private val testScope = kosmos.testScope private val deviceEntryHapticsInteractor by lazy { kosmos.deviceEntryHapticsInteractor } private val sceneInteractor by lazy { kosmos.sceneInteractor } + private val sceneBackInteractor by lazy { kosmos.sceneBackInteractor } private val bouncerInteractor by lazy { kosmos.bouncerInteractor } private val faceAuthRepository by lazy { kosmos.fakeDeviceEntryFaceAuthRepository } private val bouncerRepository by lazy { kosmos.fakeKeyguardBouncerRepository } @@ -237,17 +242,14 @@ class SceneContainerStartableTest : SysuiTestCase() { fun hydrateVisibility_basedOnOcclusion() = testScope.runTest { val isVisible by collectLastValue(sceneInteractor.isVisible) - prepareState( - isDeviceUnlocked = true, - initialSceneKey = Scenes.Lockscreen, - ) + prepareState(isDeviceUnlocked = true, initialSceneKey = Scenes.Lockscreen) underTest.start() assertThat(isVisible).isTrue() kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop( true, - mock() + mock(), ) assertThat(isVisible).isFalse() @@ -259,10 +261,7 @@ class SceneContainerStartableTest : SysuiTestCase() { fun hydrateVisibility_basedOnAlternateBouncer() = testScope.runTest { val isVisible by collectLastValue(sceneInteractor.isVisible) - prepareState( - isDeviceUnlocked = false, - initialSceneKey = Scenes.Lockscreen, - ) + prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Lockscreen) underTest.start() assertThat(isVisible).isTrue() @@ -270,7 +269,7 @@ class SceneContainerStartableTest : SysuiTestCase() { // WHEN the device is occluded, kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop( true, - mock() + mock(), ) // THEN scenes are not visible assertThat(isVisible).isFalse() @@ -393,6 +392,7 @@ class SceneContainerStartableTest : SysuiTestCase() { fun switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) + val backStack by collectLastValue(sceneBackInteractor.backStack) kosmos.sysuiStatusBarStateController.leaveOpen = true // leave shade open val transitionState = @@ -414,12 +414,14 @@ class SceneContainerStartableTest : SysuiTestCase() { transitionState.value = ObservableTransitionState.Idle(Scenes.Bouncer) runCurrent() assertThat(currentSceneKey).isEqualTo(Scenes.Bouncer) + assertThat(backStack?.asIterable()?.last()).isEqualTo(Scenes.Lockscreen) kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) ) assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings) + assertThat(backStack?.asIterable()?.last()).isEqualTo(Scenes.Gone) } @Test @@ -478,10 +480,7 @@ class SceneContainerStartableTest : SysuiTestCase() { fun stayOnLockscreenWhenDeviceUnlocksWithBypassOff() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) - prepareState( - isBypassEnabled = false, - initialSceneKey = Scenes.Lockscreen, - ) + prepareState(isBypassEnabled = false, initialSceneKey = Scenes.Lockscreen) assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen) underTest.start() @@ -520,10 +519,7 @@ class SceneContainerStartableTest : SysuiTestCase() { fun switchToGoneWhenDeviceIsUnlockedAndUserIsOnBouncerWithBypassDisabled() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) - prepareState( - isBypassEnabled = false, - initialSceneKey = Scenes.Bouncer, - ) + prepareState(isBypassEnabled = false, initialSceneKey = Scenes.Bouncer) assertThat(currentSceneKey).isEqualTo(Scenes.Bouncer) underTest.start() @@ -539,10 +535,7 @@ class SceneContainerStartableTest : SysuiTestCase() { val alternateBouncerVisible by collectLastValue(bouncerRepository.alternateBouncerVisible) val currentSceneKey by collectLastValue(sceneInteractor.currentScene) - prepareState( - isDeviceUnlocked = false, - initialSceneKey = Scenes.Shade, - ) + prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Shade) assertThat(currentSceneKey).isEqualTo(Scenes.Shade) bouncerRepository.setAlternateVisible(true) underTest.start() @@ -564,10 +557,7 @@ class SceneContainerStartableTest : SysuiTestCase() { fun switchToLockscreenWhenDeviceSleepsLocked() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) - prepareState( - isDeviceUnlocked = false, - initialSceneKey = Scenes.Shade, - ) + prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Shade) assertThat(currentSceneKey).isEqualTo(Scenes.Shade) underTest.start() powerInteractor.setAsleepForTest() @@ -583,10 +573,7 @@ class SceneContainerStartableTest : SysuiTestCase() { val currentTransitionInfo by collectLastValue(kosmos.keyguardTransitionRepository.currentTransitionInfoInternal) val transitionState = - prepareState( - isDeviceUnlocked = false, - initialSceneKey = Scenes.Shade, - ) + prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Shade) kosmos.keyguardRepository.setAodAvailable(true) runCurrent() assertThat(asleepState).isEqualTo(KeyguardState.AOD) @@ -615,10 +602,7 @@ class SceneContainerStartableTest : SysuiTestCase() { val currentTransitionInfo by collectLastValue(kosmos.keyguardTransitionRepository.currentTransitionInfoInternal) val transitionState = - prepareState( - isDeviceUnlocked = false, - initialSceneKey = Scenes.Shade, - ) + prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Shade) kosmos.keyguardRepository.setAodAvailable(false) runCurrent() assertThat(asleepState).isEqualTo(KeyguardState.DOZING) @@ -1078,16 +1062,14 @@ class SceneContainerStartableTest : SysuiTestCase() { @Test fun hydrateSystemUiState_onLockscreen_basedOnOcclusion() = testScope.runTest { - prepareState( - initialSceneKey = Scenes.Lockscreen, - ) + prepareState(initialSceneKey = Scenes.Lockscreen) underTest.start() runCurrent() clearInvocations(sysUiState) kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop( true, - mock() + mock(), ) runCurrent() assertThat( @@ -1210,7 +1192,7 @@ class SceneContainerStartableTest : SysuiTestCase() { initialSceneKey = Scenes.Lockscreen, authenticationMethod = AuthenticationMethodModel.Pin, isDeviceUnlocked = false, - startsAwake = false + startsAwake = false, ) assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen) underTest.start() @@ -1228,11 +1210,14 @@ class SceneContainerStartableTest : SysuiTestCase() { @Test fun collectFalsingSignals_onSuccessfulUnlock() = testScope.runTest { - prepareState( - initialSceneKey = Scenes.Lockscreen, - authenticationMethod = AuthenticationMethodModel.Pin, - isDeviceUnlocked = false, - ) + val currentScene by collectLastValue(sceneInteractor.currentScene) + + val transitionStateFlow = + prepareState( + initialSceneKey = Scenes.Lockscreen, + authenticationMethod = AuthenticationMethodModel.Pin, + isDeviceUnlocked = false, + ) underTest.start() runCurrent() verify(falsingCollector, never()).onSuccessfulUnlock() @@ -1247,36 +1232,46 @@ class SceneContainerStartableTest : SysuiTestCase() { ) .forEach { sceneKey -> sceneInteractor.changeScene(sceneKey, "reason") + transitionStateFlow.value = ObservableTransitionState.Idle(sceneKey) runCurrent() verify(falsingCollector, never()).onSuccessfulUnlock() } // Changing to the Gone scene should report a successful unlock. - kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( - SuccessFingerprintAuthenticationStatus(0, true) - ) + kosmos.authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN) runCurrent() - sceneInteractor.changeScene(Scenes.Gone, "reason") + // Make sure that the startable changed the scene to Gone because the device unlocked. + assertThat(currentScene).isEqualTo(Scenes.Gone) + // Make the transition state match the current state + transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Gone) runCurrent() verify(falsingCollector).onSuccessfulUnlock() // Move around scenes without changing back to Lockscreen, shouldn't report another // unlock. - listOf( - Scenes.Shade, - Scenes.QuickSettings, - Scenes.Shade, - Scenes.Gone, - ) - .forEach { sceneKey -> - sceneInteractor.changeScene(sceneKey, "reason") - runCurrent() - verify(falsingCollector, times(1)).onSuccessfulUnlock() - } - - // Changing to the Lockscreen scene shouldn't report a successful unlock. - sceneInteractor.changeScene(Scenes.Lockscreen, "reason") + listOf(Scenes.Shade, Scenes.QuickSettings, Scenes.Shade, Scenes.Gone).forEach { sceneKey + -> + sceneInteractor.changeScene(sceneKey, "reason") + transitionStateFlow.value = ObservableTransitionState.Idle(sceneKey) + runCurrent() + verify(falsingCollector, times(1)).onSuccessfulUnlock() + } + + // Putting the device to sleep to lock it again, which shouldn't report another + // successful unlock. + kosmos.powerInteractor.setAsleepForTest() + runCurrent() + // Verify that the startable changed the scene to Lockscreen because the device locked + // following the sleep. + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + // Make the transition state match the current state + transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Lockscreen) + // Wake up the device again before continuing with the test. + kosmos.powerInteractor.setAwakeForTest() runCurrent() + // Verify that the current scene is still the Lockscreen scene, now that the device is + // still locked. + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) verify(falsingCollector, times(1)).onSuccessfulUnlock() // Move around scenes without unlocking. @@ -1289,12 +1284,17 @@ class SceneContainerStartableTest : SysuiTestCase() { ) .forEach { sceneKey -> sceneInteractor.changeScene(sceneKey, "reason") + transitionStateFlow.value = ObservableTransitionState.Idle(sceneKey) runCurrent() verify(falsingCollector, times(1)).onSuccessfulUnlock() } - // Changing to the Gone scene should report a second successful unlock. - sceneInteractor.changeScene(Scenes.Gone, "reason") + kosmos.authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN) + runCurrent() + // Make sure that the startable changed the scene to Gone because the device unlocked. + assertThat(currentScene).isEqualTo(Scenes.Gone) + // Make the transition state match the current scene. + transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Gone) runCurrent() verify(falsingCollector, times(2)).onSuccessfulUnlock() } @@ -1608,7 +1608,7 @@ class SceneContainerStartableTest : SysuiTestCase() { kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop( true, - mock() + mock(), ) runCurrent() verify(notificationShadeWindowController, times(1)).setKeyguardOccluded(true) @@ -1623,10 +1623,7 @@ class SceneContainerStartableTest : SysuiTestCase() { @Test fun hydrateInteractionState_whileLocked() = testScope.runTest { - val transitionStateFlow = - prepareState( - initialSceneKey = Scenes.Lockscreen, - ) + val transitionStateFlow = prepareState(initialSceneKey = Scenes.Lockscreen) underTest.start() runCurrent() verify(centralSurfaces).setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true) @@ -1643,10 +1640,7 @@ class SceneContainerStartableTest : SysuiTestCase() { }, verifyAfterTransition = { verify(centralSurfaces) - .setInteracting( - StatusBarManager.WINDOW_STATUS_BAR, - false, - ) + .setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false) }, ) @@ -1661,11 +1655,7 @@ class SceneContainerStartableTest : SysuiTestCase() { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { - verify(centralSurfaces) - .setInteracting( - StatusBarManager.WINDOW_STATUS_BAR, - true, - ) + verify(centralSurfaces).setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true) }, ) @@ -1681,10 +1671,7 @@ class SceneContainerStartableTest : SysuiTestCase() { }, verifyAfterTransition = { verify(centralSurfaces) - .setInteracting( - StatusBarManager.WINDOW_STATUS_BAR, - false, - ) + .setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false) }, ) @@ -1699,11 +1686,7 @@ class SceneContainerStartableTest : SysuiTestCase() { verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean()) }, verifyAfterTransition = { - verify(centralSurfaces) - .setInteracting( - StatusBarManager.WINDOW_STATUS_BAR, - true, - ) + verify(centralSurfaces).setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true) }, ) @@ -1881,9 +1864,7 @@ class SceneContainerStartableTest : SysuiTestCase() { testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene) val transitionStateFlow = - prepareState( - authenticationMethod = AuthenticationMethodModel.None, - ) + prepareState(authenticationMethod = AuthenticationMethodModel.None) underTest.start() assertThat(currentScene).isEqualTo(Scenes.Lockscreen) // Swipe to Gone, more than halfway @@ -1949,9 +1930,7 @@ class SceneContainerStartableTest : SysuiTestCase() { fun switchToGone_whenKeyguardBecomesDisabled_whenOnShadeScene() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene) - prepareState( - initialSceneKey = Scenes.Shade, - ) + prepareState(initialSceneKey = Scenes.Shade) assertThat(currentScene).isEqualTo(Scenes.Shade) underTest.start() @@ -1981,10 +1960,7 @@ class SceneContainerStartableTest : SysuiTestCase() { fun doesNotSwitchToGone_whenKeyguardBecomesDisabled_whenDeviceEntered() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene) - prepareState( - isDeviceUnlocked = true, - initialSceneKey = Scenes.Gone, - ) + prepareState(isDeviceUnlocked = true, initialSceneKey = Scenes.Gone) assertThat(currentScene).isEqualTo(Scenes.Gone) assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isTrue() underTest.start() @@ -2097,10 +2073,7 @@ class SceneContainerStartableTest : SysuiTestCase() { fun refreshLockscreenEnabled() = testScope.runTest { val transitionState = - prepareState( - isDeviceUnlocked = true, - initialSceneKey = Scenes.Gone, - ) + prepareState(isDeviceUnlocked = true, initialSceneKey = Scenes.Gone) underTest.start() val isLockscreenEnabled by collectLastValue(kosmos.deviceEntryInteractor.isLockscreenEnabled) @@ -2174,10 +2147,7 @@ class SceneContainerStartableTest : SysuiTestCase() { runCurrent() verifyDuringTransition?.invoke() - transitionStateFlow.value = - ObservableTransitionState.Idle( - currentScene = toScene, - ) + transitionStateFlow.value = ObservableTransitionState.Idle(currentScene = toScene) runCurrent() verifyAfterTransition?.invoke() } @@ -2262,7 +2232,7 @@ class SceneContainerStartableTest : SysuiTestCase() { private fun TestScope.allowHapticsOnSfps( isPowerButtonDown: Boolean = false, - lastPowerPress: Long = 10000 + lastPowerPress: Long = 10000, ) { kosmos.fakeKeyEventRepository.setPowerButtonDown(isPowerButtonDown) @@ -2287,7 +2257,7 @@ class SceneContainerStartableTest : SysuiTestCase() { private fun TestScope.setupBiometricAuth( hasSfps: Boolean = false, hasUdfps: Boolean = false, - hasFace: Boolean = false + hasFace: Boolean = false, ) { if (hasSfps) { setFingerprintSensorType(FingerprintSensorType.POWER_BUTTON) diff --git a/packages/SystemUI/res/drawable/ic_volume_media_off.xml b/packages/SystemUI/res/drawable/ic_volume_media_off.xml deleted file mode 100644 index 875b7b6d1f40..000000000000 --- a/packages/SystemUI/res/drawable/ic_volume_media_off.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2020 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License - --> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:drawable="@drawable/ic_volume_media_mute" /> -</selector> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index 28f1381d94af..b43d8b667756 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -19,10 +19,8 @@ package com.android.keyguard; import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL; import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED; import static com.android.keyguard.KeyguardAbsKeyInputView.MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT; -import static com.android.systemui.Flags.msdlFeedback; import static com.android.systemui.Flags.notifyPasswordTextViewUserActivityInBackground; -import android.annotation.Nullable; import android.content.res.ColorStateList; import android.os.AsyncTask; import android.os.CountDownTimer; @@ -37,15 +35,13 @@ import com.android.internal.widget.LockscreenCredential; import com.android.keyguard.EmergencyButtonController.EmergencyButtonCallback; import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer; import com.android.systemui.classifier.FalsingClassifier; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.res.R; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; -import com.google.android.msdl.data.model.MSDLToken; -import com.google.android.msdl.domain.MSDLPlayer; - import java.util.HashMap; import java.util.Map; @@ -62,8 +58,6 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey protected AsyncTask<?, ?, ?> mPendingLockCheck; protected boolean mResumed; protected boolean mLockedOut; - @Nullable - protected MSDLPlayer mMSDLPlayer; private final KeyDownListener mKeyDownListener = (keyCode, keyEvent) -> { // Fingerprint sensor sends a KeyEvent.KEYCODE_UNKNOWN. @@ -91,16 +85,16 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey LatencyTracker latencyTracker, FalsingCollector falsingCollector, EmergencyButtonController emergencyButtonController, FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor, - @Nullable MSDLPlayer msdlPlayer, + BouncerHapticPlayer bouncerHapticPlayer, UserActivityNotifier userActivityNotifier) { super(view, securityMode, keyguardSecurityCallback, emergencyButtonController, - messageAreaControllerFactory, featureFlags, selectedUserInteractor); + messageAreaControllerFactory, featureFlags, selectedUserInteractor, + bouncerHapticPlayer); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; mLatencyTracker = latencyTracker; mFalsingCollector = falsingCollector; mEmergencyButtonController = emergencyButtonController; - mMSDLPlayer = msdlPlayer; mUserActivityNotifier = userActivityNotifier; } @@ -191,7 +185,9 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey void onPasswordChecked(int userId, boolean matched, int timeoutMs, boolean isValidPassword) { boolean dismissKeyguard = mSelectedUserInteractor.getSelectedUserId() == userId; if (matched) { - playAuthenticationHaptics(/* unlock= */true); + mBouncerHapticPlayer.playAuthenticationFeedback( + /* authenticationSucceeded = */true + ); getKeyguardSecurityCallback().reportUnlockAttempt(userId, true, 0); if (dismissKeyguard) { mDismissing = true; @@ -199,7 +195,9 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey getKeyguardSecurityCallback().dismiss(true, userId, getSecurityMode()); } } else { - playAuthenticationHaptics(/* unlock= */false); + mBouncerHapticPlayer.playAuthenticationFeedback( + /* authenticationSucceeded = */false + ); mView.resetPasswordText(true /* animate */, false /* announce deletion if no match */); if (isValidPassword) { getKeyguardSecurityCallback().reportUnlockAttempt(userId, false, timeoutMs); @@ -216,18 +214,6 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey } } - private void playAuthenticationHaptics(boolean unlock) { - if (!msdlFeedback() || mMSDLPlayer == null) return; - - MSDLToken token; - if (unlock) { - token = MSDLToken.UNLOCK; - } else { - token = MSDLToken.FAILURE; - } - mMSDLPlayer.playToken(token, mAuthInteractionProperties); - } - protected void startErrorAnimation() { /* no-op */ } protected void verifyPasswordAndUnlock() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java index 92e5432ad243..ff788484c819 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java @@ -35,6 +35,7 @@ import com.android.systemui.Flags; import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor; import com.android.systemui.bouncer.ui.BouncerMessageView; import com.android.systemui.bouncer.ui.binder.BouncerMessageViewBinder; +import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; @@ -45,9 +46,6 @@ import com.android.systemui.user.domain.interactor.SelectedUserInteractor; import com.android.systemui.util.ViewController; import com.android.systemui.util.concurrency.DelayableExecutor; -import com.google.android.msdl.domain.InteractionProperties; -import com.google.android.msdl.domain.MSDLPlayer; - import javax.inject.Inject; /** Controller for a {@link KeyguardSecurityView}. */ @@ -66,21 +64,22 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {}; private final FeatureFlags mFeatureFlags; protected final SelectedUserInteractor mSelectedUserInteractor; - protected final InteractionProperties mAuthInteractionProperties = - new AuthInteractionProperties(); + protected final BouncerHapticPlayer mBouncerHapticPlayer; protected KeyguardInputViewController(T view, SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback, EmergencyButtonController emergencyButtonController, @Nullable KeyguardMessageAreaController.Factory messageAreaControllerFactory, FeatureFlags featureFlags, - SelectedUserInteractor selectedUserInteractor) { + SelectedUserInteractor selectedUserInteractor, + BouncerHapticPlayer bouncerHapticPlayer) { super(view); mSecurityMode = securityMode; mKeyguardSecurityCallback = keyguardSecurityCallback; mEmergencyButtonController = emergencyButtonController; mFeatureFlags = featureFlags; mSelectedUserInteractor = selectedUserInteractor; + mBouncerHapticPlayer = bouncerHapticPlayer; if (messageAreaControllerFactory != null) { try { BouncerKeyguardMessageArea kma = view.requireViewById(R.id.bouncer_message_area); @@ -219,7 +218,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> private final SelectedUserInteractor mSelectedUserInteractor; private final UiEventLogger mUiEventLogger; private final KeyguardKeyboardInteractor mKeyguardKeyboardInteractor; - private final MSDLPlayer mMSDLPlayer; + private final BouncerHapticPlayer mBouncerHapticPlayer; private final UserActivityNotifier mUserActivityNotifier; @Inject @@ -236,7 +235,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor, UiEventLogger uiEventLogger, KeyguardKeyboardInteractor keyguardKeyboardInteractor, - MSDLPlayer msdlPlayer, + BouncerHapticPlayer bouncerHapticPlayer, UserActivityNotifier userActivityNotifier) { mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; @@ -255,7 +254,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> mSelectedUserInteractor = selectedUserInteractor; mUiEventLogger = uiEventLogger; mKeyguardKeyboardInteractor = keyguardKeyboardInteractor; - mMSDLPlayer = msdlPlayer; + mBouncerHapticPlayer = bouncerHapticPlayer; mUserActivityNotifier = userActivityNotifier; } @@ -272,7 +271,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> keyguardSecurityCallback, mLatencyTracker, mFalsingCollector, emergencyButtonController, mMessageAreaControllerFactory, mDevicePostureController, mFeatureFlags, mSelectedUserInteractor, - mMSDLPlayer); + mBouncerHapticPlayer); } else if (keyguardInputView instanceof KeyguardPasswordView) { return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, @@ -280,14 +279,14 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> mInputMethodManager, emergencyButtonController, mMainExecutor, mResources, mFalsingCollector, mKeyguardViewController, mDevicePostureController, mFeatureFlags, mSelectedUserInteractor, - mKeyguardKeyboardInteractor, mMSDLPlayer, mUserActivityNotifier); + mKeyguardKeyboardInteractor, mBouncerHapticPlayer, mUserActivityNotifier); } else if (keyguardInputView instanceof KeyguardPINView) { return new KeyguardPinViewController((KeyguardPINView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, mLiftToActivateListener, emergencyButtonController, mFalsingCollector, mDevicePostureController, mFeatureFlags, mSelectedUserInteractor, - mUiEventLogger, mKeyguardKeyboardInteractor, mMSDLPlayer, + mUiEventLogger, mKeyguardKeyboardInteractor, mBouncerHapticPlayer, mUserActivityNotifier); } else if (keyguardInputView instanceof KeyguardSimPinView) { return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView, @@ -295,14 +294,14 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, mLiftToActivateListener, mTelephonyManager, mFalsingCollector, emergencyButtonController, mFeatureFlags, mSelectedUserInteractor, - mKeyguardKeyboardInteractor, mMSDLPlayer, mUserActivityNotifier); + mKeyguardKeyboardInteractor, mBouncerHapticPlayer, mUserActivityNotifier); } else if (keyguardInputView instanceof KeyguardSimPukView) { return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, mLiftToActivateListener, mTelephonyManager, mFalsingCollector, emergencyButtonController, mFeatureFlags, mSelectedUserInteractor, - mKeyguardKeyboardInteractor, mMSDLPlayer, mUserActivityNotifier + mKeyguardKeyboardInteractor, mBouncerHapticPlayer, mUserActivityNotifier ); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java index 905fa0939a46..4628ed705d00 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java @@ -19,7 +19,6 @@ package com.android.keyguard; import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE; import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; -import android.annotation.Nullable; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; @@ -48,6 +47,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor; import com.android.systemui.Flags; +import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; @@ -56,8 +56,6 @@ import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; import com.android.systemui.util.concurrency.DelayableExecutor; -import com.google.android.msdl.domain.MSDLPlayer; - import java.util.List; public class KeyguardPasswordViewController @@ -138,12 +136,12 @@ public class KeyguardPasswordViewController FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor, KeyguardKeyboardInteractor keyguardKeyboardInteractor, - @Nullable MSDLPlayer msdlPlayer, + BouncerHapticPlayer bouncerHapticPlayer, UserActivityNotifier userActivityNotifier) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, falsingCollector, - emergencyButtonController, featureFlags, selectedUserInteractor, msdlPlayer, - userActivityNotifier); + emergencyButtonController, featureFlags, selectedUserInteractor, + bouncerHapticPlayer, userActivityNotifier); mKeyguardSecurityCallback = keyguardSecurityCallback; mInputMethodManager = inputMethodManager; mPostureController = postureController; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index f74d93e1d88d..7fb66640b29f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -36,7 +36,7 @@ import com.android.internal.widget.LockPatternView.Cell; import com.android.internal.widget.LockscreenCredential; import com.android.keyguard.EmergencyButtonController.EmergencyButtonCallback; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; -import com.android.systemui.bouncer.ui.helper.BouncerHapticHelper; +import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer; import com.android.systemui.classifier.FalsingClassifier; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; @@ -44,8 +44,6 @@ import com.android.systemui.res.R; import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; -import com.google.android.msdl.domain.MSDLPlayer; - import java.util.HashMap; import java.util.List; import java.util.Map; @@ -70,7 +68,6 @@ public class KeyguardPatternViewController private LockPatternView mLockPatternView; private CountDownTimer mCountdownTimer; private AsyncTask<?, ?, ?> mPendingLockCheck; - private MSDLPlayer mMSDLPlayer; private EmergencyButtonCallback mEmergencyButtonCallback = new EmergencyButtonCallback() { @Override @@ -80,7 +77,7 @@ public class KeyguardPatternViewController }; private final LockPatternView.ExternalHapticsPlayer mExternalHapticsPlayer = () -> { - BouncerHapticHelper.INSTANCE.playPatternDotFeedback(mMSDLPlayer, mView); + mBouncerHapticPlayer.playPatternDotFeedback(mView); }; /** @@ -174,9 +171,8 @@ public class KeyguardPatternViewController boolean isValidPattern) { boolean dismissKeyguard = mSelectedUserInteractor.getSelectedUserId() == userId; if (matched) { - BouncerHapticHelper.INSTANCE.playMSDLAuthenticationFeedback( - /* authenticationSucceeded= */true, - /* player =*/mMSDLPlayer + mBouncerHapticPlayer.playAuthenticationFeedback( + /* authenticationSucceeded= */true ); getKeyguardSecurityCallback().reportUnlockAttempt(userId, true, 0); if (dismissKeyguard) { @@ -185,9 +181,8 @@ public class KeyguardPatternViewController getKeyguardSecurityCallback().dismiss(true, userId, SecurityMode.Pattern); } } else { - BouncerHapticHelper.INSTANCE.playMSDLAuthenticationFeedback( - /* authenticationSucceeded= */false, - /* player =*/mMSDLPlayer + mBouncerHapticPlayer.playAuthenticationFeedback( + /* authenticationSucceeded= */false ); mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong); if (isValidPattern) { @@ -216,9 +211,11 @@ public class KeyguardPatternViewController EmergencyButtonController emergencyButtonController, KeyguardMessageAreaController.Factory messageAreaControllerFactory, DevicePostureController postureController, FeatureFlags featureFlags, - SelectedUserInteractor selectedUserInteractor, MSDLPlayer msdlPlayer) { + SelectedUserInteractor selectedUserInteractor, BouncerHapticPlayer bouncerHapticPlayer + ) { super(view, securityMode, keyguardSecurityCallback, emergencyButtonController, - messageAreaControllerFactory, featureFlags, selectedUserInteractor); + messageAreaControllerFactory, featureFlags, selectedUserInteractor, + bouncerHapticPlayer); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; mLatencyTracker = latencyTracker; @@ -228,7 +225,6 @@ public class KeyguardPatternViewController featureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)); mLockPatternView = mView.findViewById(R.id.lockPatternView); mPostureController = postureController; - mMSDLPlayer = msdlPlayer; } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java index f575cf29f402..d999994a3312 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java @@ -16,11 +16,9 @@ package com.android.keyguard; -import static com.android.systemui.Flags.msdlFeedback; import static com.android.systemui.Flags.pinInputFieldStyledFocusState; import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; -import android.annotation.Nullable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.StateListDrawable; @@ -37,14 +35,12 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor; import com.android.systemui.Flags; +import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.res.R; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; -import com.google.android.msdl.data.model.MSDLToken; -import com.google.android.msdl.domain.MSDLPlayer; - public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinBasedInputView> extends KeyguardAbsKeyInputViewController<T> { @@ -83,12 +79,12 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor, KeyguardKeyboardInteractor keyguardKeyboardInteractor, - @Nullable MSDLPlayer msdlPlayer, + BouncerHapticPlayer bouncerHapticPlayer, UserActivityNotifier userActivityNotifier) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, falsingCollector, - emergencyButtonController, featureFlags, selectedUserInteractor, msdlPlayer, - userActivityNotifier); + emergencyButtonController, featureFlags, selectedUserInteractor, + bouncerHapticPlayer, userActivityNotifier); mLiftToActivateListener = liftToActivateListener; mFalsingCollector = falsingCollector; mKeyguardKeyboardInteractor = keyguardKeyboardInteractor; @@ -110,16 +106,16 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB return false; }); button.setAnimationEnabled(showAnimations); - button.setMSDLPlayer(mMSDLPlayer); + button.setBouncerHapticHelper(mBouncerHapticPlayer); } mPasswordEntry.setOnKeyListener(mOnKeyListener); mPasswordEntry.setUserActivityListener(this::onUserInput); View deleteButton = mView.findViewById(R.id.delete_button); - if (msdlFeedback()) { + if (mBouncerHapticPlayer.isEnabled()) { deleteButton.setOnTouchListener((View view, MotionEvent event) -> { - if (event.getActionMasked() == MotionEvent.ACTION_DOWN && mMSDLPlayer != null) { - mMSDLPlayer.playToken(MSDLToken.KEYPRESS_DELETE, null); + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + mBouncerHapticPlayer.playDeleteKeyPressFeedback(); } return false; }); @@ -137,8 +133,8 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB if (mPasswordEntry.isEnabled()) { mView.resetPasswordText(true /* animate */, true /* announce */); } - if (msdlFeedback() && mMSDLPlayer != null) { - mMSDLPlayer.playToken(MSDLToken.LONG_PRESS, null); + if (mBouncerHapticPlayer.isEnabled()) { + mBouncerHapticPlayer.playDeleteKeyLongPressedFeedback(); } else { mView.doHapticKeyClick(); } @@ -147,7 +143,7 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB View okButton = mView.findViewById(R.id.key_enter); if (okButton != null) { - if (!msdlFeedback()) { + if (!mBouncerHapticPlayer.isEnabled()) { okButton.setOnTouchListener(mActionButtonTouchListener); } okButton.setOnClickListener(v -> { @@ -201,7 +197,7 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB for (NumPadKey button : mView.getButtons()) { button.setOnTouchListener(null); - button.setMSDLPlayer(null); + button.setBouncerHapticHelper(null); } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java index 3b5bf1a422a3..d3c02e6f6449 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java @@ -18,7 +18,6 @@ package com.android.keyguard; import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE; -import android.annotation.Nullable; import android.view.View; import com.android.internal.logging.UiEvent; @@ -27,6 +26,7 @@ import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor; +import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; @@ -34,8 +34,6 @@ import com.android.systemui.res.R; import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; -import com.google.android.msdl.domain.MSDLPlayer; - public class KeyguardPinViewController extends KeyguardPinBasedInputViewController<KeyguardPINView> { private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @@ -65,12 +63,12 @@ public class KeyguardPinViewController DevicePostureController postureController, FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor, UiEventLogger uiEventLogger, KeyguardKeyboardInteractor keyguardKeyboardInteractor, - @Nullable MSDLPlayer msdlPlayer, + BouncerHapticPlayer bouncerHapticPlayer, UserActivityNotifier userActivityNotifier) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor, - keyguardKeyboardInteractor, msdlPlayer, userActivityNotifier); + keyguardKeyboardInteractor, bouncerHapticPlayer, userActivityNotifier); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mPostureController = postureController; mLockPatternUtils = lockPatternUtils; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java index 47fe2b22b5f6..1c1acf83fa12 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java @@ -21,7 +21,6 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat; import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.app.Dialog; @@ -44,13 +43,12 @@ import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor; +import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.res.R; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; -import com.google.android.msdl.domain.MSDLPlayer; - public class KeyguardSimPinViewController extends KeyguardPinBasedInputViewController<KeyguardSimPinView> { public static final String TAG = "KeyguardSimPinView"; @@ -99,12 +97,12 @@ public class KeyguardSimPinViewController EmergencyButtonController emergencyButtonController, FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor, KeyguardKeyboardInteractor keyguardKeyboardInteractor, - @Nullable MSDLPlayer msdlPlayer, + BouncerHapticPlayer bouncerHapticPlayer, UserActivityNotifier userActivityNotifier) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor, - keyguardKeyboardInteractor, msdlPlayer, userActivityNotifier); + keyguardKeyboardInteractor, bouncerHapticPlayer, userActivityNotifier); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mTelephonyManager = telephonyManager; mSimImageView = mView.findViewById(R.id.keyguard_sim); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java index c688acb8d760..9adc5bae1ada 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java @@ -17,7 +17,6 @@ package com.android.keyguard; import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; @@ -39,13 +38,12 @@ import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor; +import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.res.R; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; -import com.google.android.msdl.domain.MSDLPlayer; - public class KeyguardSimPukViewController extends KeyguardPinBasedInputViewController<KeyguardSimPukView> { private static final boolean DEBUG = KeyguardConstants.DEBUG; @@ -96,12 +94,12 @@ public class KeyguardSimPukViewController EmergencyButtonController emergencyButtonController, FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor, KeyguardKeyboardInteractor keyguardKeyboardInteractor, - @Nullable MSDLPlayer msdlPlayer, + BouncerHapticPlayer bouncerHapticPlayer, UserActivityNotifier userActivityNotifier) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor, - keyguardKeyboardInteractor, msdlPlayer, userActivityNotifier); + keyguardKeyboardInteractor, bouncerHapticPlayer, userActivityNotifier); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mTelephonyManager = telephonyManager; mSimImageView = mView.findViewById(R.id.keyguard_sim); diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java index 4fb80de2d4ec..7fe4ec852045 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java @@ -15,7 +15,6 @@ */ package com.android.keyguard; -import static com.android.systemui.Flags.msdlFeedback; import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY; import android.content.Context; @@ -37,11 +36,9 @@ import android.widget.TextView; import androidx.annotation.Nullable; import com.android.settingslib.Utils; +import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer; import com.android.systemui.res.R; -import com.google.android.msdl.data.model.MSDLToken; -import com.google.android.msdl.domain.MSDLPlayer; - /** * Viewgroup for the bouncer numpad button, specifically for digits. */ @@ -62,7 +59,7 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener { private NumPadAnimator mAnimator; private int mOrientation; @Nullable - private MSDLPlayer mMSDLPlayer; + private BouncerHapticPlayer mBouncerHapticPlayer; private View.OnClickListener mListener = new View.OnClickListener() { @Override @@ -227,8 +224,8 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener { // Cause a VIRTUAL_KEY vibration public void doHapticKeyClick() { - if (msdlFeedback() && mMSDLPlayer != null) { - mMSDLPlayer.playToken(MSDLToken.KEYPRESS_STANDARD, null); + if (mBouncerHapticPlayer != null && mBouncerHapticPlayer.isEnabled()) { + mBouncerHapticPlayer.playNumpadKeyFeedback(); } else { performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); @@ -255,7 +252,7 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener { info.setTextEntryKey(true); } - public void setMSDLPlayer(@Nullable MSDLPlayer player) { - mMSDLPlayer = player; + public void setBouncerHapticHelper(@Nullable BouncerHapticPlayer bouncerHapticPlayer) { + mBouncerHapticPlayer = bouncerHapticPlayer; } } diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticHelper.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticPlayer.kt index 1faacff996ca..19e7537007bf 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticPlayer.kt @@ -23,25 +23,28 @@ import com.android.systemui.Flags //noinspection CleanArchitectureDependencyViolation: Data layer only referenced for this enum class import com.google.android.msdl.data.model.MSDLToken import com.google.android.msdl.domain.MSDLPlayer +import javax.inject.Inject -/** A helper object to deliver haptic feedback in bouncer interactions. */ -object BouncerHapticHelper { +/** + * A helper class to deliver haptic feedback in bouncer interactions. + * + * @param[msdlPlayer] The [MSDLPlayer] used to deliver MSDL feedback. + */ +class BouncerHapticPlayer @Inject constructor(private val msdlPlayer: dagger.Lazy<MSDLPlayer>) { + + private val authInteractionProperties by + lazy(LazyThreadSafetyMode.NONE) { AuthInteractionProperties() } - private val authInteractionProperties = AuthInteractionProperties() + val isEnabled: Boolean + get() = Flags.msdlFeedback() /** * Deliver MSDL feedback as a result of authenticating through a bouncer. * * @param[authenticationSucceeded] Whether the authentication was successful or not. - * @param[player] The [MSDLPlayer] that delivers the correct feedback. */ - fun playMSDLAuthenticationFeedback( - authenticationSucceeded: Boolean, - player: MSDLPlayer?, - ) { - if (player == null || !Flags.msdlFeedback()) { - return - } + fun playAuthenticationFeedback(authenticationSucceeded: Boolean) { + if (!isEnabled) return val token = if (authenticationSucceeded) { @@ -49,7 +52,7 @@ object BouncerHapticHelper { } else { MSDLToken.FAILURE } - player.playToken(token, authInteractionProperties) + msdlPlayer.get().playToken(token, authInteractionProperties) } /** @@ -57,17 +60,29 @@ object BouncerHapticHelper { * MSDL feedback using a [MSDLPlayer], or fallback to a default haptic feedback using the * [View.performHapticFeedback] API and a [View]. * - * @param[player] [MSDLPlayer] for MSDL feedback. * @param[view] A [View] for default haptic feedback using [View.performHapticFeedback] */ - fun playPatternDotFeedback(player: MSDLPlayer?, view: View?) { - if (player == null || !Flags.msdlFeedback()) { + fun playPatternDotFeedback(view: View?) { + if (!isEnabled) { view?.performHapticFeedback( HapticFeedbackConstants.VIRTUAL_KEY, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING, ) } else { - player.playToken(MSDLToken.DRAG_INDICATOR) + msdlPlayer.get().playToken(MSDLToken.DRAG_INDICATOR) } } + + /** Deliver MSDL feedback when the delete key of the pin bouncer is pressed */ + fun playDeleteKeyPressFeedback() = msdlPlayer.get().playToken(MSDLToken.KEYPRESS_DELETE) + + /** + * Deliver MSDL feedback when the delete key of the pin bouncer is long-pressed + * + * @return whether MSDL feedback is allowed to play. + */ + fun playDeleteKeyLongPressedFeedback() = msdlPlayer.get().playToken(MSDLToken.LONG_PRESS) + + /** Deliver MSDL feedback when a numpad key is pressed on the pin bouncer */ + fun playNumpadKeyFeedback() = msdlPlayer.get().playToken(MSDLToken.KEYPRESS_STANDARD) } diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt index df6ca9bf0511..da29c6230cd8 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt @@ -31,6 +31,7 @@ import com.android.keyguard.PinShapeAdapter import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.bouncer.domain.interactor.BouncerInteractor import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor +import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags import com.android.systemui.res.R import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -265,6 +266,15 @@ constructor( } } + /** Notifies that the user has pressed down on a digit button. */ + fun onDigitButtonDown() { + if (ComposeBouncerFlags.isOnlyComposeBouncerEnabled()) { + // Current PIN bouncer informs FalsingInteractor#avoidGesture() upon every Pin button + // touch. + super.onDown() + } + } + @AssistedFactory interface Factory { fun create( diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java index dcd419512498..a62600d65d4b 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java @@ -25,6 +25,7 @@ import javax.inject.Inject; public class FalsingCollectorFake implements FalsingCollector { public KeyEvent lastKeyEvent = null; + public boolean avoidGestureInvoked = false; @Override public void init() { @@ -87,6 +88,16 @@ public class FalsingCollectorFake implements FalsingCollector { @Override public void avoidGesture() { + avoidGestureInvoked = true; + } + + /** + * @return whether {@link #avoidGesture()} was invoked. + */ + public boolean wasLastGestureAvoided() { + boolean wasLastGestureAvoided = avoidGestureInvoked; + avoidGestureInvoked = false; + return wasLastGestureAvoided; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt index 7018f9dc8556..dbd7f0739f6c 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt @@ -24,8 +24,11 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.data.repository.DeviceEntryRepository import com.android.systemui.keyguard.DismissCallbackRegistry +import com.android.systemui.scene.data.model.asIterable +import com.android.systemui.scene.domain.interactor.SceneBackInteractor import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.util.kotlin.pairwise import com.android.systemui.utils.coroutines.flow.mapLatestConflated import javax.inject.Inject import kotlinx.coroutines.CoroutineScope @@ -34,6 +37,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map @@ -59,6 +63,7 @@ constructor( private val deviceUnlockedInteractor: DeviceUnlockedInteractor, private val alternateBouncerInteractor: AlternateBouncerInteractor, private val dismissCallbackRegistry: DismissCallbackRegistry, + sceneBackInteractor: SceneBackInteractor, ) { /** * Whether the device is unlocked. @@ -86,19 +91,40 @@ constructor( * Note: This does not imply that the lockscreen is visible or not. */ val isDeviceEntered: StateFlow<Boolean> = - sceneInteractor.currentScene - .filter { currentScene -> - currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen - } - .mapLatestConflated { scene -> - if (scene == Scenes.Gone) { - // Make sure device unlock status is definitely unlocked before we consider the - // device "entered". - deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked } - true - } else { - false - } + combine( + // This flow emits true when the currentScene switches to Gone for the first time + // after having been on Lockscreen. + sceneInteractor.currentScene + .filter { currentScene -> + currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen + } + .mapLatestConflated { scene -> + if (scene == Scenes.Gone) { + // Make sure device unlock status is definitely unlocked before we + // consider the device "entered". + deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked } + true + } else { + false + } + }, + // This flow emits true only if the bottom of the navigation back stack has been + // switched from Lockscreen to Gone. In other words, only if the device was unlocked + // while visiting at least one scene "above" the Lockscreen scene. + sceneBackInteractor.backStack + // The bottom of the back stack, which is Lockscreen, Gone, or null if empty. + .map { it.asIterable().lastOrNull() } + // Filter out cases where the stack changes but the bottom remains unchanged. + .distinctUntilChanged() + // Detect changes of the bottom of the stack, start with null, so the first + // update emits a value and the logic doesn't need to wait for a second value + // before emitting something. + .pairwise(initialValue = null) + // Replacing a bottom of the stack that was Lockscreen with Gone constitutes a + // "device entered" event. + .map { (from, to) -> from == Scenes.Lockscreen && to == Scenes.Gone }, + ) { enteredDirectly, enteredOnBackStack -> + enteredOnBackStack || enteredDirectly } .stateIn( scope = applicationScope, @@ -129,7 +155,7 @@ constructor( }, isLockscreenEnabled, deviceUnlockedInteractor.deviceUnlockStatus, - isDeviceEntered + isDeviceEntered, ) { isNoneAuthMethod, isLockscreenEnabled, deviceUnlockStatus, isDeviceEntered -> val isSwipeAuthMethod = isNoneAuthMethod && isLockscreenEnabled (isSwipeAuthMethod || @@ -155,9 +181,7 @@ constructor( * canceled */ @JvmOverloads - fun attemptDeviceEntry( - callback: IKeyguardDismissCallback? = null, - ) { + fun attemptDeviceEntry(callback: IKeyguardDismissCallback? = null) { callback?.let { dismissCallbackRegistry.addCallback(it) } // TODO (b/307768356), diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt index dcca12f29287..beec34881636 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt @@ -736,14 +736,13 @@ private fun CategoryItemTwoPane( val interactionSource = remember { MutableInteractionSource() } val isFocused by interactionSource.collectIsFocusedAsState() - Surface( + SelectableShortcutSurface( selected = selected, onClick = onClick, modifier = Modifier.semantics { role = Role.Tab } .heightIn(min = 64.dp) .fillMaxWidth() - .focusable(interactionSource = interactionSource) .outlineFocusModifier( isFocused = isFocused, focusColor = MaterialTheme.colorScheme.secondary, @@ -752,6 +751,7 @@ private fun CategoryItemTwoPane( ), shape = RoundedCornerShape(28.dp), color = colors.containerColor(selected).value, + interactionSource = interactionSource ) { Row(Modifier.padding(horizontal = 24.dp), verticalAlignment = Alignment.CenterVertically) { ShortcutCategoryIcon( @@ -860,14 +860,12 @@ private fun ShortcutsSearchBar(onQueryChange: (String) -> Unit) { private fun KeyboardSettings(horizontalPadding: Dp, verticalPadding: Dp, onClick: () -> Unit) { val interactionSource = remember { MutableInteractionSource() } val isFocused by interactionSource.collectIsFocusedAsState() - Surface( + ClickableShortcutSurface( onClick = onClick, shape = RoundedCornerShape(24.dp), color = Color.Transparent, - modifier = - Modifier.semantics { role = Role.Button } - .fillMaxWidth() - .focusable(interactionSource = interactionSource) + modifier = Modifier.semantics { role = Role.Button }.fillMaxWidth(), + interactionSource = interactionSource ) { Row( modifier = diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt new file mode 100644 index 000000000000..3ba3bd8fdc2f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2024 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.keyboard.shortcut.ui.composable + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.selection.selectable +import androidx.compose.material3.ColorScheme +import androidx.compose.material3.LocalAbsoluteTonalElevation +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.LocalTonalElevationEnabled +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.contentColorFor +import androidx.compose.material3.minimumInteractiveComponentSize +import androidx.compose.material3.surfaceColorAtElevation +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.NonRestartableComposable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.android.compose.modifiers.thenIf + +/** + * A selectable surface with no default focus/hover indications. + * + * This composable is similar to [androidx.compose.material3.Surface], but removes default + * focus/hover states to enable custom implementations. + */ +@Composable +@NonRestartableComposable +fun SelectableShortcutSurface( + selected: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + shape: Shape = RectangleShape, + color: Color = MaterialTheme.colorScheme.surface, + contentColor: Color = contentColorFor(color), + tonalElevation: Dp = 0.dp, + shadowElevation: Dp = 0.dp, + border: BorderStroke? = null, + interactionSource: MutableInteractionSource? = null, + content: @Composable () -> Unit +) { + @Suppress("NAME_SHADOWING") + val interactionSource = interactionSource ?: remember { MutableInteractionSource() } + val absoluteElevation = LocalAbsoluteTonalElevation.current + tonalElevation + CompositionLocalProvider( + LocalContentColor provides contentColor, + LocalAbsoluteTonalElevation provides absoluteElevation + ) { + Box( + modifier = + modifier + .minimumInteractiveComponentSize() + .surface( + shape = shape, + backgroundColor = + surfaceColorAtElevation(color = color, elevation = absoluteElevation), + border = border, + shadowElevation = with(LocalDensity.current) { shadowElevation.toPx() } + ) + .selectable( + selected = selected, + interactionSource = interactionSource, + indication = null, + enabled = enabled, + onClick = onClick + ), + propagateMinConstraints = true + ) { + content() + } + } +} + +/** + * A clickable surface with no default focus/hover indications. + * + * This composable is similar to [androidx.compose.material3.Surface], but removes default + * focus/hover states to enable custom implementations. + */ +@Composable +@NonRestartableComposable +fun ClickableShortcutSurface( + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + shape: Shape = RectangleShape, + color: Color = MaterialTheme.colorScheme.surface, + contentColor: Color = contentColorFor(color), + tonalElevation: Dp = 0.dp, + shadowElevation: Dp = 0.dp, + border: BorderStroke? = null, + interactionSource: MutableInteractionSource? = null, + content: @Composable () -> Unit +) { + @Suppress("NAME_SHADOWING") + val interactionSource = interactionSource ?: remember { MutableInteractionSource() } + val absoluteElevation = LocalAbsoluteTonalElevation.current + tonalElevation + CompositionLocalProvider( + LocalContentColor provides contentColor, + LocalAbsoluteTonalElevation provides absoluteElevation + ) { + Box( + modifier = + modifier + .minimumInteractiveComponentSize() + .surface( + shape = shape, + backgroundColor = + surfaceColorAtElevation(color = color, elevation = absoluteElevation), + border = border, + shadowElevation = with(LocalDensity.current) { shadowElevation.toPx() } + ) + .clickable( + interactionSource = interactionSource, + indication = null, + enabled = enabled, + onClick = onClick + ), + propagateMinConstraints = true + ) { + content() + } + } +} + +@Composable +private fun surfaceColorAtElevation(color: Color, elevation: Dp): Color { + return MaterialTheme.colorScheme.applyTonalElevation(color, elevation) +} + +@Composable +internal fun ColorScheme.applyTonalElevation(backgroundColor: Color, elevation: Dp): Color { + val tonalElevationEnabled = LocalTonalElevationEnabled.current + return if (backgroundColor == surface && tonalElevationEnabled) { + surfaceColorAtElevation(elevation) + } else { + backgroundColor + } +} + +/** + * Applies surface-related modifiers to a composable. + * + * This function adds background, border, and shadow effects to a composable. Also ensure the + * composable is clipped to the given shape. + * + * @param shape The shape to apply to the composable's background, border, and clipping. + * @param backgroundColor The background color to apply to the composable. + * @param border An optional border to draw around the composable. + * @param shadowElevation The size of the shadow below the surface. To prevent shadow creep, only + * apply shadow elevation when absolutely necessary, such as when the surface requires visual + * separation from a patterned background. Note that It will not affect z index of the Surface. If + * you want to change the drawing order you can use `Modifier.zIndex`. + * @return The modified Modifier instance with surface-related modifiers applied. + */ +@Stable +private fun Modifier.surface( + shape: Shape, + backgroundColor: Color, + border: BorderStroke?, + shadowElevation: Float, +): Modifier { + return this.thenIf(shadowElevation > 0f) { + Modifier.graphicsLayer(shadowElevation = shadowElevation, shape = shape, clip = false) + } + .thenIf(border != null) { Modifier.border(border!!, shape) } + .background(color = backgroundColor, shape = shape) + .clip(shape) +} diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt index bf9ef8c5d24e..8505a784d302 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt @@ -1202,13 +1202,17 @@ constructor( commonViewModels.forEach { viewModel -> when (viewModel) { is MediaCommonViewModel.MediaControl -> { - controllerById[viewModel.instanceId.toString()]?.mediaViewHolder?.let { - mediaContent.addView(it.player) + controllerById[viewModel.instanceId.toString()]?.let { + it.widthInSceneContainerPx = widthInSceneContainerPx + it.heightInSceneContainerPx = heightInSceneContainerPx + mediaContent.addView(it.mediaViewHolder?.player) } } is MediaCommonViewModel.MediaRecommendations -> { - controllerById[viewModel.key]?.recommendationViewHolder?.let { - mediaContent.addView(it.recommendations) + controllerById[viewModel.key]?.let { + it.widthInSceneContainerPx = widthInSceneContainerPx + it.heightInSceneContainerPx = heightInSceneContainerPx + mediaContent.addView(it.recommendationViewHolder?.recommendations) } } } diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt index 2d40845df802..afb72f03b28d 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt @@ -71,6 +71,12 @@ constructor( logger.logSceneBackStack(backStack.value.asIterable()) } + /** Applies the given [transform] to the back stack. */ + fun updateBackStack(transform: (SceneStack) -> SceneStack) { + _backStack.update { stack -> transform(stack) } + logger.logSceneBackStack(backStack.value.asIterable()) + } + private fun stackOperation(from: SceneKey, to: SceneKey, stack: SceneStack): StackOperation? { val fromDistance = checkNotNull(sceneContainerConfig.navigationDistances[from]) { diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt index 18767f576fef..b11d8ed9ee3d 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt @@ -45,7 +45,6 @@ import com.android.systemui.deviceentry.shared.model.DeviceUnlockSource import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor import com.android.systemui.model.SceneContainerPlugin import com.android.systemui.model.SysUiState @@ -55,6 +54,7 @@ import com.android.systemui.plugins.FalsingManager.FalsingBeliefListener import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.power.shared.model.WakeSleepReason import com.android.systemui.scene.data.model.asIterable +import com.android.systemui.scene.data.model.sceneStackOf import com.android.systemui.scene.domain.interactor.SceneBackInteractor import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.SceneInteractor @@ -118,7 +118,6 @@ constructor( private val deviceUnlockedInteractor: DeviceUnlockedInteractor, private val bouncerInteractor: BouncerInteractor, private val keyguardInteractor: KeyguardInteractor, - private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val sysUiState: SysUiState, @DisplayId private val displayId: Int, private val sceneLogger: SceneLogger, @@ -419,7 +418,20 @@ constructor( " didn't need to be left open" } else { val prevScene = previousScene.value - (prevScene ?: Scenes.Gone) to + val targetScene = prevScene ?: Scenes.Gone + if (targetScene != Scenes.Gone) { + sceneBackInteractor.updateBackStack { stack -> + val list = stack.asIterable().toMutableList() + check(list.last() == Scenes.Lockscreen) { + "The bottommost/last SceneKey of the back stack isn't" + + " the Lockscreen scene like expected. The back" + + " stack is $stack." + } + list[list.size - 1] = Scenes.Gone + sceneStackOf(*list.toTypedArray()) + } + } + targetScene to "device was unlocked with primary bouncer showing," + " from sceneKey=$prevScene" } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 7786453814e0..db4f9ef13bd6 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -1991,7 +1991,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, : R.drawable.ic_volume_media_bt; } } else if (isStreamMuted(ss)) { - iconRes = (ss.muted && isTv()) ? R.drawable.ic_volume_media_off : row.iconMuteRes; + iconRes = row.iconMuteRes; } else { iconRes = mShowLowMediaVolumeIcon && ss.level * 2 < (ss.levelMax + ss.levelMin) ? R.drawable.ic_volume_media_low : row.iconRes; diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java index c0d8be322cd6..4bb01ec1e1df 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java @@ -43,6 +43,7 @@ import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; +import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.flags.FakeFeatureFlags; @@ -96,6 +97,8 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { private UserActivityNotifier mUserActivityNotifier; private KeyguardAbsKeyInputViewController mKeyguardAbsKeyInputViewController; private KosmosJavaAdapter mKosmosJavaAdapter = new KosmosJavaAdapter(this); + private final BouncerHapticPlayer mBouncerHapticPlayer = + mKosmosJavaAdapter.getBouncerHapticHelper(); private final FakeMSDLPlayer mMSDLPlayer = mKosmosJavaAdapter.getMsdlPlayer(); @Before @@ -119,8 +122,8 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { return new KeyguardAbsKeyInputViewController(mAbsKeyInputView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, mKeyguardMessageAreaControllerFactory, mLatencyTracker, mFalsingCollector, - mEmergencyButtonController, mFeatureFlags, mSelectedUserInteractor, mMSDLPlayer, - mUserActivityNotifier) { + mEmergencyButtonController, mFeatureFlags, mSelectedUserInteractor, + mBouncerHapticPlayer, mUserActivityNotifier) { @Override void resetState() { } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt index 873bc2c92431..2c1dacdfae73 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt @@ -35,11 +35,13 @@ import com.android.systemui.classifier.FalsingCollector import com.android.systemui.classifier.FalsingCollectorFake import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.haptics.msdl.bouncerHapticPlayer import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository import com.android.systemui.res.R import com.android.systemui.statusbar.policy.DevicePostureController import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED +import com.android.systemui.testKosmos import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat @@ -107,6 +109,8 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { @Captor lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback> + private val kosmos = testKosmos() + @Before fun setup() { MockitoAnnotations.initMocks(this) @@ -151,8 +155,8 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { mSelectedUserInteractor, uiEventLogger, keyguardKeyboardInteractor, - null, - mUserActivityNotifier + kosmos.bouncerHapticPlayer, + mUserActivityNotifier, ) } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt index f141a4926149..9cd52153eff6 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt @@ -28,8 +28,10 @@ import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollector import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.haptics.msdl.bouncerHapticPlayer import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository import com.android.systemui.res.R +import com.android.systemui.testKosmos import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock @@ -73,6 +75,8 @@ class KeyguardSimPinViewControllerTest : SysuiTestCase() { private val updateMonitorCallbackArgumentCaptor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) + private val kosmos = testKosmos() + @Before fun setup() { MockitoAnnotations.initMocks(this) @@ -103,8 +107,8 @@ class KeyguardSimPinViewControllerTest : SysuiTestCase() { fakeFeatureFlags, mSelectedUserInteractor, keyguardKeyboardInteractor, - null, - mUserActivityNotifier + kosmos.bouncerHapticPlayer, + mUserActivityNotifier, ) underTest.init() underTest.onViewAttached() @@ -162,14 +166,14 @@ class KeyguardSimPinViewControllerTest : SysuiTestCase() { updateMonitorCallbackArgumentCaptor.value.onSimStateChanged( /* subId= */ 0, /* slotId= */ 0, - TelephonyManager.SIM_STATE_PIN_REQUIRED + TelephonyManager.SIM_STATE_PIN_REQUIRED, ) verify(keyguardSecurityCallback, never()).showCurrentSecurityScreen() updateMonitorCallbackArgumentCaptor.value.onSimStateChanged( /* subId= */ 0, /* slotId= */ 0, - TelephonyManager.SIM_STATE_PUK_REQUIRED + TelephonyManager.SIM_STATE_PUK_REQUIRED, ) verify(keyguardSecurityCallback).showCurrentSecurityScreen() diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt index a03c8391fa0f..3c229975eef5 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt @@ -29,8 +29,10 @@ import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollector import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.haptics.msdl.bouncerHapticPlayer import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository import com.android.systemui.res.R +import com.android.systemui.testKosmos import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.mockito.any import org.junit.Before @@ -65,6 +67,8 @@ class KeyguardSimPukViewControllerTest : SysuiTestCase() { KeyguardMessageAreaController<BouncerKeyguardMessageArea> @Mock private lateinit var mUserActivityNotifier: UserActivityNotifier + private val kosmos = testKosmos() + @Before fun setup() { MockitoAnnotations.initMocks(this) @@ -98,8 +102,8 @@ class KeyguardSimPukViewControllerTest : SysuiTestCase() { fakeFeatureFlags, mSelectedUserInteractor, keyguardKeyboardInteractor, - null, - mUserActivityNotifier + kosmos.bouncerHapticPlayer, + mUserActivityNotifier, ) underTest.init() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.kt index d31491d22435..25c4bbb75aec 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.kt @@ -18,4 +18,6 @@ package com.android.systemui.classifier import com.android.systemui.kosmos.Kosmos -var Kosmos.falsingCollector by Kosmos.Fixture<FalsingCollector> { FalsingCollectorFake() } +var Kosmos.fakeFalsingCollector by Kosmos.Fixture { FalsingCollectorFake() } + +var Kosmos.falsingCollector by Kosmos.Fixture<FalsingCollector> { fakeFalsingCollector } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt index 13116e7fd46f..096022ce1507 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt @@ -22,6 +22,7 @@ import com.android.systemui.deviceentry.data.repository.deviceEntryRepository import com.android.systemui.keyguard.dismissCallbackRegistry import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -36,5 +37,6 @@ val Kosmos.deviceEntryInteractor by deviceUnlockedInteractor = deviceUnlockedInteractor, alternateBouncerInteractor = alternateBouncerInteractor, dismissCallbackRegistry = dismissCallbackRegistry, + sceneBackInteractor = sceneBackInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/BouncerHapticHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/BouncerHapticHelperKosmos.kt new file mode 100644 index 000000000000..94982edcd5f3 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/BouncerHapticHelperKosmos.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 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.haptics.msdl + +import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer +import com.android.systemui.kosmos.Kosmos +import com.google.android.msdl.domain.MSDLPlayer +import dagger.Lazy + +val Kosmos.bouncerHapticPlayer: BouncerHapticPlayer by + Kosmos.Fixture { + val lazyPlayer = Lazy<MSDLPlayer> { fakeMSDLPlayer } + BouncerHapticPlayer(lazyPlayer) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt index c60305e85b22..f97f30383398 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt @@ -36,6 +36,7 @@ import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor import com.android.systemui.globalactions.domain.interactor.globalActionsInteractor +import com.android.systemui.haptics.msdl.bouncerHapticPlayer import com.android.systemui.haptics.msdl.fakeMSDLPlayer import com.android.systemui.haptics.qs.qsLongPressEffect import com.android.systemui.jank.interactionJankMonitor @@ -158,4 +159,5 @@ class KosmosJavaAdapter() { val sceneContainerOcclusionInteractor by lazy { kosmos.sceneContainerOcclusionInteractor } val msdlPlayer by lazy { kosmos.fakeMSDLPlayer } val shadeModeInteractor by lazy { kosmos.shadeModeInteractor } + val bouncerHapticHelper by lazy { kosmos.bouncerHapticPlayer } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt index 9a5698cfb8ca..4228c3c0b110 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt @@ -32,13 +32,11 @@ import com.android.systemui.haptics.vibratorHelper import com.android.systemui.keyguard.dismissCallbackRegistry import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor import com.android.systemui.keyguard.domain.interactor.keyguardInteractor -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.domain.interactor.windowManagerLockscreenVisibilityInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.testScope import com.android.systemui.model.sysUiState -import com.android.systemui.plugins.statusbar.statusBarStateController import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor @@ -62,7 +60,6 @@ val Kosmos.sceneContainerStartable by Fixture { deviceUnlockedInteractor = deviceUnlockedInteractor, bouncerInteractor = bouncerInteractor, keyguardInteractor = keyguardInteractor, - keyguardTransitionInteractor = keyguardTransitionInteractor, sysUiState = sysUiState, displayId = displayTracker.defaultDisplayId, sceneLogger = sceneLogger, diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java index f6c3d8ef1249..1346a294b7d8 100644 --- a/services/core/java/com/android/server/power/hint/HintManagerService.java +++ b/services/core/java/com/android/server/power/hint/HintManagerService.java @@ -160,6 +160,8 @@ public final class HintManagerService extends SystemService { private static final String PROPERTY_SF_ENABLE_CPU_HINT = "debug.sf.enable_adpf_cpu_hint"; private static final String PROPERTY_HWUI_ENABLE_HINT_MANAGER = "debug.hwui.use_hint_manager"; + private Boolean mFMQUsesIntegratedEventFlag = false; + @VisibleForTesting final IHintManager.Stub mService = new BinderService(); public HintManagerService(Context context) { @@ -1032,7 +1034,7 @@ public final class HintManagerService extends SystemService { @Override public IHintSession createHintSessionWithConfig(@NonNull IBinder token, @NonNull int[] tids, long durationNanos, @SessionTag int tag, - @Nullable SessionConfig config) { + SessionConfig config) { if (!isHalSupported()) { throw new UnsupportedOperationException("PowerHAL is not supported!"); } @@ -1070,7 +1072,7 @@ public final class HintManagerService extends SystemService { default -> tag = SessionTag.APP; } } - + config.id = -1; Long halSessionPtr = null; if (mConfigCreationSupport.get()) { try { @@ -1109,7 +1111,7 @@ public final class HintManagerService extends SystemService { } } - final long sessionId = config != null ? config.id : halSessionPtr; + final long sessionId = config.id != -1 ? config.id : halSessionPtr; logPerformanceHintSessionAtom( callingUid, sessionId, durationNanos, tids, tag); @@ -1144,14 +1146,23 @@ public final class HintManagerService extends SystemService { } @Override - public ChannelConfig getSessionChannel(IBinder token) { - if (mPowerHalVersion < 5 || !adpfUseFmqChannel()) { + public @Nullable ChannelConfig getSessionChannel(IBinder token) { + if (mPowerHalVersion < 5 || !adpfUseFmqChannel() + || mFMQUsesIntegratedEventFlag) { return null; } java.util.Objects.requireNonNull(token); final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid()); final int callingUid = Binder.getCallingUid(); ChannelItem item = getOrCreateMappedChannelItem(callingTgid, callingUid, token); + // FMQ V1 requires a separate event flag to be passed, and the default no-op + // implmenentation in PowerHAL does not return such a shared flag. This helps + // avoid using the FMQ on a default impl that does not support it. + if (item.getConfig().eventFlagDescriptor == null) { + mFMQUsesIntegratedEventFlag = true; + closeSessionChannel(); + return null; + } return item.getConfig(); }; @@ -1270,8 +1281,14 @@ public final class HintManagerService extends SystemService { @VisibleForTesting boolean updateHintAllowedByProcState(boolean allowed) { synchronized (this) { - if (allowed && !mUpdateAllowedByProcState && !mShouldForcePause) resume(); - if (!allowed && mUpdateAllowedByProcState) pause(); + if (allowed && !mUpdateAllowedByProcState && !mShouldForcePause) { + Slogf.e(TAG, "ADPF IS GETTING RESUMED? UID: " + mUid + " TAG: " + mTag); + resume(); + } + if (!allowed && mUpdateAllowedByProcState) { + Slogf.e(TAG, "ADPF IS GETTING PAUSED? UID: " + mUid + " TAG: " + mTag); + pause(); + } mUpdateAllowedByProcState = allowed; return mUpdateAllowedByProcState; } diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java index 06a2565da75a..81217014bafe 100644 --- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java +++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java @@ -51,6 +51,7 @@ import static android.hardware.SensorPrivacyManager.StateTypes.ENABLED_EXCEPT_AL import static android.hardware.SensorPrivacyManager.TOGGLE_TYPE_HARDWARE; import static android.hardware.SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE; import static android.os.UserHandle.USER_NULL; +import static android.os.UserHandle.getCallingUserId; import static android.service.SensorPrivacyIndividualEnabledSensorProto.UNKNOWN; import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION; @@ -187,6 +188,7 @@ public final class SensorPrivacyService extends SystemService { private final TelephonyManager mTelephonyManager; private final PackageManagerInternal mPackageManagerInternal; private final NotificationManager mNotificationManager; + private final UserManager mUserManager; private CameraPrivacyLightController mCameraPrivacyLightController; @@ -214,6 +216,7 @@ public final class SensorPrivacyService extends SystemService { mTelephonyManager = context.getSystemService(TelephonyManager.class); mPackageManagerInternal = getLocalService(PackageManagerInternal.class); mNotificationManager = mContext.getSystemService(NotificationManager.class); + mUserManager = context.getSystemService(UserManager.class); mSensorPrivacyServiceImpl = new SensorPrivacyServiceImpl(); for (String entry : SystemConfig.getInstance().getCameraPrivacyAllowlist()) { mCameraPrivacyAllowlist.add(entry); @@ -379,14 +382,23 @@ public final class SensorPrivacyService extends SystemService { public void onUserRestrictionsChanged(int userId, Bundle newRestrictions, Bundle prevRestrictions) { // Reset sensor privacy when restriction is added + // Note: isValidCallingUser needs to be called before resetting sensor privacy + // because DISALLOW_CAMERA_TOGGLE and DISALLOW_MICROPHONE_TOGGLE are applied on + // visible background users in Automotive's Multi Display configuration but we don't + // allow sensor privacy to be set on a visible background user. if (!prevRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE) && newRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE)) { - setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, OTHER, CAMERA, false); + if (isValidCallingUser(userId)) { + setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, OTHER, CAMERA, + false); + } } if (!prevRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE) && newRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE)) { - setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, OTHER, MICROPHONE, - false); + if (isValidCallingUser(userId)) { + setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, OTHER, MICROPHONE, + false); + } } } @@ -779,6 +791,10 @@ public final class SensorPrivacyService extends SystemService { @Override public void setSensorPrivacy(boolean enable) { enforceManageSensorPrivacyPermission(); + + // Enforce valid calling user on devices that enable visible background users. + enforceValidCallingUser(getCallingUserId()); + mSensorPrivacyStateController.setAllSensorState(enable); } @@ -795,11 +811,15 @@ public final class SensorPrivacyService extends SystemService { + " enable=" + enable + ")"); } + enforceManageSensorPrivacyPermission(); if (userId == UserHandle.USER_CURRENT) { userId = mCurrentUser; } + // Enforce valid calling user on devices that enable visible background users. + enforceValidCallingUser(userId); + if (!canChangeToggleSensorPrivacy(userId, sensor)) { return; } @@ -831,6 +851,9 @@ public final class SensorPrivacyService extends SystemService { userId = mCurrentUser; } + // Enforce valid calling user on devices that enable visible background users. + enforceValidCallingUser(userId); + if (!canChangeToggleSensorPrivacy(userId, sensor)) { return; } @@ -1151,6 +1174,42 @@ public final class SensorPrivacyService extends SystemService { }); } + // This method enforces valid calling user on devices that enable visible background users. + // Only system user or current user or the user that belongs to the same profile group + // as the current user is permitted to toggle sensor privacy. + // Visible background users are not permitted to toggle sensor privacy. + private void enforceValidCallingUser(@UserIdInt int userId) { + if (!isValidCallingUser(userId)) { + throw new SecurityException("User " + userId + + " is not permitted to toggle sensor privacy"); + } + } + + private boolean isValidCallingUser(@UserIdInt int userId) { + // Check whether visible background users are enabled. + // Visible background users are non current but can have UI access. + // The main use case for visible background users is the passenger in Automotive's + // Multi-Display configuration. + if (!UserManager.isVisibleBackgroundUsersEnabled()) { + return true; + } + + if (userId == UserHandle.USER_SYSTEM || userId == mCurrentUser) { + return true; + } + + final long ident = Binder.clearCallingIdentity(); + try { + if (mUserManager.isSameProfileGroup(userId, mCurrentUser)) { + return true; + } + } finally { + Binder.restoreCallingIdentity(ident); + } + + return false; + } + /** * Enforces the caller contains the necessary permission to change the state of sensor * privacy. diff --git a/services/core/jni/com_android_server_hint_HintManagerService.cpp b/services/core/jni/com_android_server_hint_HintManagerService.cpp index 2307aced6141..febfb9ff1def 100644 --- a/services/core/jni/com_android_server_hint_HintManagerService.cpp +++ b/services/core/jni/com_android_server_hint_HintManagerService.cpp @@ -109,7 +109,7 @@ static jlong createHintSessionWithConfig(JNIEnv* env, int32_t tgid, int32_t uid, return session_ptr; } else if (result.isUnsupported()) { throwUnsupported(env, result.errorMessage()); - return -1; + return 0; } throwFailed(env, result.errorMessage()); return 0; @@ -190,7 +190,7 @@ static jlong nativeCreateHintSessionWithConfig(JNIEnv* env, jclass /* clazz */, hal::SessionConfig config; jlong out = createHintSessionWithConfig(env, tgid, uid, std::move(threadIds), durationNanos, sessionTag, config); - if (out <= 0) { + if (out == 0) { return out; } static jclass configClass = env->FindClass("android/hardware/power/SessionConfig"); diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp index 75db31679a88..b46a6fffbaa9 100644 --- a/services/tests/PackageManagerServiceTests/host/Android.bp +++ b/services/tests/PackageManagerServiceTests/host/Android.bp @@ -95,3 +95,10 @@ test_module_config_host { test_suites: ["device-tests"], include_filters: ["com.android.server.pm.test.OverlayActorVisibilityTest"], } + +test_module_config_host { + name: "PackageManagerServiceHostTests_android_server_pm_Presubmit", + base: "PackageManagerServiceHostTests", + test_suites: ["device-tests"], + include_annotations: ["android.platform.test.annotations.Presubmit"], +} diff --git a/services/tests/PackageManagerServiceTests/server/Android.bp b/services/tests/PackageManagerServiceTests/server/Android.bp index 24e931c3cbb3..f5b0015aff94 100644 --- a/services/tests/PackageManagerServiceTests/server/Android.bp +++ b/services/tests/PackageManagerServiceTests/server/Android.bp @@ -186,3 +186,13 @@ test_module_config { include_filters: ["com.android.server.pm."], include_annotations: ["android.platform.test.annotations.Postsubmit"], } + +test_module_config { + name: "PackageManagerServiceServerTests_Presubmit", + base: "PackageManagerServiceServerTests", + test_suites: [ + "automotive-tests", + "device-tests", + ], + include_annotations: ["android.platform.test.annotations.Presubmit"], +} diff --git a/services/tests/VpnTests/Android.bp b/services/tests/VpnTests/Android.bp index ee20f1a105a4..0568892c3684 100644 --- a/services/tests/VpnTests/Android.bp +++ b/services/tests/VpnTests/Android.bp @@ -43,3 +43,10 @@ android_test { "android.test.mock.stubs", ], } + +test_module_config { + name: "FrameworksVpnTests_android_server_connectivity", + base: "FrameworksVpnTests", + test_suites: ["device-tests"], + exclude_annotations: ["com.android.testutils.SkipPresubmit"], +} diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp index 6fc80b836521..c81d6be43223 100644 --- a/services/tests/mockingservicestests/Android.bp +++ b/services/tests/mockingservicestests/Android.bp @@ -391,3 +391,13 @@ test_module_config { ], include_filters: ["com.android.server.trust"], } + +test_module_config { + name: "FrameworksMockingServicesTests_server_storagemanagerservicetest", + base: "FrameworksMockingServicesTests", + test_suites: [ + "automotive-tests", + "device-tests", + ], + include_filters: ["com.android.server.StorageManagerServiceTest"], +} diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java index b2ca991a4aa8..639ae30c00b9 100644 --- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java +++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java @@ -48,7 +48,9 @@ import android.app.ActivityManagerInternal; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.hardware.common.fmq.MQDescriptor; import android.hardware.power.ChannelConfig; +import android.hardware.power.ChannelMessage; import android.hardware.power.IPower; import android.hardware.power.SessionConfig; import android.hardware.power.SessionTag; @@ -167,6 +169,8 @@ public class HintManagerServiceTest { mConfig = new ChannelConfig(); mConfig.readFlagBitmask = 1; mConfig.writeFlagBitmask = 2; + mConfig.channelDescriptor = new MQDescriptor<ChannelMessage, Byte>(); + mConfig.eventFlagDescriptor = new MQDescriptor<Byte, Byte>(); ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.category = ApplicationInfo.CATEGORY_GAME; when(mContext.getPackageManager()).thenReturn(mMockPackageManager); diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index 895cd1e44ca8..e55e0f27dfb4 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -278,14 +278,22 @@ java_genrule { test_module_config { name: "FrameworksServicesTests_contentprotection", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.contentprotection"], } test_module_config { name: "FrameworksServicesTests_om", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.om."], } @@ -293,7 +301,11 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_contexthub_presubmit", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.location.contexthub."], // TODO(ron): are these right, does it run anything? include_annotations: ["android.platform.test.annotations.Presubmit"], @@ -302,7 +314,11 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_contexthub_postsubmit", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.location.contexthub."], // TODO(ron): are these right, does it run anything? include_annotations: ["android.platform.test.annotations.Postsubmit"], @@ -312,14 +328,22 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_contentcapture", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.contentcapture"], } test_module_config { name: "FrameworksServicesTests_recoverysystem", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.recoverysystem."], } @@ -327,7 +351,11 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_pm_presubmit", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_annotations: ["android.platform.test.annotations.Presubmit"], include_filters: ["com.android.server.pm."], } @@ -335,7 +363,11 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_pm_postsubmit", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_annotations: ["android.platform.test.annotations.Postsubmit"], include_filters: ["com.android.server.pm."], } @@ -344,21 +376,33 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_os", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.os."], } test_module_config { name: "FrameworksServicesTests_presubmit", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_annotations: ["android.platform.test.annotations.Presubmit"], } test_module_config { name: "FrameworksServicesTests_com_android_server_job_Presubmit", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.job"], exclude_annotations: [ "androidx.test.filters.LargeTest", @@ -369,49 +413,77 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_com_android_server_job", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.job"], } test_module_config { name: "FrameworksServicesTests_com_android_server_tare", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.tare"], } test_module_config { name: "FrameworksServicesTests_com_android_server_usage", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.usage"], } test_module_config { name: "FrameworksServicesTests_battery_stats", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.am.BatteryStatsServiceTest"], } test_module_config { name: "FrameworksServicesTests_accessibility", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.accessibility"], } test_module_config { name: "FrameworksServicesTests_binary_transparency", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.BinaryTransparencyServiceTest"], } test_module_config { name: "FrameworksServicesTests_pinner_service", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.PinnerServiceTest"], exclude_annotations: ["org.junit.Ignore"], } @@ -419,7 +491,11 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_android_server_am_Presubmit", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.am."], include_annotations: ["android.platform.test.annotations.Presubmit"], } @@ -427,21 +503,33 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_android_server_am", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.am."], } test_module_config { name: "FrameworksServicesTests_android_server_appop", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.appop"], } test_module_config { name: "FrameworksServicesTests_android_server_audio", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.audio"], include_annotations: ["android.platform.test.annotations.Presubmit"], } @@ -449,14 +537,22 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_android_server_compat", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.compat"], } test_module_config { name: "FrameworksServicesTests_android_server_hdmi_Presubmit", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.hdmi"], include_annotations: ["android.platform.test.annotations.Presubmit"], } @@ -464,35 +560,55 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_android_server_hdmi", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.hdmi"], } test_module_config { name: "FrameworksServicesTests_android_server_integrity", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.integrity."], } test_module_config { name: "FrameworksServicesTests_android_server_lights", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.lights"], } test_module_config { name: "FrameworksServicesTests_android_server_locales", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.locales."], } test_module_config { name: "FrameworksServicesTests_android_server_location_contexthub_Presubmit", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.location.contexthub."], include_annotations: ["android.platform.test.annotations.Presubmit"], } @@ -500,21 +616,33 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_android_server_locksettings", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.locksettings."], } test_module_config { name: "FrameworksServicesTests_android_server_logcat", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.logcat"], } test_module_config { name: "FrameworksServicesTests_android_server_net_Presubmit", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.net."], include_annotations: ["android.platform.test.annotations.Presubmit"], } @@ -522,28 +650,44 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_android_server_om", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.om."], } test_module_config { name: "FrameworksServicesTests_android_server_pdb", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.pdb.PersistentDataBlockServiceTest"], } test_module_config { name: "FrameworksServicesTests_android_server_pm_dex", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.pm.dex"], } test_module_config { name: "FrameworksServicesTests_android_server_policy_Presubmit", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.policy."], include_annotations: ["android.platform.test.annotations.Presubmit"], } @@ -551,49 +695,77 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_android_server_policy", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.policy."], } test_module_config { name: "FrameworksServicesTests_android_server_power", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.power"], } test_module_config { name: "FrameworksServicesTests_android_server_power_hint", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.power.hint"], } test_module_config { name: "FrameworksServicesTests_android_server_powerstats", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.powerstats"], } test_module_config { name: "FrameworksServicesTests_android_server_rollback", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.rollback"], } test_module_config { name: "FrameworksServicesTests_android_server_uri", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.uri."], } test_module_config { name: "FrameworksServicesTests_com_android_server_location_contexthub", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.location.contexthub."], include_annotations: ["android.platform.test.annotations.Postsubmit"], } @@ -601,7 +773,11 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_android_server_usage", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.usage"], exclude_filters: ["com.android.server.usage.StorageStatsServiceTest"], } @@ -609,14 +785,22 @@ test_module_config { test_module_config { name: "FrameworksServicesTests_android_server_soundtrigger_middleware", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.soundtrigger_middleware"], } test_module_config { name: "FrameworksServicesTests_android_server_input", base: "FrameworksServicesTests", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "automotive-tests", + ], + include_filters: ["com.android.server.input"], } @@ -792,3 +976,23 @@ test_module_config { ], include_filters: ["com.android.server.input"], } + +test_module_config { + name: "FrameworksServicesTests_people_data", + base: "FrameworksServicesTests", + test_suites: [ + "automotive-tests", + "device-tests", + ], + include_filters: ["com.android.server.people.data"], +} + +test_module_config { + name: "FrameworksServicesTests_Presubmit", + base: "FrameworksServicesTests", + test_suites: [ + "automotive-tests", + "device-tests", + ], + include_annotations: ["android.platform.test.annotations.Presubmit"], +} diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp index 850d2f7f36a5..a63a38da3740 100644 --- a/services/tests/uiservicestests/Android.bp +++ b/services/tests/uiservicestests/Android.bp @@ -92,3 +92,13 @@ android_test { // Required for TestParameterInjector javacflags: ["-parameters"], } + +test_module_config { + name: "FrameworksUiServicesTests_notification", + base: "FrameworksUiServicesTests", + test_suites: [ + "automotive-tests", + "device-tests", + ], + exclude_annotations: ["androidx.test.filters.LargeTest"], +} diff --git a/tests/permission/Android.bp b/tests/permission/Android.bp index d80eaeb32c1e..1a08f998442d 100644 --- a/tests/permission/Android.bp +++ b/tests/permission/Android.bp @@ -25,3 +25,10 @@ android_test { platform_apis: true, test_suites: ["device-tests"], } + +test_module_config { + name: "FrameworkPermissionTests_Presubmit", + base: "FrameworkPermissionTests", + test_suites: ["device-tests"], + include_annotations: ["android.platform.test.annotations.Presubmit"], +} |