Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8cd94e33 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Squash frequency control capability for merged multi-vibrators when...

Merge "Squash frequency control capability for merged multi-vibrators when missing frequency profile." into tm-qpr-dev
parents 40adcdd7 69eaf72c
Loading
Loading
Loading
Loading
+15 −3
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Context;
import android.hardware.vibrator.IVibrator;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Log;
import android.util.Range;
import android.util.Range;
@@ -313,8 +314,14 @@ public class SystemVibrator extends Vibrator {
        private static final float EPSILON = 1e-5f;
        private static final float EPSILON = 1e-5f;


        public MultiVibratorInfo(VibratorInfo[] vibrators) {
        public MultiVibratorInfo(VibratorInfo[] vibrators) {
            // Need to use an extra constructor to share the computation in super initialization.
            this(vibrators, frequencyProfileIntersection(vibrators));
        }

        private MultiVibratorInfo(VibratorInfo[] vibrators,
                VibratorInfo.FrequencyProfile mergedProfile) {
            super(/* id= */ -1,
            super(/* id= */ -1,
                    capabilitiesIntersection(vibrators),
                    capabilitiesIntersection(vibrators, mergedProfile.isEmpty()),
                    supportedEffectsIntersection(vibrators),
                    supportedEffectsIntersection(vibrators),
                    supportedBrakingIntersection(vibrators),
                    supportedBrakingIntersection(vibrators),
                    supportedPrimitivesAndDurationsIntersection(vibrators),
                    supportedPrimitivesAndDurationsIntersection(vibrators),
@@ -323,14 +330,19 @@ public class SystemVibrator extends Vibrator {
                    integerLimitIntersection(vibrators, VibratorInfo::getPwlePrimitiveDurationMax),
                    integerLimitIntersection(vibrators, VibratorInfo::getPwlePrimitiveDurationMax),
                    integerLimitIntersection(vibrators, VibratorInfo::getPwleSizeMax),
                    integerLimitIntersection(vibrators, VibratorInfo::getPwleSizeMax),
                    floatPropertyIntersection(vibrators, VibratorInfo::getQFactor),
                    floatPropertyIntersection(vibrators, VibratorInfo::getQFactor),
                    frequencyProfileIntersection(vibrators));
                    mergedProfile);
        }
        }


        private static int capabilitiesIntersection(VibratorInfo[] infos) {
        private static int capabilitiesIntersection(VibratorInfo[] infos,
                boolean frequencyProfileIsEmpty) {
            int intersection = ~0;
            int intersection = ~0;
            for (VibratorInfo info : infos) {
            for (VibratorInfo info : infos) {
                intersection &= info.getCapabilities();
                intersection &= info.getCapabilities();
            }
            }
            if (frequencyProfileIsEmpty) {
                // Revoke frequency control if the merged frequency profile ended up empty.
                intersection &= ~IVibrator.CAP_FREQUENCY_CONTROL;
            }
            return intersection;
            return intersection;
        }
        }


+54 −8
Original line number Original line Diff line number Diff line
@@ -246,10 +246,12 @@ public class VibratorTest {
    @Test
    @Test
    public void getQFactorAndResonantFrequency_differentValues_returnsNaN() {
    public void getQFactorAndResonantFrequency_differentValues_returnsNaN() {
        VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
        VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setQFactor(1f)
                .setQFactor(1f)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, null))
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, null))
                .build();
                .build();
        VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
        VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setQFactor(2f)
                .setQFactor(2f)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(2, 2, 2, null))
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(2, 2, 2, null))
                .build();
                .build();
@@ -258,6 +260,7 @@ public class VibratorTest {


        assertTrue(Float.isNaN(info.getQFactor()));
        assertTrue(Float.isNaN(info.getQFactor()));
        assertTrue(Float.isNaN(info.getResonantFrequencyHz()));
        assertTrue(Float.isNaN(info.getResonantFrequencyHz()));
        assertEmptyFrequencyProfileAndControl(info);


        // One vibrator with values undefined.
        // One vibrator with values undefined.
        VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 3).build();
        VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 3).build();
@@ -266,16 +269,19 @@ public class VibratorTest {


        assertTrue(Float.isNaN(info.getQFactor()));
        assertTrue(Float.isNaN(info.getQFactor()));
        assertTrue(Float.isNaN(info.getResonantFrequencyHz()));
        assertTrue(Float.isNaN(info.getResonantFrequencyHz()));
        assertEmptyFrequencyProfileAndControl(info);
    }
    }


    @Test
    @Test
    public void getQFactorAndResonantFrequency_sameValues_returnsValue() {
    public void getQFactorAndResonantFrequency_sameValues_returnsValue() {
        VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
        VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setQFactor(10f)
                .setQFactor(10f)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(
                        /* resonantFrequencyHz= */ 11, 10, 0.5f, null))
                        /* resonantFrequencyHz= */ 11, 10, 0.5f, null))
                .build();
                .build();
        VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
        VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setQFactor(10f)
                .setQFactor(10f)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(
                        /* resonantFrequencyHz= */ 11, 5, 1, null))
                        /* resonantFrequencyHz= */ 11, 5, 1, null))
