1 package org.robolectric.shadows; 2 3 import static org.robolectric.util.reflector.Reflector.reflector; 4 5 import android.media.audiofx.Visualizer; 6 import android.media.audiofx.Visualizer.MeasurementPeakRms; 7 import android.media.audiofx.Visualizer.OnDataCaptureListener; 8 import java.util.concurrent.atomic.AtomicReference; 9 import org.robolectric.annotation.Implementation; 10 import org.robolectric.annotation.Implements; 11 import org.robolectric.annotation.RealObject; 12 import org.robolectric.util.reflector.Accessor; 13 import org.robolectric.util.reflector.ForType; 14 15 /** Shadow for the {@link Visualizer} class. */ 16 @Implements(value = Visualizer.class) 17 public class ShadowVisualizer { 18 19 @RealObject private Visualizer realObject; 20 21 private final AtomicReference<VisualizerSource> source = 22 new AtomicReference<>(new VisualizerSource() {}); 23 24 private boolean enabled = false; 25 private OnDataCaptureListener captureListener = null; 26 private boolean captureWaveform; 27 private boolean captureFft; 28 private int captureSize; 29 private int errorCode; 30 setSource(VisualizerSource source)31 public void setSource(VisualizerSource source) { 32 this.source.set(source); 33 } 34 35 @Implementation setDataCaptureListener( OnDataCaptureListener listener, int rate, boolean waveform, boolean fft)36 protected int setDataCaptureListener( 37 OnDataCaptureListener listener, int rate, boolean waveform, boolean fft) { 38 if (errorCode != Visualizer.SUCCESS) { 39 return errorCode; 40 } 41 captureListener = listener; 42 captureWaveform = waveform; 43 captureFft = fft; 44 return Visualizer.SUCCESS; 45 } 46 47 @Implementation native_getSamplingRate()48 protected int native_getSamplingRate() { 49 return source.get().getSamplingRate(); 50 } 51 52 @Implementation native_getWaveForm(byte[] waveform)53 protected int native_getWaveForm(byte[] waveform) { 54 return source.get().getWaveForm(waveform); 55 } 56 57 @Implementation native_getFft(byte[] fft)58 protected int native_getFft(byte[] fft) { 59 return source.get().getFft(fft); 60 } 61 62 @Implementation native_getEnabled()63 protected boolean native_getEnabled() { 64 return enabled; 65 } 66 67 @Implementation native_setCaptureSize(int size)68 protected int native_setCaptureSize(int size) { 69 if (errorCode != Visualizer.SUCCESS) { 70 return errorCode; 71 } 72 captureSize = size; 73 return Visualizer.SUCCESS; 74 } 75 76 @Implementation native_getCaptureSize()77 protected int native_getCaptureSize() { 78 return captureSize; 79 } 80 81 @Implementation native_setEnabled(boolean enabled)82 protected int native_setEnabled(boolean enabled) { 83 if (errorCode != Visualizer.SUCCESS) { 84 return errorCode; 85 } 86 this.enabled = enabled; 87 return Visualizer.SUCCESS; 88 } 89 90 @Implementation native_getPeakRms(MeasurementPeakRms measurement)91 protected int native_getPeakRms(MeasurementPeakRms measurement) { 92 return source.get().getPeakRms(measurement); 93 } 94 95 @Implementation native_release()96 protected void native_release() { 97 source.get().release(); 98 } 99 100 /** 101 * Trigger calls to the existing {@link OnDataCaptureListener}. 102 * 103 * <p>This is a no-op if the listener has not been set. 104 */ triggerDataCapture()105 public void triggerDataCapture() { 106 if (captureListener == null) { 107 return; 108 } 109 if (captureWaveform) { 110 byte[] waveform = new byte[captureSize]; 111 realObject.getWaveForm(waveform); 112 captureListener.onWaveFormDataCapture(realObject, waveform, realObject.getSamplingRate()); 113 } 114 if (captureFft) { 115 byte[] fft = new byte[captureSize]; 116 realObject.getFft(fft); 117 captureListener.onFftDataCapture(realObject, fft, realObject.getSamplingRate()); 118 } 119 } 120 121 /** 122 * Updates the state of the {@link Visualizer} itself. 123 * 124 * <p>This can be used e.g. to put the Visualizer in an unexpected state and cause an exception 125 * the next time the Visualizer is used. 126 */ setState(int newState)127 public void setState(int newState) { 128 reflector(ReflectorVisualizer.class, realObject).setState(newState); 129 } 130 131 /** 132 * Sets the error code to override setter methods in this class. 133 * 134 * <p>When the error code is set to anything other than {@link Visualizer.SUCCESS} setters in the 135 * Visualizer will early-out and return that error code. 136 */ setErrorCode(int errorCode)137 public void setErrorCode(int errorCode) { 138 this.errorCode = errorCode; 139 } 140 141 /** 142 * Provides underlying data for the {@link ShadowVisualizer}. The default implementations are 143 * there only to help tests to run when they don't need to verify specific behaviour, otherwise 144 * tests should probably override these and provide some specific implementation that allows them 145 * to verify the functionality needed. 146 */ 147 public interface VisualizerSource { 148 getSamplingRate()149 default int getSamplingRate() { 150 return 0; 151 } 152 getWaveForm(byte[] waveform)153 default int getWaveForm(byte[] waveform) { 154 return Visualizer.SUCCESS; 155 } 156 getFft(byte[] fft)157 default int getFft(byte[] fft) { 158 return Visualizer.SUCCESS; 159 } 160 getPeakRms(MeasurementPeakRms measurement)161 default int getPeakRms(MeasurementPeakRms measurement) { 162 return Visualizer.SUCCESS; 163 } 164 release()165 default void release() {} 166 } 167 168 /** Accessor interface for {@link Visualizer}'s internals. */ 169 @ForType(Visualizer.class) 170 private interface ReflectorVisualizer { 171 @Accessor("mState") setState(int state)172 void setState(int state); 173 } 174 } 175