diff --git a/hover/src/main/java/io/mattcarroll/hover/BaseTouchController.java b/hover/src/main/java/io/mattcarroll/hover/BaseTouchController.java new file mode 100644 index 0000000..e69bde4 --- /dev/null +++ b/hover/src/main/java/io/mattcarroll/hover/BaseTouchController.java @@ -0,0 +1,85 @@ +package io.mattcarroll.hover; + +import android.graphics.PointF; +import android.graphics.Rect; +import android.support.annotation.NonNull; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; + +public abstract class BaseTouchController { + private static final String TAG = "BaseTouchController"; + + protected View mTouchView; + protected TouchListener mTouchListener; + protected boolean mIsActivated; + private boolean mIsDebugMode; + + private View.OnTouchListener mDragTouchListener = new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + switch (motionEvent.getAction()) { + case MotionEvent.ACTION_DOWN: + Log.d(TAG, "ACTION_DOWN"); + mTouchListener.onPress(); + return true; + case MotionEvent.ACTION_UP: + Log.d(TAG, "ACTION_UP"); + mTouchListener.onTap(); + return true; + default: + return false; + } + } + }; + + public abstract View createTouchView(@NonNull Rect rect); + + public abstract void destroyTouchView(@NonNull View touchView); + + public abstract void moveTouchViewTo(@NonNull View touchView, @NonNull PointF position); + + public void activate(@NonNull TouchListener touchListener, @NonNull Rect rect) { + if (!mIsActivated) { + Log.d(TAG, "Activating."); + mIsActivated = true; + mTouchListener = touchListener; + mTouchView = createTouchView(rect); + moveTouchViewTo(mTouchView, new PointF(rect.left, rect.top)); + mTouchView.setOnTouchListener(mDragTouchListener); + + updateTouchControlViewAppearance(); + } + } + + public void deactivate() { + if (mIsActivated) { + Log.d(TAG, "Deactivating."); + mTouchView.setOnTouchListener(null); + destroyTouchView(mTouchView); + mIsActivated = false; + mTouchView = null; + } + } + + public void enableDebugMode(boolean isDebugMode) { + mIsDebugMode = isDebugMode; + updateTouchControlViewAppearance(); + } + + private void updateTouchControlViewAppearance() { + if (null != mTouchView) { + if (mIsDebugMode) { + mTouchView.setBackgroundColor(0x44FF0000); + } else { + mTouchView.setBackgroundColor(0x00000000); + } + } + } + + public interface TouchListener { + void onPress(); + + void onTap(); + } +} diff --git a/hover/src/main/java/io/mattcarroll/hover/Dragger.java b/hover/src/main/java/io/mattcarroll/hover/Dragger.java index 0e2572d..e163cb2 100644 --- a/hover/src/main/java/io/mattcarroll/hover/Dragger.java +++ b/hover/src/main/java/io/mattcarroll/hover/Dragger.java @@ -15,44 +15,115 @@ */ package io.mattcarroll.hover; +import android.graphics.PointF; import android.graphics.Rect; import android.support.annotation.NonNull; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; /** * Reports user drag behavior on the screen to a {@link DragListener}. */ -public interface Dragger { +public abstract class Dragger extends BaseTouchController { + private static final String TAG = "Dragger"; - /** - * Starts reporting user drag behavior given a drag area represented by {@code controlBounds}. - * @param dragListener listener that receives information about drag behavior - * @param rect Rect area to be draggable - */ - void activate(@NonNull DragListener dragListener, @NonNull Rect rect); + private final int mTapTouchSlop; + private DragListener mDragListener; + private boolean mIsDragging; - /** - * Stops monitoring and reporting user drag behavior. - */ - void deactivate(); + private PointF mOriginalViewPosition = new PointF(); + private PointF mCurrentViewPosition = new PointF(); + private PointF mOriginalTouchPosition = new PointF(); - /** - * Enable/Disable debug mode. In debug mode this Dragger will paint its touch area with a - * translucent color. - * @param debugMode true for debug mode, false otherwise - */ - void enableDebugMode(boolean debugMode); + protected final View.OnTouchListener mDragTouchListener = new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + switch (motionEvent.getAction()) { + case MotionEvent.ACTION_DOWN: + Log.d(TAG, "ACTION_DOWN"); + mIsDragging = false; - interface DragListener { + mOriginalViewPosition = convertCornerToCenter(getTouchViewPosition(mTouchView)); + mCurrentViewPosition = new PointF(mOriginalViewPosition.x, mOriginalViewPosition.y); + mOriginalTouchPosition.set(motionEvent.getRawX(), motionEvent.getRawY()); + mTouchListener.onPress(); + return true; + case MotionEvent.ACTION_MOVE: + Log.d(TAG, "ACTION_MOVE. motionX: " + motionEvent.getRawX() + ", motionY: " + motionEvent.getRawY()); + float dragDeltaX = motionEvent.getRawX() - mOriginalTouchPosition.x; + float dragDeltaY = motionEvent.getRawY() - mOriginalTouchPosition.y; + mCurrentViewPosition = new PointF( + mOriginalViewPosition.x + dragDeltaX, + mOriginalViewPosition.y + dragDeltaY + ); - /** - * The user has pressed within the draggable area at the given position. - * @param x x-coordinate of the user's press (in the parent View's coordinate space) - * @param y y-coordiante of the user's press (in the parent View's coordinate space) - */ - void onPress(float x, float y); + if (mIsDragging || !isTouchWithinSlopOfOriginalTouch(dragDeltaX, dragDeltaY)) { + if (!mIsDragging) { + // Dragging just started + Log.d(TAG, "MOVE Start Drag."); + mIsDragging = true; + mDragListener.onDragStart(mCurrentViewPosition.x, mCurrentViewPosition.y); + } else { + PointF cornerPosition = convertCenterToCorner(mCurrentViewPosition); + moveTouchViewTo(mTouchView, cornerPosition); + mDragListener.onDragTo(mCurrentViewPosition.x, mCurrentViewPosition.y); + } + } + + return true; + case MotionEvent.ACTION_UP: + Log.d(TAG, "ACTION_UP"); + if (!mIsDragging) { + Log.d(TAG, "Reporting as a tap."); + mTouchListener.onTap(); + } else { + Log.d(TAG, "Reporting as a drag release at: " + mCurrentViewPosition); + mDragListener.onReleasedAt(mCurrentViewPosition.x, mCurrentViewPosition.y); + } + return true; + default: + return false; + } + } + }; + + public Dragger(int mTapTouchSlop) { + this.mTapTouchSlop = mTapTouchSlop; + } + + public abstract PointF getTouchViewPosition(@NonNull View touchView); + + public void activate(@NonNull DragListener dragListener, @NonNull Rect rect) { + super.activate(dragListener, rect); + mDragListener = dragListener; + mTouchView.setOnTouchListener(mDragTouchListener); + } + + private boolean isTouchWithinSlopOfOriginalTouch(float dx, float dy) { + double distance = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); + Log.d(TAG, "Drag distance " + distance + " vs slop allowance " + mTapTouchSlop); + return distance < mTapTouchSlop; + } + + private PointF convertCornerToCenter(@NonNull PointF cornerPosition) { + return new PointF( + cornerPosition.x + (mTouchView.getWidth() / 2f), + cornerPosition.y + (mTouchView.getHeight() / 2f) + ); + } + + private PointF convertCenterToCorner(@NonNull PointF centerPosition) { + return new PointF( + centerPosition.x - (mTouchView.getWidth() / 2f), + centerPosition.y - (mTouchView.getHeight() / 2f) + ); + } + public interface DragListener extends TouchListener { /** * The user has begun dragging. + * * @param x x-coordinate of the user's drag start (in the parent View's coordinate space) * @param y y-coordiante of the user's drag start (in the parent View's coordinate space) */ @@ -60,6 +131,7 @@ interface DragListener { /** * The user has dragged to the given coordinates. + * * @param x x-coordinate of the user's drag (in the parent View's coordinate space) * @param y y-coordiante of the user's drag (in the parent View's coordinate space) */ @@ -67,15 +139,10 @@ interface DragListener { /** * The user has stopped touching the drag area. + * * @param x x-coordinate of the user's release (in the parent View's coordinate space) * @param y y-coordiante of the user's release (in the parent View's coordinate space) */ void onReleasedAt(float x, float y); - - /** - * The user tapped the drag area (instead of dragging it). - */ - void onTap(); - } } diff --git a/hover/src/main/java/io/mattcarroll/hover/HoverView.java b/hover/src/main/java/io/mattcarroll/hover/HoverView.java index 923122d..972abc3 100644 --- a/hover/src/main/java/io/mattcarroll/hover/HoverView.java +++ b/hover/src/main/java/io/mattcarroll/hover/HoverView.java @@ -232,11 +232,9 @@ void restoreVisualState() { persistentState.restore(this, mMenu); } - // TODO: when to call this? public void release() { Log.d(TAG, "Released."); mDragger.deactivate(); - // TODO: should we also release the screen? } public void enableDebugMode(boolean debugMode) { @@ -354,21 +352,21 @@ public void removeOnInteractionListener(@NonNull OnInteractionListener onInterac mOnInteractionListeners.remove(onInteractionListener); } - void notifyOnTap() { + void notifyOnTap(HoverViewState state) { for (OnInteractionListener onInteractionListener : mOnInteractionListeners) { - onInteractionListener.onTap(); + onInteractionListener.onTap(state.getStateType()); } } - void notifyOnDragStart() { + void notifyOnDragStart(HoverViewState state) { for (OnInteractionListener onInteractionListener : mOnInteractionListeners) { - onInteractionListener.onDragStart(); + onInteractionListener.onDragStart(state.getStateType()); } } - void notifyOnDocked() { + void notifyOnDocked(HoverViewState state) { for (OnInteractionListener onInteractionListener : mOnInteractionListeners) { - onInteractionListener.onDocked(); + onInteractionListener.onDocked(state.getStateType()); } } @@ -397,6 +395,7 @@ public void removeFromWindow() { if (mIsAddedToWindow) { mWindowViewController.removeView(this); mIsAddedToWindow = false; + release(); } } @@ -609,10 +608,10 @@ public void onAnchored() { } public interface OnInteractionListener { - void onTap(); + void onTap(HoverViewStateType stateType); - void onDragStart(); + void onDragStart(HoverViewStateType stateType); - void onDocked(); + void onDocked(HoverViewStateType stateType); } } diff --git a/hover/src/main/java/io/mattcarroll/hover/HoverViewState.java b/hover/src/main/java/io/mattcarroll/hover/HoverViewState.java index c080668..6a175af 100644 --- a/hover/src/main/java/io/mattcarroll/hover/HoverViewState.java +++ b/hover/src/main/java/io/mattcarroll/hover/HoverViewState.java @@ -49,4 +49,6 @@ interface HoverViewState { * {@link #respondsToBackButton()} returns true. */ void onBackPressed(); + + HoverViewStateType getStateType(); } diff --git a/hover/src/main/java/io/mattcarroll/hover/HoverViewStateAnchored.java b/hover/src/main/java/io/mattcarroll/hover/HoverViewStateAnchored.java index 992ed73..7a2c5ec 100644 --- a/hover/src/main/java/io/mattcarroll/hover/HoverViewStateAnchored.java +++ b/hover/src/main/java/io/mattcarroll/hover/HoverViewStateAnchored.java @@ -1,17 +1,26 @@ package io.mattcarroll.hover; import android.graphics.Point; +import android.graphics.Rect; import android.support.annotation.NonNull; import android.util.Log; -public class HoverViewStateAnchored extends BaseHoverViewState { +class HoverViewStateAnchored extends BaseHoverViewState { private static final String TAG = "HoverViewStateAnchored"; - private static final int ANCHOR_TAB_X_OFFSET_IN_PX = 100; - private static final int ANCHOR_TAB_Y_OFFSET_IN_PX = 100; private FloatingTab mSelectedTab; - private Point mDock; + private HoverMenu.Section mSelectedSection; + private final BaseTouchController.TouchListener mTouchListener = new BaseTouchController.TouchListener() { + @Override + public void onPress() { + } + + @Override + public void onTap() { + mHoverView.notifyOnTap(HoverViewStateAnchored.this); + } + }; @Override public void takeControl(@NonNull HoverView hoverView, final Runnable onStateChanged) { @@ -19,20 +28,28 @@ public void takeControl(@NonNull HoverView hoverView, final Runnable onStateChan Log.d(TAG, "Taking control."); mHoverView.makeUntouchableInWindow(); mHoverView.clearFocus(); - mDock = new Point( - mHoverView.mScreen.getWidth() - ANCHOR_TAB_X_OFFSET_IN_PX, - ANCHOR_TAB_Y_OFFSET_IN_PX + final int pointMargin = hoverView.getContext().getResources().getDimensionPixelSize(R.dimen.hover_tab_anchor_margin); + final Point anchorPoint = new Point( + mHoverView.mScreen.getWidth() - pointMargin, + mHoverView.mScreen.getHeight() - pointMargin ); - HoverMenu.Section section = mHoverView.mMenu.getSection(0); - mSelectedTab = mHoverView.mScreen.createChainedTab(section); - mSelectedTab.setDock(new PositionDock(mDock)); + mSelectedSection = mHoverView.mMenu.getSection(mHoverView.mSelectedSectionId); + if (mSelectedSection == null) { + mSelectedSection = mHoverView.mMenu.getSection(0); + } + mSelectedTab = mHoverView.mScreen.getChainedTab(mSelectedSection.getId()); + if (mSelectedTab == null) { + mSelectedTab = mHoverView.mScreen.createChainedTab(mSelectedSection); + } + mSelectedTab.setDock(new PositionDock(anchorPoint)); mSelectedTab.dock(new Runnable() { @Override public void run() { if (!hasControl()) { return; } + activateTouchController(); onStateChanged.run(); } }); @@ -41,9 +58,20 @@ public void run() { @Override public void giveUpControl(@NonNull HoverViewState nextState) { Log.d(TAG, "Giving up control."); + deactivateTouchController(); super.giveUpControl(nextState); } + private void activateTouchController() { + final Rect visibleRect = new Rect(); + mSelectedTab.getGlobalVisibleRect(visibleRect); + mHoverView.mDragger.activate(mTouchListener, visibleRect); + } + + private void deactivateTouchController() { + mHoverView.mDragger.deactivate(); + } + @Override public boolean respondsToBackButton() { return false; @@ -52,4 +80,9 @@ public boolean respondsToBackButton() { @Override public void onBackPressed() { } + + @Override + public HoverViewStateType getStateType() { + return HoverViewStateType.ANCHORED; + } } diff --git a/hover/src/main/java/io/mattcarroll/hover/HoverViewStateClosed.java b/hover/src/main/java/io/mattcarroll/hover/HoverViewStateClosed.java index acddf2a..40f3da2 100644 --- a/hover/src/main/java/io/mattcarroll/hover/HoverViewStateClosed.java +++ b/hover/src/main/java/io/mattcarroll/hover/HoverViewStateClosed.java @@ -69,4 +69,9 @@ public void giveUpControl(@NonNull HoverViewState nextState) { Log.d(TAG, "Giving up control."); super.giveUpControl(nextState); } + + @Override + public HoverViewStateType getStateType() { + return HoverViewStateType.CLOSED; + } } diff --git a/hover/src/main/java/io/mattcarroll/hover/HoverViewStateCollapsed.java b/hover/src/main/java/io/mattcarroll/hover/HoverViewStateCollapsed.java index dd1b887..cb2ab16 100644 --- a/hover/src/main/java/io/mattcarroll/hover/HoverViewStateCollapsed.java +++ b/hover/src/main/java/io/mattcarroll/hover/HoverViewStateCollapsed.java @@ -207,7 +207,7 @@ private void onPickedUpByUser() { mIsDocked = false; mHoverView.mScreen.getExitView().setVisibility(VISIBLE); restoreHoverViewAlphaValue(); - mHoverView.notifyOnDragStart(); + mHoverView.notifyOnDragStart(this); } private void onDroppedByUser() { @@ -245,7 +245,7 @@ private void onDroppedByUser() { private void onTap() { Log.d(TAG, "Floating tab was tapped."); - mHoverView.notifyOnTap(); + mHoverView.notifyOnTap(this); } private void sendToDock() { @@ -296,7 +296,7 @@ private void onDocked() { if (didJustCollapse) { mOnStateChanged.run(); } - mHoverView.notifyOnDocked(); + mHoverView.notifyOnDocked(this); } protected void moveTabTo(@NonNull Point position) { @@ -322,6 +322,11 @@ protected void restoreHoverViewAlphaValue() { mHoverView.setAlpha(1f); } + @Override + public HoverViewStateType getStateType() { + return HoverViewStateType.COLLAPSED; + } + protected static final class FloatingTabDragListener implements Dragger.DragListener { private final HoverViewStateCollapsed mOwner; @@ -330,9 +335,6 @@ protected FloatingTabDragListener(@NonNull HoverViewStateCollapsed owner) { mOwner = owner; } - @Override - public void onPress(float x, float y) { } - @Override public void onDragStart(float x, float y) { mOwner.onPickedUpByUser(); @@ -348,6 +350,10 @@ public void onReleasedAt(float x, float y) { mOwner.onDroppedByUser(); } + @Override + public void onPress() { + } + @Override public void onTap() { mOwner.onTap(); diff --git a/hover/src/main/java/io/mattcarroll/hover/HoverViewStateExpanded.java b/hover/src/main/java/io/mattcarroll/hover/HoverViewStateExpanded.java index 7d0b123..483639a 100644 --- a/hover/src/main/java/io/mattcarroll/hover/HoverViewStateExpanded.java +++ b/hover/src/main/java/io/mattcarroll/hover/HoverViewStateExpanded.java @@ -459,4 +459,9 @@ private void selectSection(@NonNull HoverMenu.Section section) { contentDisplay.selectedTabIs(mSelectedTab); contentDisplay.displayContent(section.getContent()); } + + @Override + public HoverViewStateType getStateType() { + return HoverViewStateType.EXPANDED; + } } diff --git a/hover/src/main/java/io/mattcarroll/hover/HoverViewStatePreviewed.java b/hover/src/main/java/io/mattcarroll/hover/HoverViewStatePreviewed.java index 652ce7c..3ce8bcd 100644 --- a/hover/src/main/java/io/mattcarroll/hover/HoverViewStatePreviewed.java +++ b/hover/src/main/java/io/mattcarroll/hover/HoverViewStatePreviewed.java @@ -74,4 +74,9 @@ protected void activateDragger() { mHoverView.mDragger.activate(mDragListener, tabRect); } + + @Override + public HoverViewStateType getStateType() { + return HoverViewStateType.PREVIEWED; + } } diff --git a/hover/src/main/java/io/mattcarroll/hover/HoverViewStateType.java b/hover/src/main/java/io/mattcarroll/hover/HoverViewStateType.java new file mode 100644 index 0000000..7435290 --- /dev/null +++ b/hover/src/main/java/io/mattcarroll/hover/HoverViewStateType.java @@ -0,0 +1,9 @@ +package io.mattcarroll.hover; + +public enum HoverViewStateType { + CLOSED, + COLLAPSED, + PREVIEWED, + EXPANDED, + ANCHORED, +} diff --git a/hover/src/main/java/io/mattcarroll/hover/view/InViewDragger.java b/hover/src/main/java/io/mattcarroll/hover/view/InViewDragger.java index 1811bc2..ce0e528 100644 --- a/hover/src/main/java/io/mattcarroll/hover/view/InViewDragger.java +++ b/hover/src/main/java/io/mattcarroll/hover/view/InViewDragger.java @@ -18,8 +18,6 @@ import android.graphics.PointF; import android.graphics.Rect; import android.support.annotation.NonNull; -import android.util.Log; -import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; @@ -29,165 +27,43 @@ /** * {@link Dragger} implementation that works within a {@link ViewGroup}. */ -public class InViewDragger implements Dragger { - +public class InViewDragger extends Dragger { private static final String TAG = "InViewDragger"; private final ViewGroup mContainer; - private final int mTapTouchSlop; - private boolean mIsActivated; - private boolean mIsDragging; - private boolean mIsDebugMode = false; - private View mDragView; - private DragListener mDragListener; - private PointF mOriginalViewPosition = new PointF(); - private PointF mCurrentViewPosition = new PointF(); - private PointF mOriginalTouchPosition = new PointF(); - - private final View.OnTouchListener mDragTouchListener = new View.OnTouchListener() { - @Override - public boolean onTouch(View view, MotionEvent motionEvent) { - switch (motionEvent.getAction()) { - case MotionEvent.ACTION_DOWN: - Log.d(TAG, "ACTION_DOWN"); - mIsDragging = false; - - mOriginalViewPosition = getDragViewCenterPosition(); - mCurrentViewPosition = new PointF(mOriginalViewPosition.x, mOriginalViewPosition.y); - mOriginalTouchPosition.set(motionEvent.getRawX(), motionEvent.getRawY()); - - mDragListener.onPress(mCurrentViewPosition.x, mCurrentViewPosition.y); - - return true; - case MotionEvent.ACTION_MOVE: - Log.v(TAG, "ACTION_MOVE. motionX: " + motionEvent.getRawX() + ", motionY: " + motionEvent.getRawY()); - float dragDeltaX = motionEvent.getRawX() - mOriginalTouchPosition.x; - float dragDeltaY = motionEvent.getRawY() - mOriginalTouchPosition.y; - mCurrentViewPosition = new PointF( - mOriginalViewPosition.x + dragDeltaX, - mOriginalViewPosition.y + dragDeltaY - ); - - if (mIsDragging || !isTouchWithinSlopOfOriginalTouch(dragDeltaX, dragDeltaY)) { - if (!mIsDragging) { - // Dragging just started - Log.d(TAG, "MOVE Start Drag."); - mIsDragging = true; - mDragListener.onDragStart(mCurrentViewPosition.x, mCurrentViewPosition.y); - } else { - moveDragViewTo(mCurrentViewPosition); - mDragListener.onDragTo(mCurrentViewPosition.x, mCurrentViewPosition.y); - } - } - - return true; - case MotionEvent.ACTION_UP: - if (!mIsDragging) { - Log.d(TAG, "ACTION_UP: Tap."); - mDragListener.onTap(); - } else { - Log.d(TAG, "ACTION_UP: Released from dragging."); - mDragListener.onReleasedAt(mCurrentViewPosition.x, mCurrentViewPosition.y); - } - - return true; - default: - return false; - } - } - }; public InViewDragger(@NonNull ViewGroup container, int touchSlop) { + super(touchSlop); mContainer = container; - mTapTouchSlop = touchSlop; } @Override - public void enableDebugMode(boolean isDebugMode) { - mIsDebugMode = isDebugMode; - updateTouchControlViewAppearance(); - } - - @Override - public void activate(@NonNull DragListener dragListener, @NonNull Rect rect) { - if (!mIsActivated) { - Log.d(TAG, "Activating."); - mIsActivated = true; - mDragListener = dragListener; - createTouchControlView(rect); - } - } - - @Override - public void deactivate() { - if (mIsActivated) { - Log.d(TAG, "Deactivating."); - mIsActivated = false; - destroyTouchControlView(); - } - } - - private void createTouchControlView(@NonNull Rect rect) { - mDragView = new View(mContainer.getContext()); - mDragView.setId(R.id.hover_drag_view); + public View createTouchView(@NonNull Rect rect) { + View dragView = new View(mContainer.getContext()); + dragView.setId(R.id.hover_drag_view); final int width = rect.right - rect.left; final int height = rect.bottom - rect.top; - mDragView.setLayoutParams(new ViewGroup.LayoutParams(width, height)); - mDragView.setOnTouchListener(mDragTouchListener); - mContainer.addView(mDragView); - - moveDragViewTo(new PointF((rect.right + rect.left) / 2, (rect.bottom + rect.top) / 2)); - updateTouchControlViewAppearance(); - } - - private void destroyTouchControlView() { - mContainer.removeView(mDragView); - - mDragView.setOnTouchListener(null); - mDragView = null; - } - - private void updateTouchControlViewAppearance() { - if (null != mDragView) { - if (mIsDebugMode) { - Log.d(TAG, "Making mDragView red: " + mDragView.hashCode()); - mDragView.setBackgroundColor(0x44FF0000); - } else { - mDragView.setBackgroundColor(0x00000000); - } - } - } - - private boolean isTouchWithinSlopOfOriginalTouch(float dx, float dy) { - double distance = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); - return distance < mTapTouchSlop; + dragView.setLayoutParams(new ViewGroup.LayoutParams(width, height)); + mContainer.addView(dragView); + return dragView; } - private PointF getDragViewCenterPosition() { - return convertCornerToCenter(new PointF( - mDragView.getX(), - mDragView.getY() - )); - } - - private void moveDragViewTo(PointF centerPosition) { - Log.d(TAG, "Moving drag view (" + mDragView.hashCode() + ") to: " + centerPosition); - PointF cornerPosition = convertCenterToCorner(centerPosition); - mDragView.setX(cornerPosition.x); - mDragView.setY(cornerPosition.y); + @Override + public void destroyTouchView(@NonNull View touchView) { + mContainer.removeView(touchView); } - private PointF convertCornerToCenter(@NonNull PointF cornerPosition) { + @Override + public PointF getTouchViewPosition(@NonNull View touchView) { return new PointF( - cornerPosition.x + (mDragView.getWidth() / 2), - cornerPosition.y + (mDragView.getHeight() / 2) + touchView.getX(), + touchView.getY() ); } - private PointF convertCenterToCorner(@NonNull PointF centerPosition) { - return new PointF( - centerPosition.x - (mDragView.getWidth() / 2), - centerPosition.y - (mDragView.getHeight() / 2) - ); + @Override + public void moveTouchViewTo(@NonNull View touchView, @NonNull PointF position) { + touchView.setX(position.x); + touchView.setY(position.y); } } diff --git a/hover/src/main/java/io/mattcarroll/hover/window/InWindowDragger.java b/hover/src/main/java/io/mattcarroll/hover/window/InWindowDragger.java index aac914a..d65759f 100755 --- a/hover/src/main/java/io/mattcarroll/hover/window/InWindowDragger.java +++ b/hover/src/main/java/io/mattcarroll/hover/window/InWindowDragger.java @@ -16,12 +16,9 @@ package io.mattcarroll.hover.window; import android.content.Context; -import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.support.annotation.NonNull; -import android.util.Log; -import android.view.MotionEvent; import android.view.View; import io.mattcarroll.hover.Dragger; @@ -29,176 +26,41 @@ /** * {@link Dragger} implementation that works within a {@code Window}. */ -public class InWindowDragger implements Dragger { - +public class InWindowDragger extends Dragger { private static final String TAG = "InWindowDragger"; private final Context mContext; private final WindowViewController mWindowViewController; - private final float mTapTouchSlop; - private View mDragView; - private Dragger.DragListener mDragListener; - private boolean mIsActivated; - private boolean mIsDragging; - private boolean mIsDebugMode; - - private PointF mOriginalViewPosition = new PointF(); - private PointF mCurrentViewPosition = new PointF(); - private PointF mOriginalTouchPosition = new PointF(); - - private View.OnTouchListener mDragTouchListener = new View.OnTouchListener() { - @Override - public boolean onTouch(View view, MotionEvent motionEvent) { - switch (motionEvent.getAction()) { - case MotionEvent.ACTION_DOWN: - Log.d(TAG, "ACTION_DOWN"); - mIsDragging = false; - - mOriginalViewPosition = getDragViewCenterPosition(); - mCurrentViewPosition = new PointF(mOriginalViewPosition.x, mOriginalViewPosition.y); - mOriginalTouchPosition.set(motionEvent.getRawX(), motionEvent.getRawY()); - - mDragListener.onPress(mCurrentViewPosition.x, mCurrentViewPosition.y); - - return true; - case MotionEvent.ACTION_MOVE: - Log.d(TAG, "ACTION_MOVE. motionX: " + motionEvent.getRawX() + ", motionY: " + motionEvent.getRawY()); - float dragDeltaX = motionEvent.getRawX() - mOriginalTouchPosition.x; - float dragDeltaY = motionEvent.getRawY() - mOriginalTouchPosition.y; - mCurrentViewPosition = new PointF( - mOriginalViewPosition.x + dragDeltaX, - mOriginalViewPosition.y + dragDeltaY - ); - - if (mIsDragging || !isTouchWithinSlopOfOriginalTouch(dragDeltaX, dragDeltaY)) { - if (!mIsDragging) { - // Dragging just started - Log.d(TAG, "MOVE Start Drag."); - mIsDragging = true; - mDragListener.onDragStart(mCurrentViewPosition.x, mCurrentViewPosition.y); - } else { - moveDragViewTo(mCurrentViewPosition); - mDragListener.onDragTo(mCurrentViewPosition.x, mCurrentViewPosition.y); - } - } - - return true; - case MotionEvent.ACTION_UP: - Log.d(TAG, "ACTION_UP"); - if (!mIsDragging) { - Log.d(TAG, "Reporting as a tap."); - mDragListener.onTap(); - } else { - Log.d(TAG, "Reporting as a drag release at: " + mCurrentViewPosition); - mDragListener.onReleasedAt(mCurrentViewPosition.x, mCurrentViewPosition.y); - } - return true; - default: - return false; - } - } - }; - - /** - * Note: {@code view} must already be added to the {@code Window}. - * @param context context - * @param windowViewController windowViewController - * @param tapTouchSlop tapTouchSlop - */ public InWindowDragger(@NonNull Context context, @NonNull WindowViewController windowViewController, - float tapTouchSlop) { + int tapTouchSlop) { + super(tapTouchSlop); mContext = context; mWindowViewController = windowViewController; - mTapTouchSlop = tapTouchSlop; - } - - @Override - public void activate(@NonNull DragListener dragListener, @NonNull Rect rect) { - if (!mIsActivated) { - Log.d(TAG, "Activating."); - createTouchControlView(rect); - mDragListener = dragListener; - mDragView.setOnTouchListener(mDragTouchListener); - mIsActivated = true; - } - } - - @Override - public void deactivate() { - if (mIsActivated) { - Log.d(TAG, "Deactivating."); - mDragView.setOnTouchListener(null); - destroyTouchControlView(); - mIsActivated = false; - } } @Override - public void enableDebugMode(boolean isDebugMode) { - mIsDebugMode = isDebugMode; - updateTouchControlViewAppearance(); - } - - private void createTouchControlView(@NonNull Rect rect) { - mDragView = new View(mContext); + public View createTouchView(@NonNull Rect rect) { + View dragView = new View(mContext); final int width = rect.right - rect.left; final int height = rect.bottom - rect.top; - mWindowViewController.addView(width, height, true, mDragView); - mWindowViewController.moveViewTo(mDragView, rect.left, rect.top); - mDragView.setOnTouchListener(mDragTouchListener); - - updateTouchControlViewAppearance(); - } - - private void destroyTouchControlView() { - mWindowViewController.removeView(mDragView); - mDragView = null; - } - - private void updateTouchControlViewAppearance() { - if (null != mDragView) { - if (mIsDebugMode) { - mDragView.setBackgroundColor(0x44FF0000); - } else { - mDragView.setBackgroundColor(0x00000000); - } - } + mWindowViewController.addView(width, height, true, dragView); + return dragView; } - private boolean isTouchWithinSlopOfOriginalTouch(float dx, float dy) { - double distance = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); - Log.d(TAG, "Drag distance " + distance + " vs slop allowance " + mTapTouchSlop); - return distance < mTapTouchSlop; - } - - private PointF getDragViewCenterPosition() { - Point cornerPosition = mWindowViewController.getViewPosition(mDragView); - return convertCornerToCenter(new PointF( - cornerPosition.x, - cornerPosition.y - )); - } - - private void moveDragViewTo(PointF centerPosition) { - Log.d(TAG, "Center position: " + centerPosition); - PointF cornerPosition = convertCenterToCorner(centerPosition); - Log.d(TAG, "Corner position: " + cornerPosition); - mWindowViewController.moveViewTo(mDragView, (int) cornerPosition.x, (int) cornerPosition.y); + @Override + public void destroyTouchView(@NonNull View touchView) { + mWindowViewController.removeView(touchView); } - private PointF convertCornerToCenter(@NonNull PointF cornerPosition) { - return new PointF( - cornerPosition.x + (mDragView.getWidth() / 2), - cornerPosition.y + (mDragView.getHeight() / 2) - ); + @Override + public PointF getTouchViewPosition(@NonNull View touchView) { + return new PointF(mWindowViewController.getViewPosition(touchView)); } - private PointF convertCenterToCorner(@NonNull PointF centerPosition) { - return new PointF( - centerPosition.x - (mDragView.getWidth() / 2), - centerPosition.y - (mDragView.getHeight() / 2) - ); + @Override + public void moveTouchViewTo(@NonNull View touchView, @NonNull PointF position) { + mWindowViewController.moveViewTo(touchView, (int) position.x, (int) position.y); } } diff --git a/hover/src/main/res/values/dimens.xml b/hover/src/main/res/values/dimens.xml index 0023349..51aeba3 100755 --- a/hover/src/main/res/values/dimens.xml +++ b/hover/src/main/res/values/dimens.xml @@ -6,4 +6,5 @@ 75dp 32dp 24dp + 32dp