Improve coverage (#22)
* New tests * Try adjust codecov * CropHelper and CameraUtils tests * Set target coverage to 40% * OrientationHelperTest * Preview tests * Fix SurfaceView * Introduce Task for async tests * Gesture tests * Improve Gesture Tests * Add wake lock * Fix view size * Add build info logs * Revert info * Try fix bug * Test timeout * Try fix tests * Fix TextureView tests if not hardware accelerated * Fix bugpull/36/head
parent
982ed3d094
commit
66077c1eaa
@ -0,0 +1,13 @@ |
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
package="com.otaliastudios.cameraview"> |
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" /> |
||||||
|
<uses-permission android:name="android.permission.RECORD_AUDIO" /> |
||||||
|
|
||||||
|
<application> |
||||||
|
<activity |
||||||
|
android:hardwareAccelerated="true" |
||||||
|
android:name=".TestActivity"/> |
||||||
|
</application> |
||||||
|
|
||||||
|
</manifest> |
@ -0,0 +1,41 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.os.Handler; |
||||||
|
import android.os.Looper; |
||||||
|
import android.support.test.InstrumentationRegistry; |
||||||
|
import android.support.test.annotation.UiThreadTest; |
||||||
|
import android.support.test.rule.ActivityTestRule; |
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Rule; |
||||||
|
|
||||||
|
public class BaseTest { |
||||||
|
|
||||||
|
public static void ui(Runnable runnable) { |
||||||
|
InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable); |
||||||
|
} |
||||||
|
|
||||||
|
public static void uiAsync(Runnable runnable) { |
||||||
|
new Handler(Looper.getMainLooper()).post(runnable); |
||||||
|
} |
||||||
|
|
||||||
|
public static Context context() { |
||||||
|
return InstrumentationRegistry.getInstrumentation().getContext(); |
||||||
|
} |
||||||
|
|
||||||
|
public static void uiRequestLayout(final View view) { |
||||||
|
ui(new Runnable() { |
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
view.requestLayout(); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
public static void waitUi() { |
||||||
|
InstrumentationRegistry.getInstrumentation().waitForIdleSync(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.annotation.TargetApi; |
||||||
|
import android.app.Instrumentation; |
||||||
|
import android.content.Context; |
||||||
|
import android.content.pm.PackageManager; |
||||||
|
import android.graphics.Bitmap; |
||||||
|
import android.graphics.Color; |
||||||
|
import android.support.test.InstrumentationRegistry; |
||||||
|
import android.support.test.filters.SmallTest; |
||||||
|
import android.support.test.internal.runner.InstrumentationConnection; |
||||||
|
import android.support.test.runner.AndroidJUnit4; |
||||||
|
|
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream; |
||||||
|
|
||||||
|
import static org.mockito.Mockito.*; |
||||||
|
import static org.junit.Assert.*; |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class) |
||||||
|
@SmallTest |
||||||
|
public class CameraUtilsTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testHasCameras() { |
||||||
|
Context context = mock(Context.class); |
||||||
|
PackageManager pm = mock(PackageManager.class); |
||||||
|
when(context.getPackageManager()).thenReturn(pm); |
||||||
|
when(pm.hasSystemFeature(anyString())).thenReturn(true); |
||||||
|
assertTrue(CameraUtils.hasCameras(context)); |
||||||
|
|
||||||
|
when(pm.hasSystemFeature(anyString())).thenReturn(false); |
||||||
|
assertFalse(CameraUtils.hasCameras(context)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDecodeBitmap() { |
||||||
|
int w = 100, h = 200, color = Color.WHITE; |
||||||
|
Bitmap source = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); |
||||||
|
source.setPixel(0, 0, color); |
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream(); |
||||||
|
|
||||||
|
// Using lossy JPG we can't have strict comparison of values after compression.
|
||||||
|
source.compress(Bitmap.CompressFormat.PNG, 100, os); |
||||||
|
|
||||||
|
// No orientation.
|
||||||
|
Bitmap other = CameraUtils.decodeBitmap(os.toByteArray()); |
||||||
|
assertEquals(100, w); |
||||||
|
assertEquals(200, h); |
||||||
|
assertEquals(color, other.getPixel(0, 0)); |
||||||
|
assertEquals(0, other.getPixel(0, h-1)); |
||||||
|
assertEquals(0, other.getPixel(w-1, 0)); |
||||||
|
assertEquals(0, other.getPixel(w-1, h-1)); |
||||||
|
|
||||||
|
// TODO: improve when we add EXIF writing to byte arrays
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,92 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.content.pm.PackageManager; |
||||||
|
import android.graphics.Bitmap; |
||||||
|
import android.graphics.BitmapFactory; |
||||||
|
import android.graphics.Color; |
||||||
|
import android.graphics.Rect; |
||||||
|
import android.graphics.YuvImage; |
||||||
|
import android.support.test.filters.SmallTest; |
||||||
|
import android.support.test.runner.AndroidJUnit4; |
||||||
|
|
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
import org.mockito.invocation.InvocationOnMock; |
||||||
|
import org.mockito.stubbing.Answer; |
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream; |
||||||
|
import java.io.OutputStream; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
import static org.junit.Assert.assertFalse; |
||||||
|
import static org.junit.Assert.assertTrue; |
||||||
|
import static org.mockito.Matchers.any; |
||||||
|
import static org.mockito.Matchers.anyInt; |
||||||
|
import static org.mockito.Mockito.anyString; |
||||||
|
import static org.mockito.Mockito.mock; |
||||||
|
import static org.mockito.Mockito.when; |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class) |
||||||
|
@SmallTest |
||||||
|
public class CropHelperTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testCropFromYuv() { |
||||||
|
testCropFromYuv(1600, 1600, AspectRatio.of(16, 9)); |
||||||
|
testCropFromYuv(1600, 1600, AspectRatio.of(9, 16)); |
||||||
|
} |
||||||
|
|
||||||
|
private void testCropFromYuv(final int w, final int h, final AspectRatio target) { |
||||||
|
final boolean wider = target.toFloat() > ((float) w / (float) h); |
||||||
|
|
||||||
|
// Not sure how to test YuvImages...
|
||||||
|
YuvImage i = mock(YuvImage.class); |
||||||
|
when(i.getWidth()).thenReturn(w); |
||||||
|
when(i.getHeight()).thenReturn(h); |
||||||
|
when(i.compressToJpeg(any(Rect.class), anyInt(), any(OutputStream.class))).thenAnswer(new Answer<Boolean>() { |
||||||
|
@Override |
||||||
|
public Boolean answer(InvocationOnMock iom) throws Throwable { |
||||||
|
Object[] args = iom.getArguments(); |
||||||
|
Rect rect = (Rect) args[0]; |
||||||
|
|
||||||
|
// Assert.
|
||||||
|
AspectRatio ratio = AspectRatio.of(rect.width(), rect.height()); |
||||||
|
assertEquals(target, ratio); |
||||||
|
if (wider) { // width must match.
|
||||||
|
assertEquals(rect.width(), w); |
||||||
|
} else { |
||||||
|
assertEquals(rect.height(), h); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
}); |
||||||
|
CropHelper.cropToJpeg(i, target, 100); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testCropFromJpeg() { |
||||||
|
testCropFromJpeg(1600, 1600, AspectRatio.of(16, 9)); |
||||||
|
testCropFromJpeg(1600, 1600, AspectRatio.of(9, 16)); |
||||||
|
} |
||||||
|
|
||||||
|
private void testCropFromJpeg(int w, int h, AspectRatio target) { |
||||||
|
final boolean wider = target.toFloat() > ((float) w / (float) h); |
||||||
|
|
||||||
|
Bitmap source = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); |
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream(); |
||||||
|
source.compress(Bitmap.CompressFormat.JPEG, 100, os); |
||||||
|
byte[] b = CropHelper.cropToJpeg(os.toByteArray(), target, 100); |
||||||
|
Bitmap result = BitmapFactory.decodeByteArray(b, 0, b.length); |
||||||
|
|
||||||
|
// Assert.
|
||||||
|
AspectRatio ratio = AspectRatio.of(result.getWidth(), result.getHeight()); |
||||||
|
assertEquals(target, ratio); |
||||||
|
if (wider) { // width must match.
|
||||||
|
assertEquals(result.getWidth(), w); |
||||||
|
} else { |
||||||
|
assertEquals(result.getHeight(), h); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,62 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.annotation.TargetApi; |
||||||
|
import android.content.Context; |
||||||
|
import android.support.test.espresso.Espresso; |
||||||
|
import android.support.test.espresso.Root; |
||||||
|
import android.support.test.espresso.ViewAssertion; |
||||||
|
import android.support.test.espresso.ViewInteraction; |
||||||
|
import android.support.test.espresso.assertion.ViewAssertions; |
||||||
|
import android.support.test.espresso.matcher.ViewMatchers; |
||||||
|
import android.support.test.rule.ActivityTestRule; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
import org.hamcrest.BaseMatcher; |
||||||
|
import org.hamcrest.Description; |
||||||
|
import org.hamcrest.Matchers; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Rule; |
||||||
|
|
||||||
|
import static android.support.test.espresso.Espresso.onView; |
||||||
|
import static org.hamcrest.Matchers.any; |
||||||
|
|
||||||
|
@TargetApi(17) |
||||||
|
public abstract class GestureLayoutTest<T extends GestureLayout> extends BaseTest { |
||||||
|
|
||||||
|
protected abstract T create(Context context); |
||||||
|
|
||||||
|
@Rule |
||||||
|
public ActivityTestRule<TestActivity> rule = new ActivityTestRule<>(TestActivity.class); |
||||||
|
|
||||||
|
protected T layout; |
||||||
|
protected Task<Gesture> touch; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void setUp() { |
||||||
|
ui(new Runnable() { |
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
TestActivity a = rule.getActivity(); |
||||||
|
layout = create(a); |
||||||
|
layout.enable(true); |
||||||
|
a.inflate(layout); |
||||||
|
|
||||||
|
touch = new Task<>(); |
||||||
|
layout.setOnTouchListener(new View.OnTouchListener() { |
||||||
|
@Override |
||||||
|
public boolean onTouch(View view, MotionEvent motionEvent) { |
||||||
|
boolean found = layout.onTouchEvent(motionEvent); |
||||||
|
if (found) touch.end(layout.getGestureType()); |
||||||
|
return true; |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
protected final ViewInteraction onLayout() { |
||||||
|
return onView(Matchers.<View>is(layout)).inRoot(any(Root.class)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,78 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.drawable.ColorDrawable; |
||||||
|
import android.support.test.InstrumentationRegistry; |
||||||
|
import android.support.test.filters.MediumTest; |
||||||
|
import android.support.test.rule.ActivityTestRule; |
||||||
|
import android.support.test.runner.AndroidJUnit4; |
||||||
|
|
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Rule; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
|
||||||
|
import static org.mockito.Mockito.*; |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class) |
||||||
|
@MediumTest |
||||||
|
public class GridLinesLayoutTest extends BaseTest { |
||||||
|
|
||||||
|
@Rule |
||||||
|
public ActivityTestRule<TestActivity> rule = new ActivityTestRule<>(TestActivity.class); |
||||||
|
|
||||||
|
private GridLinesLayout layout; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void setUp() { |
||||||
|
ui(new Runnable() { |
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
TestActivity a = rule.getActivity(); |
||||||
|
layout = new GridLinesLayout(a); |
||||||
|
layout.setGridMode(Grid.OFF); |
||||||
|
a.getContentView().addView(layout); |
||||||
|
layout.vert = mock(ColorDrawable.class); |
||||||
|
layout.horiz = mock(ColorDrawable.class); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testOff() { |
||||||
|
layout.drawTask.listen(); |
||||||
|
layout.setGridMode(Grid.OFF); |
||||||
|
layout.drawTask.await(); |
||||||
|
verify(layout.vert, never()).draw(any(Canvas.class)); |
||||||
|
verify(layout.horiz, never()).draw(any(Canvas.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void test3x3() { |
||||||
|
layout.drawTask.listen(); |
||||||
|
layout.setGridMode(Grid.DRAW_3X3); |
||||||
|
layout.drawTask.await(); |
||||||
|
verify(layout.vert, times(2)).draw(any(Canvas.class)); |
||||||
|
verify(layout.horiz, times(2)).draw(any(Canvas.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testPhi() { |
||||||
|
layout.drawTask.listen(); |
||||||
|
layout.setGridMode(Grid.DRAW_PHI); |
||||||
|
layout.drawTask.await(); |
||||||
|
verify(layout.vert, times(2)).draw(any(Canvas.class)); |
||||||
|
verify(layout.horiz, times(2)).draw(any(Canvas.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void test4x4() { |
||||||
|
layout.drawTask.listen(); |
||||||
|
layout.setGridMode(Grid.DRAW_4X4); |
||||||
|
layout.drawTask.await(); |
||||||
|
verify(layout.vert, times(3)).draw(any(Canvas.class)); |
||||||
|
verify(layout.horiz, times(3)).draw(any(Canvas.class)); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,97 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.annotation.TargetApi; |
||||||
|
import android.app.Instrumentation; |
||||||
|
import android.app.UiAutomation; |
||||||
|
import android.support.test.InstrumentationRegistry; |
||||||
|
import android.support.test.filters.SmallTest; |
||||||
|
import android.support.test.runner.AndroidJUnit4; |
||||||
|
import android.view.OrientationEventListener; |
||||||
|
|
||||||
|
import org.junit.After; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
|
||||||
|
import static org.junit.Assert.*; |
||||||
|
import static org.mockito.Mockito.*; |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class) |
||||||
|
@SmallTest |
||||||
|
public class OrientationHelperTest extends BaseTest { |
||||||
|
|
||||||
|
private OrientationHelper helper; |
||||||
|
private OrientationHelper.Callbacks callbacks; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void setUp() { |
||||||
|
ui(new Runnable() { |
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
callbacks = mock(OrientationHelper.Callbacks.class); |
||||||
|
helper = new OrientationHelper(context(), callbacks); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
@After |
||||||
|
public void tearDown() { |
||||||
|
callbacks = null; |
||||||
|
helper = null; |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testEnable() { |
||||||
|
assertNotNull(helper.mListener); |
||||||
|
assertNull(helper.mDisplay); |
||||||
|
|
||||||
|
helper.enable(context()); |
||||||
|
assertNotNull(helper.mListener); |
||||||
|
assertNotNull(helper.mDisplay); |
||||||
|
|
||||||
|
// Ensure nothing bad if called twice.
|
||||||
|
helper.enable(context()); |
||||||
|
assertNotNull(helper.mListener); |
||||||
|
assertNotNull(helper.mDisplay); |
||||||
|
|
||||||
|
helper.disable(); |
||||||
|
assertNotNull(helper.mListener); |
||||||
|
assertNull(helper.mDisplay); |
||||||
|
|
||||||
|
verify(callbacks, atLeastOnce()).onDisplayOffsetChanged(anyInt()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testRotation() { |
||||||
|
helper.enable(context()); |
||||||
|
|
||||||
|
reset(callbacks); // Reset counts.
|
||||||
|
helper.mListener.onOrientationChanged(OrientationEventListener.ORIENTATION_UNKNOWN); |
||||||
|
assertEquals(helper.mLastOrientation, 0); |
||||||
|
helper.mListener.onOrientationChanged(10); |
||||||
|
assertEquals(helper.mLastOrientation, 0); |
||||||
|
helper.mListener.onOrientationChanged(-10); |
||||||
|
assertEquals(helper.mLastOrientation, 0); |
||||||
|
helper.mListener.onOrientationChanged(44); |
||||||
|
assertEquals(helper.mLastOrientation, 0); |
||||||
|
helper.mListener.onOrientationChanged(360); |
||||||
|
assertEquals(helper.mLastOrientation, 0); |
||||||
|
|
||||||
|
// Callback called just once.
|
||||||
|
verify(callbacks, times(1)).onDeviceOrientationChanged(0); |
||||||
|
|
||||||
|
helper.mListener.onOrientationChanged(90); |
||||||
|
helper.mListener.onOrientationChanged(91); |
||||||
|
assertEquals(helper.mLastOrientation, 90); |
||||||
|
verify(callbacks, times(1)).onDeviceOrientationChanged(90); |
||||||
|
|
||||||
|
helper.mListener.onOrientationChanged(180); |
||||||
|
assertEquals(helper.mLastOrientation, 180); |
||||||
|
verify(callbacks, times(1)).onDeviceOrientationChanged(180); |
||||||
|
|
||||||
|
helper.mListener.onOrientationChanged(270); |
||||||
|
assertEquals(helper.mLastOrientation, 270); |
||||||
|
verify(callbacks, times(1)).onDeviceOrientationChanged(270); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,86 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.support.test.espresso.Espresso; |
||||||
|
import android.support.test.espresso.UiController; |
||||||
|
import android.support.test.espresso.ViewAction; |
||||||
|
import android.support.test.espresso.action.CoordinatesProvider; |
||||||
|
import android.support.test.espresso.action.GeneralLocation; |
||||||
|
import android.support.test.espresso.action.GeneralSwipeAction; |
||||||
|
import android.support.test.espresso.action.MotionEvents; |
||||||
|
import android.support.test.espresso.action.PrecisionDescriber; |
||||||
|
import android.support.test.espresso.action.Press; |
||||||
|
import android.support.test.espresso.action.Swipe; |
||||||
|
import android.support.test.espresso.action.ViewActions; |
||||||
|
import android.support.test.espresso.assertion.ViewAssertions; |
||||||
|
import android.support.test.espresso.matcher.ViewMatchers; |
||||||
|
import android.support.test.filters.SmallTest; |
||||||
|
import android.support.test.runner.AndroidJUnit4; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import android.view.ScaleGestureDetector; |
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
import org.hamcrest.Matcher; |
||||||
|
import org.hamcrest.Matchers; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
import static android.support.test.espresso.Espresso.onView; |
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withId; |
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
import static org.junit.Assert.assertNotNull; |
||||||
|
import static org.junit.Assert.assertNull; |
||||||
|
import static org.junit.Assert.assertTrue; |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class) |
||||||
|
@SmallTest |
||||||
|
public class PinchGestureLayoutTest extends GestureLayoutTest<PinchGestureLayout> { |
||||||
|
|
||||||
|
@Override |
||||||
|
protected PinchGestureLayout create(Context context) { |
||||||
|
return new PinchGestureLayout(context); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDefaults() { |
||||||
|
assertEquals(layout.getGestureType(), Gesture.PINCH); |
||||||
|
assertEquals(layout.getPoints().length, 2); |
||||||
|
assertEquals(layout.getPoints()[0].x, 0, 0); |
||||||
|
assertEquals(layout.getPoints()[0].y, 0, 0); |
||||||
|
assertEquals(layout.getPoints()[1].x, 0, 0); |
||||||
|
assertEquals(layout.getPoints()[1].y, 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: test pinch open
|
||||||
|
// TODO: test pinch close
|
||||||
|
// TODO: test pinch disabled
|
||||||
|
|
||||||
|
// Possible approach: mimic pinch gesture and let espresso test.
|
||||||
|
// Too lazy to do this now, but it's possible.
|
||||||
|
// https://stackoverflow.com/questions/11523423/how-to-generate-zoom-pinch-gesture-for-testing-for-android
|
||||||
|
|
||||||
|
public abstract class PinchViewAction implements ViewAction { |
||||||
|
} |
||||||
|
|
||||||
|
private void testPinch(ViewAction action, boolean increasing) { |
||||||
|
touch.listen(); |
||||||
|
touch.start(); |
||||||
|
onLayout().perform(action); |
||||||
|
Gesture found = touch.await(10000, TimeUnit.MILLISECONDS); |
||||||
|
assertNotNull(found); |
||||||
|
|
||||||
|
// How will this move our parameter?
|
||||||
|
float curr = 0.5f, min = 0f, max = 1f; |
||||||
|
float newValue = layout.scaleValue(curr, min, max); |
||||||
|
if (increasing) { |
||||||
|
assertTrue(newValue > curr); |
||||||
|
assertTrue(newValue <= max); |
||||||
|
} else { |
||||||
|
assertTrue(newValue < curr); |
||||||
|
assertTrue(newValue >= min); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,157 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.support.test.rule.ActivityTestRule; |
||||||
|
import android.view.ViewGroup; |
||||||
|
|
||||||
|
import org.junit.After; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Rule; |
||||||
|
import org.junit.Test; |
||||||
|
import org.mockito.invocation.InvocationOnMock; |
||||||
|
import org.mockito.stubbing.Answer; |
||||||
|
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
import static org.junit.Assert.*; |
||||||
|
|
||||||
|
import static org.mockito.Mockito.*; |
||||||
|
|
||||||
|
public abstract class PreviewTest extends BaseTest { |
||||||
|
|
||||||
|
protected abstract Preview createPreview(Context context, ViewGroup parent, Preview.SurfaceCallback callback); |
||||||
|
|
||||||
|
@Rule |
||||||
|
public ActivityTestRule<TestActivity> rule = new ActivityTestRule<>(TestActivity.class); |
||||||
|
|
||||||
|
protected Preview preview; |
||||||
|
protected Size surfaceSize; |
||||||
|
private Preview.SurfaceCallback callback; |
||||||
|
private Task<Boolean> availability; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void setUp() { |
||||||
|
availability = new Task<>(); |
||||||
|
availability.listen(); |
||||||
|
|
||||||
|
ui(new Runnable() { |
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
TestActivity a = rule.getActivity(); |
||||||
|
surfaceSize = a.getContentSize(); |
||||||
|
|
||||||
|
callback = mock(Preview.SurfaceCallback.class); |
||||||
|
doAnswer(new Answer() { |
||||||
|
@Override |
||||||
|
public Object answer(InvocationOnMock invocation) throws Throwable { |
||||||
|
if (availability != null) availability.end(true); |
||||||
|
return null; |
||||||
|
} |
||||||
|
}).when(callback).onSurfaceAvailable(); |
||||||
|
preview = createPreview(a, a.getContentView(), callback); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
// Wait for surface to be available.
|
||||||
|
protected void ensureAvailable() { |
||||||
|
assertNotNull(availability.await(2, TimeUnit.SECONDS)); |
||||||
|
} |
||||||
|
|
||||||
|
// Trigger a destroy.
|
||||||
|
protected void ensureDestroyed() { |
||||||
|
ui(new Runnable() { |
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
rule.getActivity().getContentView().removeView(preview.getView()); |
||||||
|
} |
||||||
|
}); |
||||||
|
waitUi(); |
||||||
|
} |
||||||
|
|
||||||
|
@After |
||||||
|
public void tearDown() { |
||||||
|
preview = null; |
||||||
|
callback = null; |
||||||
|
surfaceSize = null; |
||||||
|
availability = null; |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDefaults() { |
||||||
|
ensureAvailable(); |
||||||
|
assertTrue(preview.isReady()); |
||||||
|
assertNotNull(preview.getView()); |
||||||
|
assertNotNull(preview.getOutputClass()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDesiredSize() { |
||||||
|
preview.setDesiredSize(160, 90); |
||||||
|
assertEquals(160, preview.getDesiredSize().getWidth()); |
||||||
|
assertEquals(90, preview.getDesiredSize().getHeight()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSurfaceAvailable() { |
||||||
|
ensureAvailable(); |
||||||
|
verify(callback, times(1)).onSurfaceAvailable(); |
||||||
|
assertEquals(surfaceSize.getWidth(), preview.getSurfaceSize().getWidth()); |
||||||
|
assertEquals(surfaceSize.getHeight(), preview.getSurfaceSize().getHeight()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSurfaceDestroyed() { |
||||||
|
ensureAvailable(); |
||||||
|
ensureDestroyed(); |
||||||
|
assertEquals(0, preview.getSurfaceSize().getWidth()); |
||||||
|
assertEquals(0, preview.getSurfaceSize().getHeight()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testCropCenter() throws Exception { |
||||||
|
ensureAvailable(); |
||||||
|
|
||||||
|
// This is given by the activity, it's the fixed size.
|
||||||
|
float view = getViewAspectRatio(); |
||||||
|
|
||||||
|
// If we apply a desired size with same aspect ratio, there should be no crop.
|
||||||
|
setDesiredAspectRatio(view); |
||||||
|
assertFalse(preview.isCropping()); |
||||||
|
|
||||||
|
// If we apply a different aspect ratio, there should be cropping.
|
||||||
|
float desired = view * 1.2f; |
||||||
|
setDesiredAspectRatio(desired); |
||||||
|
assertTrue(preview.isCropping()); |
||||||
|
|
||||||
|
// Since desired is 'desired', let's fake a new view size that is consistent with it.
|
||||||
|
// Ensure crop is not happening anymore.
|
||||||
|
preview.mCropTask.listen(); |
||||||
|
preview.onSurfaceSizeChanged((int) (50f * desired), 50); // Wait...
|
||||||
|
preview.mCropTask.await(); |
||||||
|
assertEquals(desired, getViewAspectRatioWithScale(), 0.01f); |
||||||
|
assertFalse(preview.isCropping()); |
||||||
|
} |
||||||
|
|
||||||
|
private void setDesiredAspectRatio(float desiredAspectRatio) { |
||||||
|
preview.mCropTask.listen(); |
||||||
|
preview.setDesiredSize((int) (10f * desiredAspectRatio), 10); // Wait...
|
||||||
|
preview.mCropTask.await(); |
||||||
|
assertEquals(desiredAspectRatio, getViewAspectRatioWithScale(), 0.01f); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private float getViewAspectRatio() { |
||||||
|
Size size = preview.getSurfaceSize(); |
||||||
|
return AspectRatio.of(size.getWidth(), size.getHeight()).toFloat(); |
||||||
|
} |
||||||
|
|
||||||
|
private float getViewAspectRatioWithScale() { |
||||||
|
Size size = preview.getSurfaceSize(); |
||||||
|
int newWidth = (int) (((float) size.getWidth()) * preview.getView().getScaleX()); |
||||||
|
int newHeight = (int) (((float) size.getHeight()) * preview.getView().getScaleY()); |
||||||
|
return AspectRatio.of(newWidth, newHeight).toFloat(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,97 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.support.test.espresso.ViewAction; |
||||||
|
import android.support.test.espresso.assertion.ViewAssertions; |
||||||
|
import android.support.test.filters.SmallTest; |
||||||
|
import android.support.test.runner.AndroidJUnit4; |
||||||
|
|
||||||
|
import org.hamcrest.Matchers; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
import static android.support.test.espresso.Espresso.onView; |
||||||
|
import static android.support.test.espresso.action.ViewActions.click; |
||||||
|
import static android.support.test.espresso.action.ViewActions.swipeDown; |
||||||
|
import static android.support.test.espresso.action.ViewActions.swipeLeft; |
||||||
|
import static android.support.test.espresso.action.ViewActions.swipeRight; |
||||||
|
import static android.support.test.espresso.action.ViewActions.swipeUp; |
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withId; |
||||||
|
import static junit.framework.Assert.assertNotNull; |
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
import static org.junit.Assert.assertNull; |
||||||
|
import static org.junit.Assert.assertTrue; |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class) |
||||||
|
@SmallTest |
||||||
|
public class ScrollGestureLayoutTest extends GestureLayoutTest<ScrollGestureLayout> { |
||||||
|
|
||||||
|
@Override |
||||||
|
protected ScrollGestureLayout create(Context context) { |
||||||
|
return new ScrollGestureLayout(context); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDefaults() { |
||||||
|
assertNull(layout.getGestureType()); |
||||||
|
assertEquals(layout.getPoints().length, 2); |
||||||
|
assertEquals(layout.getPoints()[0].x, 0, 0); |
||||||
|
assertEquals(layout.getPoints()[0].y, 0, 0); |
||||||
|
assertEquals(layout.getPoints()[1].x, 0, 0); |
||||||
|
assertEquals(layout.getPoints()[1].y, 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testScrollDisabled() { |
||||||
|
layout.enable(false); |
||||||
|
touch.listen(); |
||||||
|
touch.start(); |
||||||
|
onLayout().perform(swipeUp()); |
||||||
|
Gesture found = touch.await(500, TimeUnit.MILLISECONDS); |
||||||
|
assertNull(found); |
||||||
|
} |
||||||
|
|
||||||
|
private void testScroll(ViewAction scroll, Gesture expected, boolean increasing) { |
||||||
|
touch.listen(); |
||||||
|
touch.start(); |
||||||
|
onLayout().perform(scroll); |
||||||
|
Gesture found = touch.await(500, TimeUnit.MILLISECONDS); |
||||||
|
assertEquals(found, expected); |
||||||
|
|
||||||
|
// How will this move our parameter?
|
||||||
|
float curr = 0.5f, min = 0f, max = 1f; |
||||||
|
float newValue = layout.scaleValue(curr, min, max); |
||||||
|
if (increasing) { |
||||||
|
assertTrue(newValue > curr); |
||||||
|
assertTrue(newValue <= max); |
||||||
|
} else { |
||||||
|
assertTrue(newValue < curr); |
||||||
|
assertTrue(newValue >= min); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testScrollLeft() { |
||||||
|
testScroll(swipeLeft(), Gesture.SCROLL_HORIZONTAL, false); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testScrollRight() { |
||||||
|
testScroll(swipeRight(), Gesture.SCROLL_HORIZONTAL, true); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testScrollUp() { |
||||||
|
testScroll(swipeUp(), Gesture.SCROLL_VERTICAL, true); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testScrollDown() { |
||||||
|
testScroll(swipeDown(), Gesture.SCROLL_VERTICAL, false); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.support.test.filters.SmallTest; |
||||||
|
import android.support.test.runner.AndroidJUnit4; |
||||||
|
import android.view.ViewGroup; |
||||||
|
|
||||||
|
import org.junit.runner.RunWith; |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class) |
||||||
|
@SmallTest |
||||||
|
public class SurfaceViewPreviewTest extends PreviewTest { |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Preview createPreview(Context context, ViewGroup parent, Preview.SurfaceCallback callback) { |
||||||
|
return new SurfaceViewPreview(context, parent, callback); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,81 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.support.test.espresso.action.GeneralClickAction; |
||||||
|
import android.support.test.espresso.action.GeneralLocation; |
||||||
|
import android.support.test.espresso.action.Press; |
||||||
|
import android.support.test.espresso.action.Tap; |
||||||
|
import android.support.test.filters.SmallTest; |
||||||
|
import android.support.test.runner.AndroidJUnit4; |
||||||
|
import android.view.InputDevice; |
||||||
|
import android.view.MotionEvent; |
||||||
|
|
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
import static android.support.test.espresso.Espresso.*; |
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.*; |
||||||
|
import static android.support.test.espresso.action.ViewActions.*; |
||||||
|
import static org.junit.Assert.*; |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class) |
||||||
|
@SmallTest |
||||||
|
public class TapGestureLayoutTest extends GestureLayoutTest<TapGestureLayout> { |
||||||
|
|
||||||
|
@Override |
||||||
|
protected TapGestureLayout create(Context context) { |
||||||
|
return new TapGestureLayout(context); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDefaults() { |
||||||
|
assertNull(layout.getGestureType()); |
||||||
|
assertEquals(layout.getPoints().length, 1); |
||||||
|
assertEquals(layout.getPoints()[0].x, 0, 0); |
||||||
|
assertEquals(layout.getPoints()[0].y, 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testTap() { |
||||||
|
touch.listen(); |
||||||
|
touch.start(); |
||||||
|
GeneralClickAction a = new GeneralClickAction( |
||||||
|
Tap.SINGLE, GeneralLocation.CENTER, Press.FINGER, |
||||||
|
InputDevice.SOURCE_UNKNOWN, MotionEvent.BUTTON_PRIMARY); |
||||||
|
onLayout().perform(a); |
||||||
|
Gesture found = touch.await(500, TimeUnit.MILLISECONDS); |
||||||
|
|
||||||
|
assertEquals(found, Gesture.TAP); |
||||||
|
Size size = rule.getActivity().getContentSize(); |
||||||
|
assertEquals(layout.getPoints()[0].x, (size.getWidth() / 2f), 1f); |
||||||
|
assertEquals(layout.getPoints()[0].y, (size.getHeight() / 2f), 1f); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testTapWhileDisabled() { |
||||||
|
layout.enable(false); |
||||||
|
touch.listen(); |
||||||
|
touch.start(); |
||||||
|
onLayout().perform(click()); |
||||||
|
Gesture found = touch.await(500, TimeUnit.MILLISECONDS); |
||||||
|
assertNull(found); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testLongTap() { |
||||||
|
touch.listen(); |
||||||
|
touch.start(); |
||||||
|
GeneralClickAction a = new GeneralClickAction( |
||||||
|
Tap.LONG, GeneralLocation.CENTER, Press.FINGER, |
||||||
|
InputDevice.SOURCE_UNKNOWN, MotionEvent.BUTTON_PRIMARY); |
||||||
|
onLayout().perform(a); |
||||||
|
Gesture found = touch.await(500, TimeUnit.MILLISECONDS); |
||||||
|
assertEquals(found, Gesture.LONG_TAP); |
||||||
|
Size size = rule.getActivity().getContentSize(); |
||||||
|
assertEquals(layout.getPoints()[0].x, (size.getWidth() / 2f), 1f); |
||||||
|
assertEquals(layout.getPoints()[0].y, (size.getHeight() / 2f), 1f); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,75 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.app.Activity; |
||||||
|
import android.app.KeyguardManager; |
||||||
|
import android.content.Context; |
||||||
|
import android.graphics.Point; |
||||||
|
import android.os.Bundle; |
||||||
|
import android.os.PersistableBundle; |
||||||
|
import android.support.annotation.Nullable; |
||||||
|
import android.view.Gravity; |
||||||
|
import android.view.View; |
||||||
|
import android.view.ViewGroup; |
||||||
|
import android.view.WindowManager; |
||||||
|
import android.widget.FrameLayout; |
||||||
|
|
||||||
|
import static android.view.ViewGroup.LayoutParams.*; |
||||||
|
|
||||||
|
public class TestActivity extends Activity { |
||||||
|
|
||||||
|
private ViewGroup content; |
||||||
|
private Size contentSize = new Size(1000, 1000); |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) { |
||||||
|
super.onCreate(savedInstanceState); |
||||||
|
wakeScreen(); |
||||||
|
|
||||||
|
// Match parent decor view.
|
||||||
|
FrameLayout root = new FrameLayout(this); |
||||||
|
root.setKeepScreenOn(true); |
||||||
|
root.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); |
||||||
|
|
||||||
|
// Inner content view with fixed size.
|
||||||
|
// We want it to be fully visible or expresso will crash.
|
||||||
|
Point size = new Point(); |
||||||
|
getWindowManager().getDefaultDisplay().getSize(size); |
||||||
|
int width = Math.min(size.x, size.y); |
||||||
|
int height = Math.min(size.x, size.y); |
||||||
|
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( |
||||||
|
width, height, Gravity.CENTER); |
||||||
|
content = new FrameLayout(this); |
||||||
|
content.setLayoutParams(params); |
||||||
|
contentSize = new Size(width, height); |
||||||
|
|
||||||
|
// Add.
|
||||||
|
root.addView(content); |
||||||
|
setContentView(root); |
||||||
|
} |
||||||
|
|
||||||
|
public void wakeScreen() { |
||||||
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
||||||
|
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
||||||
|
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
||||||
|
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
||||||
|
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON); |
||||||
|
} |
||||||
|
|
||||||
|
public Size getContentSize() { |
||||||
|
return contentSize; |
||||||
|
} |
||||||
|
|
||||||
|
public ViewGroup getContentView() { |
||||||
|
return content; |
||||||
|
} |
||||||
|
|
||||||
|
public void inflate(View child) { |
||||||
|
inflate(child, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); |
||||||
|
} |
||||||
|
|
||||||
|
public void inflate(View child, ViewGroup.LayoutParams params) { |
||||||
|
content.addView(child, params); |
||||||
|
content.requestLayout(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.support.test.filters.SmallTest; |
||||||
|
import android.support.test.runner.AndroidJUnit4; |
||||||
|
import android.view.ViewGroup; |
||||||
|
|
||||||
|
import org.junit.runner.RunWith; |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class) |
||||||
|
@SmallTest |
||||||
|
public class TextureViewPreviewTest extends PreviewTest { |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Preview createPreview(Context context, ViewGroup parent, Preview.SurfaceCallback callback) { |
||||||
|
return new TextureViewPreview(context, parent, callback); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void ensureAvailable() { |
||||||
|
if (isHardwareAccelerated()) { |
||||||
|
super.ensureAvailable(); |
||||||
|
} else { |
||||||
|
preview.onSurfaceAvailable( |
||||||
|
surfaceSize.getWidth(), |
||||||
|
surfaceSize.getHeight()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void ensureDestroyed() { |
||||||
|
super.ensureDestroyed(); |
||||||
|
if (!isHardwareAccelerated()) { |
||||||
|
// Ensure it is called.
|
||||||
|
preview.onSurfaceDestroyed(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isHardwareAccelerated() { |
||||||
|
return preview.getView().isHardwareAccelerated(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
package com.otaliastudios.cameraview; |
||||||
|
|
||||||
|
import android.support.annotation.NonNull; |
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch; |
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
/** |
||||||
|
* A naive implementation of {@link java.util.concurrent.CountDownLatch} |
||||||
|
* to help in testing. |
||||||
|
*/ |
||||||
|
class Task<T> { |
||||||
|
|
||||||
|
private CountDownLatch mLatch; |
||||||
|
private T mResult; |
||||||
|
private int mCount; |
||||||
|
|
||||||
|
Task() { |
||||||
|
} |
||||||
|
|
||||||
|
private boolean listening() { |
||||||
|
return mLatch != null; |
||||||
|
} |
||||||
|
|
||||||
|
void listen() { |
||||||
|
if (listening()) throw new RuntimeException("Should not happen."); |
||||||
|
mResult = null; |
||||||
|
mLatch = new CountDownLatch(1); |
||||||
|
} |
||||||
|
|
||||||
|
void start() { |
||||||
|
if (!listening()) mCount++; |
||||||
|
} |
||||||
|
|
||||||
|
void end(T result) { |
||||||
|
if (mCount > 0) { |
||||||
|
mCount--; |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (listening()) { // Should be always true.
|
||||||
|
mResult = result; |
||||||
|
mLatch.countDown(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
T await() { |
||||||
|
try { |
||||||
|
mLatch.await(); |
||||||
|
} catch (Exception e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
T result = mResult; |
||||||
|
mResult = null; |
||||||
|
mLatch = null; |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
T await(long time, @NonNull TimeUnit unit) { |
||||||
|
try { |
||||||
|
mLatch.await(time, unit); |
||||||
|
} catch (Exception e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
T result = mResult; |
||||||
|
mResult = null; |
||||||
|
mLatch = null; |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue