Skip to content

Commit

Permalink
1. Adds ShadowVibrator#addSupportedPrimitives to enable
Browse files Browse the repository at this point in the history
   shadowing of `Vibrator#areAllPrimitivesSupported`.
2. Creates `ShadowVibrator#mHandler` using main looper to avoid getting
   `null` from `Looper#myLooper` in some occasions.
3. Stores `VibrationEffectSegment`s in `ShadowVibrator` and exposes a getter to
   enable verification of `VibrationEffect` created by
   `VibrationEffect#startComposition`.

PiperOrigin-RevId: 413689184
  • Loading branch information
Googler authored and hoisie committed Dec 6, 2021
1 parent bcb31db commit 26bc30a
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 2 deletions.
Expand Up @@ -2,16 +2,23 @@

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;

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;
Expand Down Expand Up @@ -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);
Expand Down
Expand Up @@ -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() {
Expand Down Expand Up @@ -137,6 +137,8 @@ private void recordVibratePattern(List<VibrationEffectSegment> segments, int rep
pattern[i] = segment.getDuration();
i++;
}
vibrationEffectSegments.clear();
vibrationEffectSegments.addAll(segments);
recordVibratePattern(pattern, repeatIndex);
}

Expand Down
@@ -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)
Expand All @@ -9,6 +16,8 @@ public class ShadowVibrator {
boolean cancelled;
long milliseconds;
protected long[] pattern;
protected final List<VibrationEffectSegment> vibrationEffectSegments = new ArrayList<>();
protected final List<Integer> supportedPrimitives = new ArrayList<>();
int repeat;
boolean hasVibrator = true;
boolean hasAmplitudeControl = false;
Expand Down Expand Up @@ -73,4 +82,24 @@ public int getRepeat() {
return repeat;
}

/** Returns the last list of {@link VibrationEffectSegment}. */
public List<VibrationEffectSegment> 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<Integer> primitives) {
supportedPrimitives.clear();
supportedPrimitives.addAll(primitives);
}
}

0 comments on commit 26bc30a

Please sign in to comment.