Simplify GestureLayouts, now simple classes

pull/494/head
Mattia Iavarone 6 years ago
parent 64714017b8
commit c617a7da2a
  1. 6
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraViewCallbacksTest.java
  2. 26
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraViewTest.java
  3. 43
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/gesture/GestureFinderTest.java
  4. 31
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/gesture/PinchGestureFinderTest.java
  5. 39
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/gesture/ScrollGestureFinderTest.java
  6. 47
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/gesture/TapGestureFinderTest.java
  7. 94
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  8. 19
      cameraview/src/main/java/com/otaliastudios/cameraview/gesture/GestureFinder.java
  9. 13
      cameraview/src/main/java/com/otaliastudios/cameraview/gesture/PinchGestureFinder.java
  10. 15
      cameraview/src/main/java/com/otaliastudios/cameraview/gesture/ScrollGestureFinder.java
  11. 22
      cameraview/src/main/java/com/otaliastudios/cameraview/gesture/TapGestureFinder.java

@ -195,7 +195,7 @@ public class CameraViewCallbacksTest extends BaseTest {
@Test
public void testDispatchOnFocusStart() {
// Enable tap gesture.
// Can't mock package protected. camera.mTapGestureLayout = mock(TapGestureLayout.class);
// Can't mock package protected. camera.mTapGestureFinder = mock(TapGestureLayout.class);
camera.mapGesture(Gesture.TAP, GestureAction.AUTO_FOCUS);
AutoFocusMarker marker = mock(AutoFocusMarker.class);
MarkerLayout markerLayout = mock(MarkerLayout.class);
@ -215,7 +215,7 @@ public class CameraViewCallbacksTest extends BaseTest {
@Test
public void testDispatchOnFocusEnd() {
// Enable tap gesture.
// Can't mock package protected. camera.mTapGestureLayout = mock(TapGestureLayout.class);
// Can't mock package protected. camera.mTapGestureFinder = mock(TapGestureLayout.class);
camera.mapGesture(Gesture.TAP, GestureAction.AUTO_FOCUS);
AutoFocusMarker marker = mock(AutoFocusMarker.class);
camera.setAutoFocusMarker(marker);
@ -229,7 +229,7 @@ public class CameraViewCallbacksTest extends BaseTest {
verify(listener, times(1)).onAutoFocusEnd(success, point);
verify(marker, times(1)).onAutoFocusEnd(AutoFocusTrigger.GESTURE, success, point);
// Can't mock package protected. verify(camera.mTapGestureLayout, times(1)).onAutoFocusEnd(success);
// Can't mock package protected. verify(camera.mTapGestureFinder, times(1)).onAutoFocusEnd(success);
}
@Test

@ -28,9 +28,9 @@ import com.otaliastudios.cameraview.controls.Mode;
import com.otaliastudios.cameraview.controls.VideoCodec;
import com.otaliastudios.cameraview.controls.WhiteBalance;
import com.otaliastudios.cameraview.gesture.GestureParser;
import com.otaliastudios.cameraview.gesture.PinchGestureLayout;
import com.otaliastudios.cameraview.gesture.ScrollGestureLayout;
import com.otaliastudios.cameraview.gesture.TapGestureLayout;
import com.otaliastudios.cameraview.gesture.PinchGestureFinder;
import com.otaliastudios.cameraview.gesture.ScrollGestureFinder;
import com.otaliastudios.cameraview.gesture.TapGestureFinder;
import com.otaliastudios.cameraview.engine.MockCameraEngine;
import com.otaliastudios.cameraview.internal.utils.Op;
import com.otaliastudios.cameraview.markers.AutoFocusMarker;
@ -201,21 +201,21 @@ public class CameraViewTest extends BaseTest {
// PinchGestureLayout
cameraView.mapGesture(Gesture.PINCH, GestureAction.ZOOM);
assertTrue(cameraView.mPinchGestureLayout.isActive());
assertTrue(cameraView.mPinchGestureFinder.isActive());
cameraView.clearGesture(Gesture.PINCH);
assertFalse(cameraView.mPinchGestureLayout.isActive());
assertFalse(cameraView.mPinchGestureFinder.isActive());
// TapGestureLayout
cameraView.mapGesture(Gesture.TAP, GestureAction.TAKE_PICTURE);
assertTrue(cameraView.mTapGestureLayout.isActive());
assertTrue(cameraView.mTapGestureFinder.isActive());
cameraView.clearGesture(Gesture.TAP);
assertFalse(cameraView.mPinchGestureLayout.isActive());
assertFalse(cameraView.mPinchGestureFinder.isActive());
// ScrollGestureLayout
cameraView.mapGesture(Gesture.SCROLL_HORIZONTAL, GestureAction.ZOOM);
assertTrue(cameraView.mScrollGestureLayout.isActive());
assertTrue(cameraView.mScrollGestureFinder.isActive());
cameraView.clearGesture(Gesture.SCROLL_HORIZONTAL);
assertFalse(cameraView.mScrollGestureLayout.isActive());
assertFalse(cameraView.mScrollGestureFinder.isActive());
}
//endregion
@ -231,7 +231,7 @@ public class CameraViewTest extends BaseTest {
ui(new Runnable() {
@Override
public void run() {
cameraView.mTapGestureLayout = new TapGestureLayout(cameraView.getContext()) {
cameraView.mTapGestureFinder = new TapGestureFinder(cameraView.getContext()) {
protected boolean handleTouchEvent(@NonNull MotionEvent event) {
setGesture(Gesture.TAP);
return true;
@ -253,7 +253,7 @@ public class CameraViewTest extends BaseTest {
ui(new Runnable() {
@Override
public void run() {
cameraView.mTapGestureLayout = new TapGestureLayout(cameraView.getContext()) {
cameraView.mTapGestureFinder = new TapGestureFinder(cameraView.getContext()) {
protected boolean handleTouchEvent(@NonNull MotionEvent event) {
setGesture(Gesture.TAP);
return true;
@ -280,7 +280,7 @@ public class CameraViewTest extends BaseTest {
ui(new Runnable() {
@Override
public void run() {
cameraView.mPinchGestureLayout = new PinchGestureLayout(cameraView.getContext()) {
cameraView.mPinchGestureFinder = new PinchGestureFinder(cameraView.getContext()) {
@Override
protected boolean handleTouchEvent(@NonNull MotionEvent event) {
setGesture(Gesture.PINCH);
@ -321,7 +321,7 @@ public class CameraViewTest extends BaseTest {
ui(new Runnable() {
@Override
public void run() {
cameraView.mScrollGestureLayout = new ScrollGestureLayout(cameraView.getContext()) {
cameraView.mScrollGestureFinder = new ScrollGestureFinder(cameraView.getContext()) {
@Override
protected boolean handleTouchEvent(@NonNull MotionEvent event) {
setGesture(Gesture.SCROLL_HORIZONTAL);

@ -4,11 +4,14 @@ package com.otaliastudios.cameraview.gesture;
import android.annotation.TargetApi;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.test.espresso.ViewInteraction;
import androidx.test.espresso.matcher.RootMatchers;
import androidx.test.rule.ActivityTestRule;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.otaliastudios.cameraview.BaseTest;
import com.otaliastudios.cameraview.TestActivity;
@ -21,17 +24,19 @@ import org.junit.Rule;
import static androidx.test.espresso.Espresso.onView;
@TargetApi(17)
public abstract class GestureLayoutTest<T extends GestureLayout> extends BaseTest {
public abstract class GestureFinderTest<T extends GestureFinder> extends BaseTest {
protected abstract T create(Context context);
protected abstract T createFinder(@NonNull GestureFinder.Controller controller);
@Rule
public ActivityTestRule<TestActivity> rule = new ActivityTestRule<>(TestActivity.class);
@SuppressWarnings("WeakerAccess")
protected T layout;
protected T finder;
@SuppressWarnings("WeakerAccess")
protected Op<Gesture> touch;
protected Op<Gesture> touchOp;
@SuppressWarnings("WeakerAccess")
protected ViewGroup layout;
@Before
public void setUp() {
@ -39,16 +44,17 @@ public abstract class GestureLayoutTest<T extends GestureLayout> extends BaseTes
@Override
public void run() {
TestActivity a = rule.getActivity();
layout = create(a);
layout.setActive(true);
layout = new FrameLayout(a);
finder = createFinder(new Controller());
finder.setActive(true);
a.inflate(layout);
touch = new Op<>();
touchOp = new Op<>();
layout.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
boolean found = layout.onTouchEvent(motionEvent);
if (found) touch.end(layout.getGesture());
boolean found = finder.onTouchEvent(motionEvent);
if (found) touchOp.end(finder.getGesture());
return true;
}
});
@ -62,4 +68,23 @@ public abstract class GestureLayoutTest<T extends GestureLayout> extends BaseTes
.inRoot(RootMatchers.withDecorView(
Matchers.is(rule.getActivity().getWindow().getDecorView())));
}
private class Controller implements GestureFinder.Controller {
@NonNull
@Override
public Context getContext() {
return layout.getContext();
}
@Override
public int getWidth() {
return layout.getWidth();
}
@Override
public int getHeight() {
return layout.getHeight();
}
}
}

@ -3,10 +3,7 @@ package com.otaliastudios.cameraview.gesture;
import android.content.Context;
import com.otaliastudios.cameraview.gesture.Gesture;
import com.otaliastudios.cameraview.gesture.GestureLayoutTest;
import com.otaliastudios.cameraview.gesture.PinchGestureLayout;
import androidx.annotation.NonNull;
import androidx.test.espresso.ViewAction;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@ -22,21 +19,21 @@ import static org.junit.Assert.assertTrue;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class PinchGestureLayoutTest extends GestureLayoutTest<PinchGestureLayout> {
public class PinchGestureFinderTest extends GestureFinderTest<PinchGestureFinder> {
@Override
protected PinchGestureLayout create(Context context) {
return new PinchGestureLayout(context);
protected PinchGestureFinder createFinder(@NonNull GestureFinder.Controller controller) {
return new PinchGestureFinder(controller);
}
@Test
public void testDefaults() {
assertEquals(layout.getGesture(), 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);
assertEquals(finder.getGesture(), Gesture.PINCH);
assertEquals(finder.getPoints().length, 2);
assertEquals(finder.getPoints()[0].x, 0, 0);
assertEquals(finder.getPoints()[0].y, 0, 0);
assertEquals(finder.getPoints()[1].x, 0, 0);
assertEquals(finder.getPoints()[1].y, 0, 0);
}
// TODO: test pinch open
@ -51,15 +48,15 @@ public class PinchGestureLayoutTest extends GestureLayoutTest<PinchGestureLayout
}
private void testPinch(ViewAction action, boolean increasing) {
touch.listen();
touch.start();
touchOp.listen();
touchOp.start();
onLayout().perform(action);
Gesture found = touch.await(10000);
Gesture found = touchOp.await(10000);
assertNotNull(found);
// How will this move our parameter?
float curr = 0.5f, min = 0f, max = 1f;
float newValue = layout.computeValue(curr, min, max);
float newValue = finder.computeValue(curr, min, max);
if (increasing) {
assertTrue(newValue > curr);
assertTrue(newValue <= max);

@ -3,10 +3,7 @@ package com.otaliastudios.cameraview.gesture;
import android.content.Context;
import com.otaliastudios.cameraview.gesture.Gesture;
import com.otaliastudios.cameraview.gesture.GestureLayoutTest;
import com.otaliastudios.cameraview.gesture.ScrollGestureLayout;
import androidx.annotation.NonNull;
import androidx.test.espresso.ViewAction;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@ -27,43 +24,43 @@ import static org.junit.Assert.assertTrue;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class ScrollGestureLayoutTest extends GestureLayoutTest<ScrollGestureLayout> {
public class ScrollGestureFinderTest extends GestureFinderTest<ScrollGestureFinder> {
@Override
protected ScrollGestureLayout create(Context context) {
return new ScrollGestureLayout(context);
protected ScrollGestureFinder createFinder(@NonNull GestureFinder.Controller controller) {
return new ScrollGestureFinder(controller);
}
@Test
public void testDefaults() {
assertNull(layout.getGesture());
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);
assertNull(finder.getGesture());
assertEquals(finder.getPoints().length, 2);
assertEquals(finder.getPoints()[0].x, 0, 0);
assertEquals(finder.getPoints()[0].y, 0, 0);
assertEquals(finder.getPoints()[1].x, 0, 0);
assertEquals(finder.getPoints()[1].y, 0, 0);
}
@Test
public void testScrollDisabled() {
layout.setActive(false);
touch.listen();
touch.start();
finder.setActive(false);
touchOp.listen();
touchOp.start();
onLayout().perform(swipeUp());
Gesture found = touch.await(500);
Gesture found = touchOp.await(500);
assertNull(found);
}
private void testScroll(ViewAction scroll, Gesture expected, boolean increasing) {
touch.listen();
touch.start();
touchOp.listen();
touchOp.start();
onLayout().perform(scroll);
Gesture found = touch.await(500);
Gesture found = touchOp.await(500);
assertEquals(found, expected);
// How will this move our parameter?
float curr = 0.5f, min = 0f, max = 1f;
float newValue = layout.computeValue(curr, min, max);
float newValue = finder.computeValue(curr, min, max);
if (increasing) {
assertTrue(newValue >= curr);
assertTrue(newValue <= max);

@ -2,6 +2,8 @@ package com.otaliastudios.cameraview.gesture;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.test.espresso.action.GeneralClickAction;
import androidx.test.espresso.action.GeneralLocation;
import androidx.test.espresso.action.Press;
@ -11,9 +13,6 @@ import androidx.test.filters.SmallTest;
import android.view.InputDevice;
import android.view.MotionEvent;
import com.otaliastudios.cameraview.gesture.Gesture;
import com.otaliastudios.cameraview.gesture.GestureLayoutTest;
import com.otaliastudios.cameraview.gesture.TapGestureLayout;
import com.otaliastudios.cameraview.size.Size;
import org.junit.Test;
@ -24,59 +23,59 @@ import static org.junit.Assert.*;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class TapGestureLayoutTest extends GestureLayoutTest<TapGestureLayout> {
public class TapGestureFinderTest extends GestureFinderTest<TapGestureFinder> {
@Override
protected TapGestureLayout create(Context context) {
return new TapGestureLayout(context);
protected TapGestureFinder createFinder(@NonNull GestureFinder.Controller controller) {
return new TapGestureFinder(controller);
}
@Test
public void testDefaults() {
assertNull(layout.getGesture());
assertEquals(layout.getPoints().length, 1);
assertEquals(layout.getPoints()[0].x, 0, 0);
assertEquals(layout.getPoints()[0].y, 0, 0);
assertNull(finder.getGesture());
assertEquals(finder.getPoints().length, 1);
assertEquals(finder.getPoints()[0].x, 0, 0);
assertEquals(finder.getPoints()[0].y, 0, 0);
}
@Test
public void testTap() {
touch.listen();
touch.start();
touchOp.listen();
touchOp.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);
Gesture found = touchOp.await(500);
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);
assertEquals(finder.getPoints()[0].x, (size.getWidth() / 2f), 1f);
assertEquals(finder.getPoints()[0].y, (size.getHeight() / 2f), 1f);
}
@Test
public void testTapWhileDisabled() {
layout.setActive(false);
touch.listen();
touch.start();
finder.setActive(false);
touchOp.listen();
touchOp.start();
onLayout().perform(click());
Gesture found = touch.await(500);
Gesture found = touchOp.await(500);
assertNull(found);
}
@Test
public void testLongTap() {
touch.listen();
touch.start();
touchOp.listen();
touchOp.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);
Gesture found = touchOp.await(500);
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);
assertEquals(finder.getPoints()[0].x, (size.getWidth() / 2f), 1f);
assertEquals(finder.getPoints()[0].y, (size.getHeight() / 2f), 1f);
}
}

@ -50,11 +50,11 @@ import com.otaliastudios.cameraview.controls.Mode;
import com.otaliastudios.cameraview.controls.Preview;
import com.otaliastudios.cameraview.controls.VideoCodec;
import com.otaliastudios.cameraview.controls.WhiteBalance;
import com.otaliastudios.cameraview.gesture.GestureLayout;
import com.otaliastudios.cameraview.gesture.GestureFinder;
import com.otaliastudios.cameraview.gesture.GestureParser;
import com.otaliastudios.cameraview.gesture.PinchGestureLayout;
import com.otaliastudios.cameraview.gesture.ScrollGestureLayout;
import com.otaliastudios.cameraview.gesture.TapGestureLayout;
import com.otaliastudios.cameraview.gesture.PinchGestureFinder;
import com.otaliastudios.cameraview.gesture.ScrollGestureFinder;
import com.otaliastudios.cameraview.gesture.TapGestureFinder;
import com.otaliastudios.cameraview.internal.GridLinesLayout;
import com.otaliastudios.cameraview.internal.utils.CropHelper;
import com.otaliastudios.cameraview.internal.utils.OrientationHelper;
@ -115,11 +115,13 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
@VisibleForTesting List<FrameProcessor> mFrameProcessors = new CopyOnWriteArrayList<>();
private Lifecycle mLifecycle;
// Gestures
@VisibleForTesting PinchGestureFinder mPinchGestureFinder;
@VisibleForTesting TapGestureFinder mTapGestureFinder;
@VisibleForTesting ScrollGestureFinder mScrollGestureFinder;
// Views
GridLinesLayout mGridLinesLayout;
PinchGestureLayout mPinchGestureLayout;
TapGestureLayout mTapGestureLayout;
ScrollGestureLayout mScrollGestureLayout;
MarkerLayout mMarkerLayout;
private boolean mKeepScreenOn;
@SuppressWarnings({"FieldCanBeLocal", "unused"})
@ -173,16 +175,15 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
mUiHandler = new Handler(Looper.getMainLooper());
mFrameProcessorsHandler = WorkerHandler.get("FrameProcessorsWorker");
// Gestures
mPinchGestureFinder = new PinchGestureFinder(mCameraCallbacks);
mTapGestureFinder = new TapGestureFinder(mCameraCallbacks);
mScrollGestureFinder = new ScrollGestureFinder(mCameraCallbacks);
// Views
mGridLinesLayout = new GridLinesLayout(context);
mPinchGestureLayout = new PinchGestureLayout(context);
mTapGestureLayout = new TapGestureLayout(context);
mScrollGestureLayout = new ScrollGestureLayout(context);
mMarkerLayout = new MarkerLayout(context);
addView(mGridLinesLayout);
addView(mPinchGestureLayout);
addView(mTapGestureLayout);
addView(mScrollGestureLayout);
addView(mMarkerLayout);
// Create the engine
@ -225,6 +226,26 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
}
/**
* Engine is instantiated on creation and anytime
* {@link #setEngine(Engine)} is called.
*/
private void doInstantiateEngine() {
mCameraEngine = instantiateCameraEngine(mEngine, mCameraCallbacks);
}
/**
* Preview is instantiated {@link #onAttachedToWindow()}, because
* we want to know if we're hardware accelerated or not.
* However, in tests, we might want to create the preview right after constructor.
*/
@VisibleForTesting
void doInstantiatePreview() {
mCameraPreview = instantiatePreview(mPreview, getContext(), this);
mCameraEngine.setPreview(mCameraPreview);
}
/**
* Instantiates the camera engine.
*
@ -269,16 +290,6 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
}
@VisibleForTesting
void doInstantiatePreview() {
mCameraPreview = instantiatePreview(mPreview, getContext(), this);
mCameraEngine.setPreview(mCameraPreview);
}
private void doInstantiateEngine() {
mCameraEngine = instantiateCameraEngine(mEngine, mCameraCallbacks);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
@ -474,19 +485,19 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
mGestureMap.put(gesture, action);
switch (gesture) {
case PINCH:
mPinchGestureLayout.setActive(mGestureMap.get(Gesture.PINCH) != none);
mPinchGestureFinder.setActive(mGestureMap.get(Gesture.PINCH) != none);
break;
case TAP:
// case DOUBLE_TAP:
case LONG_TAP:
mTapGestureLayout.setActive(
mTapGestureFinder.setActive(
mGestureMap.get(Gesture.TAP) != none ||
// mGestureMap.get(Gesture.DOUBLE_TAP) != none ||
mGestureMap.get(Gesture.LONG_TAP) != none);
break;
case SCROLL_HORIZONTAL:
case SCROLL_VERTICAL:
mScrollGestureLayout.setActive(
mScrollGestureFinder.setActive(
mGestureMap.get(Gesture.SCROLL_HORIZONTAL) != none ||
mGestureMap.get(Gesture.SCROLL_VERTICAL) != none);
break;
@ -534,15 +545,15 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
// Pass to our own GestureLayouts
CameraOptions options = mCameraEngine.getCameraOptions(); // Non null
if (options == null) throw new IllegalStateException("Options should not be null here.");
if (mPinchGestureLayout.onTouchEvent(event)) {
if (mPinchGestureFinder.onTouchEvent(event)) {
LOG.i("onTouchEvent", "pinch!");
onGesture(mPinchGestureLayout, options);
} else if (mScrollGestureLayout.onTouchEvent(event)) {
onGesture(mPinchGestureFinder, options);
} else if (mScrollGestureFinder.onTouchEvent(event)) {
LOG.i("onTouchEvent", "scroll!");
onGesture(mScrollGestureLayout, options);
} else if (mTapGestureLayout.onTouchEvent(event)) {
onGesture(mScrollGestureFinder, options);
} else if (mTapGestureFinder.onTouchEvent(event)) {
LOG.i("onTouchEvent", "tap!");
onGesture(mTapGestureLayout, options);
onGesture(mTapGestureFinder, options);
}
return true;
}
@ -551,7 +562,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
// Some gesture layout detected a gesture. It's not known at this moment:
// (1) if it was mapped to some action (we check here)
// (2) if it's supported by the camera (CameraEngine checks)
private void onGesture(GestureLayout source, @NonNull CameraOptions options) {
private void onGesture(GestureFinder source, @NonNull CameraOptions options) {
Gesture gesture = source.getGesture();
GestureAction action = mGestureMap.get(gesture);
PointF[] points = source.getPoints();
@ -1732,7 +1743,10 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
//region Callbacks and dispatching
@VisibleForTesting
class CameraCallbacks implements CameraEngine.Callback, OrientationHelper.Callback {
class CameraCallbacks implements
CameraEngine.Callback,
OrientationHelper.Callback,
GestureFinder.Controller {
private CameraLogger mLogger = CameraLogger.create(CameraCallbacks.class.getSimpleName());
@ -1742,6 +1756,16 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
return CameraView.this.getContext();
}
@Override
public int getWidth() {
return CameraView.this.getWidth();
}
@Override
public int getHeight() {
return CameraView.this.getHeight();
}
@Override
public void dispatchOnCameraOpened(final CameraOptions options) {
mLogger.i("dispatchOnCameraOpened", options);
@ -1786,7 +1810,6 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
@Override
public void onShutter(boolean shouldPlaySound) {
if (shouldPlaySound && mPlaySounds) {
//noinspection all
playSound(MediaActionSound.SHUTTER_CLICK);
}
}
@ -1847,7 +1870,6 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
@Override
public void run() {
if (success && mPlaySounds) {
//noinspection all
playSound(MediaActionSound.FOCUS_COMPLETE);
}

@ -7,20 +7,28 @@ import android.view.MotionEvent;
import android.widget.FrameLayout;
/**
* Base class for gesture layouts, that is, layouts that will capture
* gestures.
* Base class for gesture finders.
* Gesture finders are passed down touch events to detect gestures.
*/
public abstract class GestureLayout extends FrameLayout {
public abstract class GestureFinder {
public interface Controller {
@NonNull Context getContext();
int getWidth();
int getHeight();
}
// The number of possible values between minValue and maxValue, for the getValue method.
// We could make this non-static (e.g. larger granularity for exposure correction).
private final static int GRANULARITY = 50;
private boolean mActive;
private Gesture mType;
private PointF[] mPoints;
private Controller mController;
GestureLayout(@NonNull Context context, int points) {
super(context);
GestureFinder(@NonNull Controller controller, int points) {
mController = controller;
mPoints = new PointF[points];
for (int i = 0; i < points; i++) {
mPoints[i] = new PointF(0, 0);
@ -108,6 +116,7 @@ public abstract class GestureLayout extends FrameLayout {
* @param which the array position
* @return the point
*/
@SuppressWarnings("WeakerAccess")
@NonNull
protected final PointF getPoint(int which) {
return mPoints[which];

@ -1,26 +1,25 @@
package com.otaliastudios.cameraview.gesture;
import android.content.Context;
import android.os.Build;
import androidx.annotation.NonNull;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
/**
* A {@link GestureLayout} that detects {@link Gesture#PINCH} gestures.
* A {@link GestureFinder} that detects {@link Gesture#PINCH} gestures.
*/
public class PinchGestureLayout extends GestureLayout {
public class PinchGestureFinder extends GestureFinder {
private final static float ADD_SENSITIVITY = 2f;
ScaleGestureDetector mDetector;
private ScaleGestureDetector mDetector;
private boolean mNotify;
private float mFactor = 0;
public PinchGestureLayout(@NonNull Context context) {
super(context, 2);
public PinchGestureFinder(@NonNull Controller controller) {
super(controller, 2);
setGesture(Gesture.PINCH);
mDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.SimpleOnScaleGestureListener() {
mDetector = new ScaleGestureDetector(controller.getContext(), new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector detector) {
mNotify = true;

@ -1,6 +1,5 @@
package com.otaliastudios.cameraview.gesture;
import android.content.Context;
import androidx.annotation.NonNull;
import android.view.GestureDetector;
import android.view.MotionEvent;
@ -8,21 +7,21 @@ import android.view.MotionEvent;
import com.otaliastudios.cameraview.CameraLogger;
/**
* A {@link GestureLayout} that detects {@link Gesture#SCROLL_HORIZONTAL}
* A {@link GestureFinder} that detects {@link Gesture#SCROLL_HORIZONTAL}
* and {@link Gesture#SCROLL_VERTICAL} gestures.
*/
public class ScrollGestureLayout extends GestureLayout {
public class ScrollGestureFinder extends GestureFinder {
private static final String TAG = ScrollGestureLayout.class.getSimpleName();
private static final String TAG = ScrollGestureFinder.class.getSimpleName();
private static final CameraLogger LOG = CameraLogger.create(TAG);
private GestureDetector mDetector;
private boolean mNotify;
private float mFactor;
public ScrollGestureLayout(@NonNull Context context) {
super(context, 2);
mDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
public ScrollGestureFinder(final @NonNull Controller controller) {
super(controller, 2);
mDetector = new GestureDetector(controller.getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
@ -40,7 +39,7 @@ public class ScrollGestureLayout extends GestureLayout {
horizontal = getGesture() == Gesture.SCROLL_HORIZONTAL;
}
getPoint(1).set(e2.getX(), e2.getY());
mFactor = horizontal ? (distanceX / getWidth()) : (distanceY / getHeight());
mFactor = horizontal ? (distanceX / controller.getWidth()) : (distanceY / controller.getHeight());
mFactor = horizontal ? -mFactor : mFactor; // When vertical, up = positive
mNotify = true;
return true;

@ -1,32 +1,22 @@
package com.otaliastudios.cameraview.gesture;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.graphics.PointF;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.otaliastudios.cameraview.R;
/**
* A {@link GestureLayout} that detects {@link Gesture#TAP}
* A {@link GestureFinder} that detects {@link Gesture#TAP}
* and {@link Gesture#LONG_TAP} gestures.
*/
public class TapGestureLayout extends GestureLayout {
public class TapGestureFinder extends GestureFinder {
private GestureDetector mDetector;
private boolean mNotify;
public TapGestureLayout(@NonNull Context context) {
super(context, 1);
mDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
public TapGestureFinder(@NonNull Controller controller) {
super(controller, 1);
mDetector = new GestureDetector(controller.getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
Loading…
Cancel
Save