diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowVibratorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowVibratorTest.java index b4963fedcc5..79dde573aa4 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowVibratorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowVibratorTest.java @@ -2,7 +2,12 @@ import static android.os.Build.VERSION_CODES.O; import static android.os.Build.VERSION_CODES.Q; +import static android.os.Build.VERSION_CODES.R; +import static android.os.Build.VERSION_CODES.S; import static android.os.VibrationEffect.EFFECT_CLICK; +import static android.os.VibrationEffect.EFFECT_DOUBLE_CLICK; +import static android.os.VibrationEffect.EFFECT_HEAVY_CLICK; +import static android.os.VibrationEffect.EFFECT_TICK; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; import static org.robolectric.shadows.ShadowLooper.shadowMainLooper; @@ -10,8 +15,10 @@ import android.content.Context; import android.os.VibrationEffect; import android.os.Vibrator; +import android.os.vibrator.PrimitiveSegment; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.common.collect.ImmutableList; import java.time.Duration; import org.junit.Before; import org.junit.Test; @@ -77,6 +84,85 @@ public void vibratePredefined() { assertThat(shadowOf(vibrator).getEffectId()).isEqualTo(EFFECT_CLICK); } + @Config(minSdk = S) + @Test + public void getVibrationEffectSegments_composeOnce_shouldReturnSameFragment() { + vibrator.vibrate( + VibrationEffect.startComposition() + .addPrimitive(EFFECT_CLICK, /* scale= */ 0.5f, /* delay= */ 20) + .addPrimitive(EFFECT_CLICK, /* scale= */ 0.7f, /* delay= */ 50) + .addPrimitive(EFFECT_CLICK, /* scale= */ 0.9f, /* delay= */ 150) + .compose()); + + assertThat(shadowOf(vibrator).getVibrationEffectSegments()) + .isEqualTo( + ImmutableList.of( + new PrimitiveSegment(EFFECT_CLICK, /* scale= */ 0.5f, /* delay= */ 20), + new PrimitiveSegment(EFFECT_CLICK, /* scale= */ 0.7f, /* delay= */ 50), + new PrimitiveSegment(EFFECT_CLICK, /* scale= */ 0.9f, /* delay= */ 150))); + } + + @Config(minSdk = S) + @Test + public void getVibrationEffectSegments_composeTwice_shouldReturnTheLastComposition() { + vibrator.vibrate( + VibrationEffect.startComposition() + .addPrimitive(EFFECT_CLICK, /* scale= */ 0.5f, /* delay= */ 20) + .addPrimitive(EFFECT_CLICK, /* scale= */ 0.7f, /* delay= */ 50) + .addPrimitive(EFFECT_CLICK, /* scale= */ 0.9f, /* delay= */ 150) + .compose()); + vibrator.vibrate( + VibrationEffect.startComposition() + .addPrimitive(EFFECT_CLICK, /* scale= */ 0.4f, /* delay= */ 120) + .addPrimitive(EFFECT_CLICK, /* scale= */ 0.9f, /* delay= */ 150) + .addPrimitive(EFFECT_CLICK, /* scale= */ 1f, /* delay= */ 2150) + .compose()); + + assertThat(shadowOf(vibrator).getVibrationEffectSegments()) + .isEqualTo( + ImmutableList.of( + new PrimitiveSegment(EFFECT_CLICK, /* scale= */ 0.4f, /* delay= */ 120), + new PrimitiveSegment(EFFECT_CLICK, /* scale= */ 0.9f, /* delay= */ 150), + new PrimitiveSegment(EFFECT_CLICK, /* scale= */ 1f, /* delay= */ 2150))); + } + + @Config(minSdk = R) + @Test + public void areAllPrimitivesSupported_oneSupportedPrimitive_shouldReturnTrue() { + shadowOf(vibrator) + .setSupportedPrimitives(ImmutableList.of(EFFECT_CLICK, EFFECT_TICK, EFFECT_HEAVY_CLICK)); + + assertThat(vibrator.areAllPrimitivesSupported(EFFECT_CLICK)).isTrue(); + } + + @Config(minSdk = R) + @Test + public void areAllPrimitivesSupported_twoSupportedPrimitives_shouldReturnTrue() { + shadowOf(vibrator) + .setSupportedPrimitives(ImmutableList.of(EFFECT_CLICK, EFFECT_TICK, EFFECT_HEAVY_CLICK)); + + assertThat(vibrator.areAllPrimitivesSupported(EFFECT_TICK, EFFECT_CLICK)).isTrue(); + } + + @Config(minSdk = R) + @Test + public void areAllPrimitivesSupported_twoSupportedPrimitivesOneUnsupported_shouldReturnFalse() { + shadowOf(vibrator) + .setSupportedPrimitives(ImmutableList.of(EFFECT_CLICK, EFFECT_TICK, EFFECT_HEAVY_CLICK)); + + assertThat(vibrator.areAllPrimitivesSupported(EFFECT_TICK, EFFECT_CLICK, EFFECT_DOUBLE_CLICK)) + .isFalse(); + } + + @Config(minSdk = R) + @Test + public void areAllPrimitivesSupported_oneUnsupportedPrimitivie_shouldReturnFalse() { + shadowOf(vibrator) + .setSupportedPrimitives(ImmutableList.of(EFFECT_CLICK, EFFECT_TICK, EFFECT_HEAVY_CLICK)); + + assertThat(vibrator.areAllPrimitivesSupported(EFFECT_DOUBLE_CLICK)).isFalse(); + } + @Test public void cancelled() { vibrator.vibrate(5000); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemVibrator.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemVibrator.java index 0dbcd1c2200..56aa8beaa0b 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemVibrator.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemVibrator.java @@ -27,8 +27,8 @@ @Implements(value = SystemVibrator.class, isInAndroidSdk = false) public class ShadowSystemVibrator extends ShadowVibrator { - private Handler handler = new Handler(Looper.myLooper()); - private Runnable stopVibratingRunnable = () -> vibrating = false; + private final Handler handler = new Handler(Looper.getMainLooper()); + private final Runnable stopVibratingRunnable = () -> vibrating = false; @Implementation protected boolean hasVibrator() { @@ -137,6 +137,8 @@ private void recordVibratePattern(List segments, int rep pattern[i] = segment.getDuration(); i++; } + vibrationEffectSegments.clear(); + vibrationEffectSegments.addAll(segments); recordVibratePattern(pattern, repeatIndex); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVibrator.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVibrator.java index 04068c46c9d..6f86aacb8a6 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVibrator.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVibrator.java @@ -1,6 +1,13 @@ package org.robolectric.shadows; +import static android.os.Build.VERSION_CODES.R; + import android.os.Vibrator; +import android.os.vibrator.VibrationEffectSegment; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @Implements(Vibrator.class) @@ -9,6 +16,8 @@ public class ShadowVibrator { boolean cancelled; long milliseconds; protected long[] pattern; + protected final List vibrationEffectSegments = new ArrayList<>(); + protected final List supportedPrimitives = new ArrayList<>(); int repeat; boolean hasVibrator = true; boolean hasAmplitudeControl = false; @@ -73,4 +82,24 @@ public int getRepeat() { return repeat; } + /** Returns the last list of {@link VibrationEffectSegment}. */ + public List getVibrationEffectSegments() { + return vibrationEffectSegments; + } + + @Implementation(minSdk = R) + protected boolean areAllPrimitivesSupported(int... primitiveIds) { + for (int i = 0; i < primitiveIds.length; i++) { + if (!supportedPrimitives.contains(primitiveIds[i])) { + return false; + } + } + return true; + } + + /** Adds supported vibration primitives. */ + public void setSupportedPrimitives(Collection primitives) { + supportedPrimitives.clear(); + supportedPrimitives.addAll(primitives); + } }