@@ -285,113 +291,131 @@ public class VibratorTest {


        assertEquals(10f, info.getQFactor(), TEST_TOLERANCE);
        assertEquals(10f, info.getQFactor(), TEST_TOLERANCE);
        assertEquals(11f, info.getResonantFrequencyHz(), TEST_TOLERANCE);
        assertEquals(11f, info.getResonantFrequencyHz(), TEST_TOLERANCE);

        // No frequency range defined.
        assertTrue(info.getFrequencyProfile().isEmpty());
        assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
    }
    }


    @Test
    @Test
    public void getFrequencyProfile_noVibrator_returnsEmpty() {
    public void getFrequencyProfile_noVibrator_returnsEmpty() {
        VibratorInfo info = new SystemVibrator.NoVibratorInfo();
        VibratorInfo info = new SystemVibrator.NoVibratorInfo();


        assertTrue(info.getFrequencyProfile().isEmpty());
        assertEmptyFrequencyProfileAndControl(info);
    }
    }


    @Test
    @Test
    public void getFrequencyProfile_differentResonantFrequencyOrResolutionValues_returnsEmpty() {
    public void getFrequencyProfile_differentResonantFrequencyOrResolutionValues_returnsEmpty() {
        VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
        VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1,
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1,
                        new float[] { 0, 1 }))
                        new float[] { 0, 1 }))
                .build();
                .build();
        VibratorInfo differentResonantFrequency = new VibratorInfo.Builder(/* id= */ 2)
        VibratorInfo differentResonantFrequency = new VibratorInfo.Builder(/* id= */ 2)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(2, 1, 1,
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(2, 1, 1,
                        new float[] { 0, 1 }))
                        new float[] { 0, 1 }))
                .build();
                .build();
        VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
        VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
                new VibratorInfo[]{firstVibrator, differentResonantFrequency});
                new VibratorInfo[]{firstVibrator, differentResonantFrequency});


        assertTrue(info.getFrequencyProfile().isEmpty());
        assertEmptyFrequencyProfileAndControl(info);


        VibratorInfo differentFrequencyResolution = new VibratorInfo.Builder(/* id= */ 2)
        VibratorInfo differentFrequencyResolution = new VibratorInfo.Builder(/* id= */ 2)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 2,
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 2,
                        new float[] { 0, 1 }))
                        new float[] { 0, 1 }))
                .build();
                .build();
        info = new SystemVibrator.MultiVibratorInfo(
        info = new SystemVibrator.MultiVibratorInfo(
                new VibratorInfo[]{firstVibrator, differentFrequencyResolution});
                new VibratorInfo[]{firstVibrator, differentFrequencyResolution});


        assertTrue(info.getFrequencyProfile().isEmpty());
        assertEmptyFrequencyProfileAndControl(info);
    }
    }


    @Test
    @Test
    public void getFrequencyProfile_missingValues_returnsEmpty() {
    public void getFrequencyProfile_missingValues_returnsEmpty() {
        VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
        VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1,
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1,
                        new float[] { 0, 1 }))
                        new float[] { 0, 1 }))
                .build();
                .build();
        VibratorInfo missingResonantFrequency = new VibratorInfo.Builder(/* id= */ 2)
        VibratorInfo missingResonantFrequency = new VibratorInfo.Builder(/* id= */ 2)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(Float.NaN, 1, 1,
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(Float.NaN, 1, 1,
                        new float[] { 0, 1 }))
                        new float[] { 0, 1 }))
                .build();
                .build();
        VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
        VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
                new VibratorInfo[]{firstVibrator, missingResonantFrequency});
                new VibratorInfo[]{firstVibrator, missingResonantFrequency});


        assertTrue(info.getFrequencyProfile().isEmpty());
        assertEmptyFrequencyProfileAndControl(info);


        VibratorInfo missingMinFrequency = new VibratorInfo.Builder(/* id= */ 2)
        VibratorInfo missingMinFrequency = new VibratorInfo.Builder(/* id= */ 2)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, Float.NaN, 1,
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, Float.NaN, 1,
                        new float[] { 0, 1 }))
                        new float[] { 0, 1 }))
                .build();
                .build();
        info = new SystemVibrator.MultiVibratorInfo(
        info = new SystemVibrator.MultiVibratorInfo(
                new VibratorInfo[]{firstVibrator, missingMinFrequency});
                new VibratorInfo[]{firstVibrator, missingMinFrequency});


        assertTrue(info.getFrequencyProfile().isEmpty());
        assertEmptyFrequencyProfileAndControl(info);


        VibratorInfo missingFrequencyResolution = new VibratorInfo.Builder(/* id= */ 2)
        VibratorInfo missingFrequencyResolution = new VibratorInfo.Builder(/* id= */ 2)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, Float.NaN,
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, Float.NaN,
                        new float[] { 0, 1 }))
                        new float[] { 0, 1 }))
                .build();
                .build();
        info = new SystemVibrator.MultiVibratorInfo(
        info = new SystemVibrator.MultiVibratorInfo(
                new VibratorInfo[]{firstVibrator, missingFrequencyResolution});
                new VibratorInfo[]{firstVibrator, missingFrequencyResolution});


        assertTrue(info.getFrequencyProfile().isEmpty());
        assertEmptyFrequencyProfileAndControl(info);


        VibratorInfo missingMaxAmplitudes = new VibratorInfo.Builder(/* id= */ 2)
        VibratorInfo missingMaxAmplitudes = new VibratorInfo.Builder(/* id= */ 2)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, null))
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, null))
                .build();
                .build();
        info = new SystemVibrator.MultiVibratorInfo(
        info = new SystemVibrator.MultiVibratorInfo(
                new VibratorInfo[]{firstVibrator, missingMaxAmplitudes});
                new VibratorInfo[]{firstVibrator, missingMaxAmplitudes});


        assertTrue(info.getFrequencyProfile().isEmpty());
        assertEmptyFrequencyProfileAndControl(info);
    }
    }


    @Test
    @Test
    public void getFrequencyProfile_unalignedMaxAmplitudes_returnsEmpty() {
    public void getFrequencyProfile_unalignedMaxAmplitudes_returnsEmpty() {
        VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
        VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10, 0.5f,
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10, 0.5f,
                        new float[] { 0, 1, 1, 0 }))
                        new float[] { 0, 1, 1, 0 }))
                .build();
                .build();
        VibratorInfo unalignedMinFrequency = new VibratorInfo.Builder(/* id= */ 2)
        VibratorInfo unalignedMinFrequency = new VibratorInfo.Builder(/* id= */ 2)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.1f, 0.5f,
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.1f, 0.5f,
                        new float[] { 0, 1, 1, 0 }))
                        new float[] { 0, 1, 1, 0 }))
                .build();
                .build();
        VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 2)
        VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 2)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
                        new float[] { 0, 1, 1, 0 }))
                        new float[] { 0, 1, 1, 0 }))
                .build();
                .build();
        VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
        VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
                new VibratorInfo[]{firstVibrator, unalignedMinFrequency, thirdVibrator});
                new VibratorInfo[]{firstVibrator, unalignedMinFrequency, thirdVibrator});


        assertTrue(info.getFrequencyProfile().isEmpty());
        assertEmptyFrequencyProfileAndControl(info);
    }
    }


    @Test
    @Test
    public void getFrequencyProfile_alignedProfiles_returnsIntersection() {
    public void getFrequencyProfile_alignedProfiles_returnsIntersection() {
        VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
        VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10, 0.5f,
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10, 0.5f,
                        new float[] { 0.5f, 1, 1, 0.5f }))
                        new float[] { 0.5f, 1, 1, 0.5f }))
                .build();
                .build();
        VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
        VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
                        new float[] { 1, 1, 1 }))
                        new float[] { 1, 1, 1 }))
                .build();
                .build();
        VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 3)
        VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 3)
                .setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
                        new float[] { 0.8f, 1, 0.8f, 0.5f }))
                        new float[] { 0.8f, 1, 0.8f, 0.5f }))
                .build();
                .build();
