diff options
9 files changed, 363 insertions, 111 deletions
diff --git a/core/java/Android.bp b/core/java/Android.bp index eba500dd32b4..34b8a878b3d1 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -126,6 +126,7 @@ filegroup { srcs: [ "android/os/IExternalVibrationController.aidl", "android/os/IExternalVibratorService.aidl", + "android/os/ExternalVibrationScale.aidl", ], } diff --git a/core/java/android/os/ExternalVibrationScale.aidl b/core/java/android/os/ExternalVibrationScale.aidl new file mode 100644 index 000000000000..cf6f8ed52f7d --- /dev/null +++ b/core/java/android/os/ExternalVibrationScale.aidl @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2018, 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; + +/** + * ExternalVibrationScale holds the vibration scale level and adaptive haptics scale. These + * can be used to scale external vibrations. + * + * @hide + */ +parcelable ExternalVibrationScale { + @Backing(type="int") + enum ScaleLevel { + SCALE_MUTE = -100, + SCALE_VERY_LOW = -2, + SCALE_LOW = -1, + SCALE_NONE = 0, + SCALE_HIGH = 1, + SCALE_VERY_HIGH = 2 + } + + /** + * The scale level that will be applied to external vibrations. + */ + ScaleLevel scaleLevel = ScaleLevel.SCALE_NONE; + + /** + * The adaptive haptics scale that will be applied to external vibrations. + */ + float adaptiveHapticsScale = 1f; +} diff --git a/core/java/android/os/IExternalVibratorService.aidl b/core/java/android/os/IExternalVibratorService.aidl index 666171fcbcb3..a9df15a088bf 100644 --- a/core/java/android/os/IExternalVibratorService.aidl +++ b/core/java/android/os/IExternalVibratorService.aidl @@ -17,6 +17,7 @@ package android.os; import android.os.ExternalVibration; +import android.os.ExternalVibrationScale; /** * The communication channel by which an external system that wants to control the system @@ -32,29 +33,24 @@ import android.os.ExternalVibration; * {@hide} */ interface IExternalVibratorService { - const int SCALE_MUTE = -100; - const int SCALE_VERY_LOW = -2; - const int SCALE_LOW = -1; - const int SCALE_NONE = 0; - const int SCALE_HIGH = 1; - const int SCALE_VERY_HIGH = 2; - /** * A method called by the external system to start a vibration. * - * If this returns {@code SCALE_MUTE}, then the vibration should <em>not</em> play. If this - * returns any other scale level, then any currently playing vibration controlled by the - * requesting system must be muted and this vibration can begin playback. + * This returns an {@link ExternalVibrationScale} which includes the vibration scale level and + * the adaptive haptics scale. + * + * If the returned scale level is {@link ExternalVibrationScale.ScaleLevel#SCALE_MUTE}, then + * the vibration should <em>not</em> play. If it returns any other scale level, then + * any currently playing vibration controlled by the requesting system must be muted and this + * vibration can begin playback. * * Note that the IExternalVibratorService implementation will not call mute on any currently * playing external vibrations in order to avoid re-entrancy with the system on the other side. * - * @param vibration An ExternalVibration - * - * @return {@code SCALE_MUTE} if the external vibration should not play, and any other scale - * level if it should. + * @param vib The external vibration starting. + * @return {@link ExternalVibrationScale} including scale level and adaptive haptics scale. */ - int onExternalVibrationStart(in ExternalVibration vib); + ExternalVibrationScale onExternalVibrationStart(in ExternalVibration vib); /** * A method called by the external system when a vibration no longer wants to play. diff --git a/services/core/java/com/android/server/vibrator/VibrationScaler.java b/services/core/java/com/android/server/vibrator/VibrationScaler.java index 7163319f281a..5d17884c769b 100644 --- a/services/core/java/com/android/server/vibrator/VibrationScaler.java +++ b/services/core/java/com/android/server/vibrator/VibrationScaler.java @@ -19,7 +19,7 @@ package com.android.server.vibrator; import android.annotation.NonNull; import android.content.Context; import android.hardware.vibrator.V1_0.EffectStrength; -import android.os.IExternalVibratorService; +import android.os.ExternalVibrationScale; import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.os.Vibrator; @@ -37,11 +37,13 @@ final class VibrationScaler { // Scale levels. Each level, except MUTE, is defined as the delta between the current setting // and the default intensity for that type of vibration (i.e. current - default). - private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2 - private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1 - private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0 - private static final int SCALE_HIGH = IExternalVibratorService.SCALE_HIGH; // 1 - private static final int SCALE_VERY_HIGH = IExternalVibratorService.SCALE_VERY_HIGH; // 2 + private static final int SCALE_VERY_LOW = + ExternalVibrationScale.ScaleLevel.SCALE_VERY_LOW; // -2 + private static final int SCALE_LOW = ExternalVibrationScale.ScaleLevel.SCALE_LOW; // -1 + private static final int SCALE_NONE = ExternalVibrationScale.ScaleLevel.SCALE_NONE; // 0 + private static final int SCALE_HIGH = ExternalVibrationScale.ScaleLevel.SCALE_HIGH; // 1 + private static final int SCALE_VERY_HIGH = + ExternalVibrationScale.ScaleLevel.SCALE_VERY_HIGH; // 2 // Scale factors for each level. private static final float SCALE_FACTOR_VERY_LOW = 0.6f; @@ -83,9 +85,9 @@ final class VibrationScaler { * Calculates the scale to be applied to external vibration with given usage. * * @param usageHint one of VibrationAttributes.USAGE_* - * @return one of IExternalVibratorService.SCALE_* + * @return one of ExternalVibrationScale.ScaleLevel.SCALE_* */ - public int getExternalVibrationScale(int usageHint) { + public int getExternalVibrationScaleLevel(int usageHint) { int defaultIntensity = mSettingsController.getDefaultIntensity(usageHint); int currentIntensity = mSettingsController.getCurrentIntensity(usageHint); @@ -107,6 +109,22 @@ final class VibrationScaler { } /** + * Returns the adaptive haptics scale that should be applied to the vibrations with + * the given usage. When no adaptive scales are available for the usages, then returns 1 + * indicating no scaling will be applied + * + * @param usageHint one of VibrationAttributes.USAGE_* + * @return The adaptive haptics scale. + */ + public float getAdaptiveHapticsScale(int usageHint) { + if (shouldApplyAdaptiveHapticsScale(usageHint)) { + return mAdaptiveHapticsScales.get(usageHint); + } + + return 1f; // no scaling + } + + /** * Scale a {@link VibrationEffect} based on the given usage hint for this vibration. * * @param effect the effect to be scaled @@ -152,9 +170,7 @@ final class VibrationScaler { } // If adaptive haptics scaling is available for this usage, apply it to the segment. - if (Flags.adaptiveHapticsEnabled() - && mAdaptiveHapticsScales.size() > 0 - && mAdaptiveHapticsScales.contains(usageHint)) { + if (shouldApplyAdaptiveHapticsScale(usageHint)) { float adaptiveScale = mAdaptiveHapticsScales.get(usageHint); segment = segment.scaleLinearly(adaptiveScale); } @@ -224,6 +240,10 @@ final class VibrationScaler { mAdaptiveHapticsScales.clear(); } + private boolean shouldApplyAdaptiveHapticsScale(int usageHint) { + return Flags.adaptiveHapticsEnabled() && mAdaptiveHapticsScales.contains(usageHint); + } + /** Mapping of Vibrator.VIBRATION_INTENSITY_* values to {@link EffectStrength}. */ private static int intensityToEffectStrength(int intensity) { switch (intensity) { diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java index be5d15877e32..78e0ebbb53fa 100644 --- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java +++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java @@ -16,6 +16,7 @@ package com.android.server.vibrator; +import static android.os.ExternalVibrationScale.ScaleLevel.SCALE_MUTE; import static android.os.VibrationEffect.VibrationParameter.targetAmplitude; import static android.os.VibrationEffect.VibrationParameter.targetFrequency; @@ -35,6 +36,7 @@ import android.os.Binder; import android.os.Build; import android.os.CombinedVibration; import android.os.ExternalVibration; +import android.os.ExternalVibrationScale; import android.os.Handler; import android.os.IBinder; import android.os.IExternalVibratorService; @@ -277,7 +279,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { context.registerReceiver(mIntentReceiver, filter, Context.RECEIVER_NOT_EXPORTED); injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService()); - if (ServiceManager.isDeclared(VIBRATOR_CONTROL_SERVICE)) { + if (injector.isServiceDeclared(VIBRATOR_CONTROL_SERVICE)) { injector.addService(VIBRATOR_CONTROL_SERVICE, mVibratorControlService); } @@ -1427,6 +1429,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { VibratorControllerHolder createVibratorControllerHolder() { return new VibratorControllerHolder(); } + + boolean isServiceDeclared(String name) { + return ServiceManager.isDeclared(name); + } } /** @@ -1594,7 +1600,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { IBinder.DeathRecipient { public final ExternalVibration externalVibration; - public int scale; + public ExternalVibrationScale scale = new ExternalVibrationScale(); private Vibration.Status mStatus; @@ -1605,7 +1611,6 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { // instead of using DEVICE_ID_INVALID here and relying on the UID checks. Context.DEVICE_ID_INVALID, externalVibration.getPackage(), null)); this.externalVibration = externalVibration; - this.scale = IExternalVibratorService.SCALE_NONE; mStatus = Vibration.Status.RUNNING; } @@ -1658,7 +1663,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { public Vibration.DebugInfo getDebugInfo() { return new Vibration.DebugInfo(mStatus, stats, /* playedEffect= */ null, - /* originalEffect= */ null, scale, callerInfo); + /* originalEffect= */ null, scale.scaleLevel, callerInfo); } public VibrationStats.StatsInfo getStatsInfo(long completionUptimeMillis) { @@ -1988,11 +1993,17 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { /** Implementation of {@link IExternalVibratorService} to be triggered on external control. */ @VisibleForTesting final class ExternalVibratorService extends IExternalVibratorService.Stub { + private static final ExternalVibrationScale SCALE_MUTE = new ExternalVibrationScale(); + + static { + SCALE_MUTE.scaleLevel = ExternalVibrationScale.ScaleLevel.SCALE_MUTE; + } @Override - public int onExternalVibrationStart(ExternalVibration vib) { + public ExternalVibrationScale onExternalVibrationStart(ExternalVibration vib) { + if (!hasExternalControlCapability()) { - return IExternalVibratorService.SCALE_MUTE; + return SCALE_MUTE; } if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE, vib.getUid(), -1 /*owningUid*/, true /*exported*/) @@ -2000,7 +2011,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid() + " tried to play externally controlled vibration" + " without VIBRATE permission, ignoring."); - return IExternalVibratorService.SCALE_MUTE; + return SCALE_MUTE; } // Create Vibration.Stats as close to the received request as possible, for tracking. @@ -2033,7 +2044,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { } if (vibrationEndInfo != null) { - vibHolder.scale = IExternalVibratorService.SCALE_MUTE; + vibHolder.scale = SCALE_MUTE; // Failed to start the vibration, end it and report metrics right away. endVibrationAndWriteStatsLocked(vibHolder, vibrationEndInfo); return vibHolder.scale; @@ -2074,7 +2085,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { } mCurrentExternalVibration = vibHolder; vibHolder.linkToDeath(); - vibHolder.scale = mVibrationScaler.getExternalVibrationScale(attrs.getUsage()); + vibHolder.scale.scaleLevel = mVibrationScaler.getExternalVibrationScaleLevel( + attrs.getUsage()); + vibHolder.scale.adaptiveHapticsScale = mVibrationScaler.getAdaptiveHapticsScale( + attrs.getUsage()); } if (waitForCompletion) { @@ -2086,7 +2100,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { new Vibration.EndInfo(Vibration.Status.IGNORED_ERROR_CANCELLING), /* continueExternalControl= */ false); } - return IExternalVibratorService.SCALE_MUTE; + return SCALE_MUTE; } } if (!alreadyUnderExternalControl) { diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java index b431888a72fb..3e59878f9e1e 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java @@ -35,8 +35,8 @@ import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContextWrapper; import android.content.pm.PackageManagerInternal; +import android.os.ExternalVibrationScale; import android.os.Handler; -import android.os.IExternalVibratorService; import android.os.PowerManagerInternal; import android.os.UserHandle; import android.os.VibrationAttributes; @@ -49,6 +49,7 @@ import android.os.vibrator.PrimitiveSegment; import android.os.vibrator.StepSegment; import android.os.vibrator.VibrationConfig; import android.os.vibrator.VibrationEffectSegment; +import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; @@ -119,29 +120,65 @@ public class VibrationScalerTest { public void testGetExternalVibrationScale() { setDefaultIntensity(USAGE_TOUCH, Vibrator.VIBRATION_INTENSITY_LOW); setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH); - assertEquals(IExternalVibratorService.SCALE_VERY_HIGH, - mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH)); + assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_VERY_HIGH, + mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH)); setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_MEDIUM); - assertEquals(IExternalVibratorService.SCALE_HIGH, - mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH)); + assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_HIGH, + mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH)); setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_LOW); - assertEquals(IExternalVibratorService.SCALE_NONE, - mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH)); + assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_NONE, + mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH)); setDefaultIntensity(USAGE_TOUCH, VIBRATION_INTENSITY_MEDIUM); - assertEquals(IExternalVibratorService.SCALE_LOW, - mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH)); + assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_LOW, + mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH)); setDefaultIntensity(USAGE_TOUCH, VIBRATION_INTENSITY_HIGH); - assertEquals(IExternalVibratorService.SCALE_VERY_LOW, - mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH)); + assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_VERY_LOW, + mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH)); setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF); // Vibration setting being bypassed will use default setting and not scale. - assertEquals(IExternalVibratorService.SCALE_NONE, - mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH)); + assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_NONE, + mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH)); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ADAPTIVE_HAPTICS_ENABLED) + public void testAdaptiveHapticsScale_withAdaptiveHapticsAvailable() { + setDefaultIntensity(USAGE_TOUCH, Vibrator.VIBRATION_INTENSITY_LOW); + setDefaultIntensity(USAGE_RINGTONE, Vibrator.VIBRATION_INTENSITY_LOW); + setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH); + setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_HIGH); + + mVibrationScaler.updateAdaptiveHapticsScale(USAGE_TOUCH, 0.5f); + mVibrationScaler.updateAdaptiveHapticsScale(USAGE_RINGTONE, 0.2f); + + assertEquals(0.5f, mVibrationScaler.getAdaptiveHapticsScale(USAGE_TOUCH)); + assertEquals(0.2f, mVibrationScaler.getAdaptiveHapticsScale(USAGE_RINGTONE)); + assertEquals(1f, mVibrationScaler.getAdaptiveHapticsScale(USAGE_NOTIFICATION)); + + setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF); + // Vibration setting being bypassed will apply adaptive haptics scales. + assertEquals(0.2f, mVibrationScaler.getAdaptiveHapticsScale(USAGE_RINGTONE)); + } + + @Test + @RequiresFlagsDisabled(Flags.FLAG_ADAPTIVE_HAPTICS_ENABLED) + public void testAdaptiveHapticsScale_flagDisabled_adaptiveHapticScaleAlwaysNone() { + setDefaultIntensity(USAGE_TOUCH, Vibrator.VIBRATION_INTENSITY_LOW); + setDefaultIntensity(USAGE_RINGTONE, Vibrator.VIBRATION_INTENSITY_LOW); + setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH); + setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_HIGH); + + mVibrationScaler.updateAdaptiveHapticsScale(USAGE_TOUCH, 0.5f); + mVibrationScaler.updateAdaptiveHapticsScale(USAGE_RINGTONE, 0.2f); + + assertEquals(1f, mVibrationScaler.getAdaptiveHapticsScale(USAGE_TOUCH)); + assertEquals(1f, mVibrationScaler.getAdaptiveHapticsScale(USAGE_RINGTONE)); + assertEquals(1f, mVibrationScaler.getAdaptiveHapticsScale(USAGE_NOTIFICATION)); } @Test diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java index 2823223e4859..417fbd06be66 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2023 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. @@ -35,7 +35,6 @@ import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.pm.PackageManagerInternal; import android.frameworks.vibrator.ScaleParam; -import android.frameworks.vibrator.VibrationParam; import android.os.Binder; import android.os.Handler; import android.os.IBinder; @@ -55,8 +54,6 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -135,7 +132,7 @@ public class VibratorControlServiceTest { vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f); mVibratorControlService.onRequestVibrationParamsComplete(token, - generateVibrationParams(vibrationScales)); + VibrationParamGenerator.generateVibrationParams(vibrationScales)); verify(mMockVibrationScaler).updateAdaptiveHapticsScale(USAGE_ALARM, 0.7f); verify(mMockVibrationScaler).updateAdaptiveHapticsScale(USAGE_NOTIFICATION, 0.4f); @@ -162,7 +159,7 @@ public class VibratorControlServiceTest { vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f); mVibratorControlService.onRequestVibrationParamsComplete(new Binder(), - generateVibrationParams(vibrationScales)); + VibrationParamGenerator.generateVibrationParams(vibrationScales)); verifyZeroInteractions(mMockVibrationScaler); } @@ -175,7 +172,8 @@ public class VibratorControlServiceTest { vibrationScales.put(ScaleParam.TYPE_ALARM, 0.7f); vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f); - mVibratorControlService.setVibrationParams(generateVibrationParams(vibrationScales), + mVibratorControlService.setVibrationParams( + VibrationParamGenerator.generateVibrationParams(vibrationScales), mFakeVibratorController); verify(mMockVibrationScaler).updateAdaptiveHapticsScale(USAGE_ALARM, 0.7f); @@ -193,7 +191,8 @@ public class VibratorControlServiceTest { vibrationScales.put(ScaleParam.TYPE_ALARM, 0.7f); vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f); - mVibratorControlService.setVibrationParams(generateVibrationParams(vibrationScales), + mVibratorControlService.setVibrationParams( + VibrationParamGenerator.generateVibrationParams(vibrationScales), mFakeVibratorController); verifyZeroInteractions(mMockVibrationScaler); @@ -268,28 +267,6 @@ public class VibratorControlServiceTest { } } - private VibrationParam[] generateVibrationParams(SparseArray<Float> vibrationScales) { - List<VibrationParam> vibrationParamList = new ArrayList<>(); - for (int i = 0; i < vibrationScales.size(); i++) { - int type = vibrationScales.keyAt(i); - float scale = vibrationScales.valueAt(i); - - vibrationParamList.add(generateVibrationParam(type, scale)); - } - - return vibrationParamList.toArray(new VibrationParam[0]); - } - - private VibrationParam generateVibrationParam(int type, float scale) { - ScaleParam scaleParam = new ScaleParam(); - scaleParam.typesMask = type; - scaleParam.scale = scale; - VibrationParam vibrationParam = new VibrationParam(); - vibrationParam.setScale(scaleParam); - - return vibrationParam; - } - private int buildVibrationTypesMask(int... types) { int typesMask = 0; for (int type : types) { diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java index e7571ef47864..ed89ccf07453 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -50,6 +50,7 @@ import android.content.ContextWrapper; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.res.Resources; +import android.frameworks.vibrator.ScaleParam; import android.hardware.input.IInputManager; import android.hardware.input.InputManager; import android.hardware.input.InputManagerGlobal; @@ -59,16 +60,17 @@ import android.media.AudioAttributes; import android.media.AudioManager; import android.os.CombinedVibration; import android.os.ExternalVibration; +import android.os.ExternalVibrationScale; import android.os.Handler; import android.os.IBinder; import android.os.IExternalVibrationController; -import android.os.IExternalVibratorService; import android.os.IVibratorStateListener; import android.os.Looper; import android.os.PowerManager; import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.Process; +import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.os.VibrationAttributes; @@ -82,6 +84,10 @@ import android.os.vibrator.PrimitiveSegment; import android.os.vibrator.StepSegment; import android.os.vibrator.VibrationConfig; import android.os.vibrator.VibrationEffectSegment; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.util.SparseArray; @@ -153,6 +159,8 @@ public class VibratorManagerServiceTest { public MockitoRule rule = MockitoJUnit.rule(); @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -185,8 +193,10 @@ public class VibratorManagerServiceTest { private Context mContextSpy; private TestLooper mTestLooper; private FakeVibrator mVibrator; + private FakeVibratorController mFakeVibratorController; private PowerManagerInternal.LowPowerModeListener mRegisteredPowerModeListener; private VibratorManagerService.ExternalVibratorService mExternalVibratorService; + private VibratorControlService mVibratorControlService; private VibrationConfig mVibrationConfig; private InputManagerGlobal.TestSession mInputManagerGlobalSession; private InputManager mInputManager; @@ -197,6 +207,7 @@ public class VibratorManagerServiceTest { mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); mInputManagerGlobalSession = InputManagerGlobal.createTestSession(mIInputManagerMock); mVibrationConfig = new VibrationConfig(mContextSpy.getResources()); + mFakeVibratorController = new FakeVibratorController(); ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy); when(mContextSpy.getContentResolver()).thenReturn(contentResolver); @@ -310,6 +321,8 @@ public class VibratorManagerServiceTest { if (service instanceof VibratorManagerService.ExternalVibratorService) { mExternalVibratorService = (VibratorManagerService.ExternalVibratorService) service; + } else if (service instanceof VibratorControlService) { + mVibratorControlService = (VibratorControlService) service; } } @@ -321,9 +334,13 @@ public class VibratorManagerServiceTest { VibratorControllerHolder createVibratorControllerHolder() { VibratorControllerHolder holder = new VibratorControllerHolder(); - holder.setVibratorController(new FakeVibratorController()); + holder.setVibratorController(mFakeVibratorController); return holder; } + + boolean isServiceDeclared(String name) { + return true; + } }); return mService; } @@ -1108,12 +1125,13 @@ public class VibratorManagerServiceTest { ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ALARM_ATTRS, controller, firstToken); - int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); + ExternalVibrationScale scale = + mExternalVibratorService.onExternalVibrationStart(externalVibration); vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), RINGTONE_ATTRS); - assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale); + assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); // The external vibration should have been cancelled verify(controller).mute(); assertEquals(Arrays.asList(false, true, false), @@ -1708,13 +1726,14 @@ public class VibratorManagerServiceTest { ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ALARM_ATTRS, mock(IExternalVibrationController.class), binderToken); - int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); - assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale); + ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart( + externalVibration); + assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); when(mVirtualDeviceManagerInternalMock.isAppRunningOnAnyVirtualDevice(UID)) .thenReturn(true); scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); - assertEquals(IExternalVibratorService.SCALE_MUTE, scale); + assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); } @Test @@ -1727,10 +1746,11 @@ public class VibratorManagerServiceTest { ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ALARM_ATTRS, mock(IExternalVibrationController.class), binderToken); - int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); + ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart( + externalVibration); mExternalVibratorService.onExternalVibrationStop(externalVibration); - assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale); + assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); assertEquals(Arrays.asList(false, true, false), mVibratorProviders.get(1).getExternalControlStates()); @@ -1753,17 +1773,19 @@ public class VibratorManagerServiceTest { ExternalVibration firstVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ALARM_ATTRS, firstController, firstToken); - int firstScale = mExternalVibratorService.onExternalVibrationStart(firstVibration); + ExternalVibrationScale firstScale = + mExternalVibratorService.onExternalVibrationStart(firstVibration); AudioAttributes ringtoneAudioAttrs = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) .build(); ExternalVibration secondVibration = new ExternalVibration(UID, PACKAGE_NAME, ringtoneAudioAttrs, secondController, secondToken); - int secondScale = mExternalVibratorService.onExternalVibrationStart(secondVibration); + ExternalVibrationScale secondScale = + mExternalVibratorService.onExternalVibrationStart(secondVibration); - assertNotEquals(IExternalVibratorService.SCALE_MUTE, firstScale); - assertNotEquals(IExternalVibratorService.SCALE_MUTE, secondScale); + assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, firstScale.scaleLevel); + assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, secondScale.scaleLevel); verify(firstController).mute(); verify(secondController, never()).mute(); // Set external control called only once. @@ -1799,8 +1821,9 @@ public class VibratorManagerServiceTest { ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ALARM_ATTRS, mock(IExternalVibrationController.class)); - int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); - assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale); + ExternalVibrationScale scale = + mExternalVibratorService.onExternalVibrationStart(externalVibration); + assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); // Vibration is cancelled. assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); @@ -1825,9 +1848,10 @@ public class VibratorManagerServiceTest { ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ALARM_ATTRS, mock(IExternalVibrationController.class)); - int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); + ExternalVibrationScale scale = + mExternalVibratorService.onExternalVibrationStart(externalVibration); // External vibration is ignored. - assertEquals(IExternalVibratorService.SCALE_MUTE, scale); + assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); // Vibration is not cancelled. assertFalse(waitUntil(s -> !s.isVibrating(1), service, CLEANUP_TIMEOUT_MILLIS)); @@ -1852,8 +1876,9 @@ public class VibratorManagerServiceTest { ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ALARM_ATTRS, mock(IExternalVibrationController.class)); - int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); - assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale); + ExternalVibrationScale scale = + mExternalVibratorService.onExternalVibrationStart(externalVibration); + assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); // Vibration is cancelled. assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); @@ -1879,9 +1904,10 @@ public class VibratorManagerServiceTest { ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_NOTIFICATION_ATTRS, mock(IExternalVibrationController.class)); - int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); + ExternalVibrationScale scale = + mExternalVibratorService.onExternalVibrationStart(externalVibration); // New vibration is ignored. - assertEquals(IExternalVibratorService.SCALE_MUTE, scale); + assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); // Vibration is not cancelled. assertFalse(waitUntil(s -> !s.isVibrating(1), service, CLEANUP_TIMEOUT_MILLIS)); @@ -1901,18 +1927,19 @@ public class VibratorManagerServiceTest { setRingerMode(AudioManager.RINGER_MODE_SILENT); createSystemReadyService(); - int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); - assertEquals(IExternalVibratorService.SCALE_MUTE, scale); + ExternalVibrationScale scale = + mExternalVibratorService.onExternalVibrationStart(externalVibration); + assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); setRingerMode(AudioManager.RINGER_MODE_NORMAL); createSystemReadyService(); scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); - assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale); + assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); setRingerMode(AudioManager.RINGER_MODE_VIBRATE); createSystemReadyService(); scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); - assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale); + assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); } @Test @@ -1935,14 +1962,14 @@ public class VibratorManagerServiceTest { ExternalVibration vib = new ExternalVibration(UID, PACKAGE_NAME, audioAttrs, mock(IExternalVibrationController.class)); - int scale = mExternalVibratorService.onExternalVibrationStart(vib); - assertEquals(IExternalVibratorService.SCALE_MUTE, scale); + ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart(vib); + assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); mExternalVibratorService.onExternalVibrationStop(vib); scale = mExternalVibratorService.onExternalVibrationStart( new ExternalVibration(UID, PACKAGE_NAME, flaggedAudioAttrs, mock(IExternalVibrationController.class))); - assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale); + assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); } @Test @@ -1956,10 +1983,91 @@ public class VibratorManagerServiceTest { .build(); createSystemReadyService(); - int scale = mExternalVibratorService.onExternalVibrationStart( - new ExternalVibration(/* uid= */ 123, PACKAGE_NAME, flaggedAudioAttrs, - mock(IExternalVibrationController.class))); - assertEquals(IExternalVibratorService.SCALE_MUTE, scale); + ExternalVibrationScale scale = + mExternalVibratorService.onExternalVibrationStart( + new ExternalVibration(/* uid= */ 123, PACKAGE_NAME, flaggedAudioAttrs, + mock(IExternalVibrationController.class))); + assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); + } + + @Test + @RequiresFlagsEnabled(android.os.vibrator.Flags.FLAG_ADAPTIVE_HAPTICS_ENABLED) + public void onExternalVibration_withAdaptiveHaptics_returnsCorrectAdaptiveScales() + throws RemoteException { + mockVibrators(1); + mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL, + IVibrator.CAP_AMPLITUDE_CONTROL); + createSystemReadyService(); + + SparseArray<Float> vibrationScales = new SparseArray<>(); + vibrationScales.put(ScaleParam.TYPE_ALARM, 0.7f); + vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f); + + mVibratorControlService.setVibrationParams( + VibrationParamGenerator.generateVibrationParams(vibrationScales), + mFakeVibratorController); + ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, + AUDIO_ALARM_ATTRS, + mock(IExternalVibrationController.class)); + ExternalVibrationScale scale = + mExternalVibratorService.onExternalVibrationStart(externalVibration); + mExternalVibratorService.onExternalVibrationStop(externalVibration); + + assertEquals(scale.adaptiveHapticsScale, 0.7f, 0); + + externalVibration = new ExternalVibration(UID, PACKAGE_NAME, + AUDIO_NOTIFICATION_ATTRS, + mock(IExternalVibrationController.class)); + scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); + mExternalVibratorService.onExternalVibrationStop(externalVibration); + + assertEquals(scale.adaptiveHapticsScale, 0.4f, 0); + + AudioAttributes ringtoneAudioAttrs = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) + .build(); + externalVibration = new ExternalVibration(UID, PACKAGE_NAME, + ringtoneAudioAttrs, + mock(IExternalVibrationController.class)); + scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); + + assertEquals(scale.adaptiveHapticsScale, 1f, 0); + } + + @Test + @RequiresFlagsDisabled(android.os.vibrator.Flags.FLAG_ADAPTIVE_HAPTICS_ENABLED) + public void onExternalVibration_withAdaptiveHapticsFlagDisabled_alwaysReturnScaleNone() + throws RemoteException { + mockVibrators(1); + mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL, + IVibrator.CAP_AMPLITUDE_CONTROL); + createSystemReadyService(); + + SparseArray<Float> vibrationScales = new SparseArray<>(); + vibrationScales.put(ScaleParam.TYPE_ALARM, 0.7f); + vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f); + + mVibratorControlService.setVibrationParams( + VibrationParamGenerator.generateVibrationParams(vibrationScales), + mFakeVibratorController); + ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, + AUDIO_ALARM_ATTRS, + mock(IExternalVibrationController.class)); + ExternalVibrationScale scale = + mExternalVibratorService.onExternalVibrationStart(externalVibration); + mExternalVibratorService.onExternalVibrationStop(externalVibration); + + assertEquals(scale.adaptiveHapticsScale, 1f, 0); + + mVibratorControlService.setVibrationParams( + VibrationParamGenerator.generateVibrationParams(vibrationScales), + mFakeVibratorController); + externalVibration = new ExternalVibration(UID, PACKAGE_NAME, + AUDIO_NOTIFICATION_ATTRS, + mock(IExternalVibrationController.class)); + scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); + + assertEquals(scale.adaptiveHapticsScale, 1f, 0); } @Test diff --git a/services/tests/vibrator/utils/com/android/server/vibrator/VibrationParamGenerator.java b/services/tests/vibrator/utils/com/android/server/vibrator/VibrationParamGenerator.java new file mode 100644 index 000000000000..a606388da190 --- /dev/null +++ b/services/tests/vibrator/utils/com/android/server/vibrator/VibrationParamGenerator.java @@ -0,0 +1,54 @@ +/* + * 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.server.vibrator; + +import android.frameworks.vibrator.ScaleParam; +import android.frameworks.vibrator.VibrationParam; +import android.util.SparseArray; + +import java.util.ArrayList; +import java.util.List; + +/** + * A helper class that can be used to generate arrays of {@link VibrationParam}. + */ +public final class VibrationParamGenerator { + /** + * Generates an array of {@link VibrationParam}. + */ + public static VibrationParam[] generateVibrationParams(SparseArray<Float> vibrationScales) { + List<VibrationParam> vibrationParamList = new ArrayList<>(); + for (int i = 0; i < vibrationScales.size(); i++) { + int type = vibrationScales.keyAt(i); + float scale = vibrationScales.valueAt(i); + + vibrationParamList.add(generateVibrationParam(type, scale)); + } + + return vibrationParamList.toArray(new VibrationParam[0]); + } + + private static VibrationParam generateVibrationParam(int type, float scale) { + ScaleParam scaleParam = new ScaleParam(); + scaleParam.typesMask = type; + scaleParam.scale = scale; + VibrationParam vibrationParam = new VibrationParam(); + vibrationParam.setScale(scaleParam); + + return vibrationParam; + } +} |