@@ -401,6 +425,20 @@ public class VibratorTest {
        assertEquals(
        assertEquals(
                new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, new float[] { 0.8f, 1, 0.5f }),
                new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, new float[] { 0.8f, 1, 0.5f }),
                info.getFrequencyProfile());
                info.getFrequencyProfile());
        assertEquals(true, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));

        // Third vibrator without frequency control capability.
        thirdVibrator = new VibratorInfo.Builder(/* id= */ 3)
                .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
                        new float[] { 0.8f, 1, 0.8f, 0.5f }))
                .build();
        info = new SystemVibrator.MultiVibratorInfo(
                new VibratorInfo[]{firstVibrator, secondVibrator, thirdVibrator});

        assertEquals(
                new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, new float[] { 0.8f, 1, 0.5f }),
                info.getFrequencyProfile());
        assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
    }
    }


    @Test
    @Test
@@ -547,4 +585,12 @@ public class VibratorTest {
        VibrationAttributes vibrationAttributes = captor.getValue();
        VibrationAttributes vibrationAttributes = captor.getValue();
        assertEquals(new VibrationAttributes.Builder().build(), vibrationAttributes);
        assertEquals(new VibrationAttributes.Builder().build(), vibrationAttributes);
    }
    }

    /**
     * Asserts that the frequency profile is empty, and therefore frequency control isn't supported.
     */
    void assertEmptyFrequencyProfileAndControl(VibratorInfo info) {
        assertTrue(info.getFrequencyProfile().isEmpty());
        assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
    }
}
}