| /* |
| * Copyright (c) 2016, The Linux Foundation. All rights reserved. |
| |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * * Neither the name of The Linux Foundation nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| |
| * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| package com.android.gallery3d.app; |
| |
| import android.content.Context; |
| import android.graphics.Rect; |
| import android.view.GestureDetector; |
| import android.view.MotionEvent; |
| |
| public class GestureController { |
| private static final int GESTURE_THRESHOLD = 20; |
| private GestureDetector mGestureDetector; |
| private GestureControlListener mGestureControlListener; |
| |
| private Rect mFullRect = new Rect(); |
| private Rect mBrightnessRect = new Rect(); |
| private Rect mVolumeRect = new Rect(); |
| private Type mType = Type.NONE; |
| |
| private MotionEvent mStartEvent; |
| |
| public GestureController(Context context, GestureControlListener gestureControlListener) { |
| mGestureControlListener = gestureControlListener; |
| mGestureDetector = |
| new GestureDetector(context, new GestureListener(gestureControlListener)); |
| } |
| |
| public interface GestureControlListener { |
| void onGestureDone(boolean notStart); |
| /** |
| * change current windows brightness by add adjustPercent. |
| * |
| * @param adjustPercent: -1.0f ~ 1.0f, increase if adjustPercent > 0, |
| * decrease if adjustPercent < 0; |
| */ |
| void adjustBrightness(double adjustPercent); |
| |
| /** |
| * change volume level by add adjustPercent. |
| * |
| * @param adjustPercent: -1.0f ~ 1.0f, increase if adjustPercent > 0, |
| * decrease if adjustPercent < 0; |
| */ |
| void adjustVolumeLevel(double adjustPercent); |
| |
| /** |
| * change video position by add adjustPercent. |
| * |
| * @param adjustPercent: -1.0f ~ 1.0f, increase if adjustPercent > 0, |
| * decrease if adjustPercent < 0; |
| * @param forwardDirection: true if direction is forward. |
| */ |
| void adjustVideoPosition(double adjustPercent, boolean forwardDirection); |
| } |
| |
| private enum Type { |
| NONE, |
| BRIGHTNESS, |
| VOLUME, |
| SEEK, |
| } |
| |
| public void setRect(Rect rect) { |
| this.setRect(rect.left, rect.top, rect.right, rect.bottom); |
| } |
| |
| public void setRect(int l, int t, int r, int b) { |
| mFullRect.left = l; |
| mFullRect.top = t; |
| mFullRect.right = r; |
| mFullRect.bottom = b; |
| |
| mBrightnessRect.left = l; |
| mBrightnessRect.top = t; |
| mBrightnessRect.right = r / 2; |
| mBrightnessRect.bottom = b; |
| |
| mVolumeRect.left = l / 2; |
| mVolumeRect.top = t; |
| mVolumeRect.right = r; |
| mVolumeRect.bottom = b; |
| } |
| |
| private class GestureListener extends GestureDetector.SimpleOnGestureListener { |
| private GestureControlListener mGestureControlListener; |
| |
| public GestureListener(GestureControlListener controlListener) { |
| mGestureControlListener = controlListener; |
| } |
| |
| @Override |
| public boolean onScroll(MotionEvent start, MotionEvent end, |
| float distanceX, float distanceY) { |
| if (mGestureControlListener == null) { |
| return super.onScroll(start, end, distanceX, distanceY); |
| } |
| // function depends on start position. (volume or brightness or play position.) |
| double yDistance = end.getY() - start.getY(); |
| double xDistance = end.getX() - start.getX(); |
| |
| if (mType == Type.BRIGHTNESS) { |
| // use half of BrightnessRect's height to calc percent. |
| if (mBrightnessRect.height() != 0) { |
| double percent = yDistance / (mBrightnessRect.height() / 2.0f) * -1.0f; |
| mGestureControlListener.adjustBrightness(percent); |
| } |
| } else if (mType == Type.VOLUME) { |
| // use half of VolumeRect's height to calc percent. |
| if (mVolumeRect.height() != 0) { |
| double percent = yDistance / (mVolumeRect.height() / 2.0f) * -1.0f; |
| mGestureControlListener.adjustVolumeLevel(percent); |
| } |
| } else if (mType == Type.SEEK) { |
| if (mFullRect.width() != 0) { |
| double percent = xDistance / mFullRect.width(); |
| mGestureControlListener.adjustVideoPosition(percent, distanceX < 0); |
| } |
| } |
| return true; |
| } |
| } |
| |
| private boolean isEventValid(MotionEvent event) { |
| // this gesture just worked on single pointer. |
| return (mGestureDetector != null && event.getPointerCount() == 1); |
| } |
| |
| public boolean onTouchEvent(MotionEvent event) { |
| if (!isEventValid(event)) { |
| return false; |
| } |
| // decide which process is needed. |
| switch (event.getAction()) { |
| case MotionEvent.ACTION_DOWN: |
| mStartEvent = MotionEvent.obtain(event); |
| break; |
| case MotionEvent.ACTION_MOVE: |
| if (mType == Type.NONE && mStartEvent != null) { |
| mType = calcControllerType(mStartEvent, event); |
| } |
| break; |
| case MotionEvent.ACTION_UP: |
| if (mGestureControlListener != null) { |
| if (mType == Type.NONE) { |
| mGestureControlListener.onGestureDone(true); |
| } else { |
| mGestureControlListener.onGestureDone(false); |
| } |
| } |
| mType = Type.NONE; |
| mStartEvent = null; |
| break; |
| default: |
| break; |
| } |
| |
| return mGestureDetector.onTouchEvent(event); |
| } |
| |
| private Type calcControllerType(MotionEvent startEvent, MotionEvent currentEvent) { |
| float startX = startEvent.getX(); |
| float startY = startEvent.getY(); |
| float currentX = currentEvent.getX(); |
| float currentY = currentEvent.getY(); |
| if (Math.abs(currentX - startX) >= GESTURE_THRESHOLD) { |
| return Type.SEEK; |
| } else if (Math.abs(currentY - startY) >= GESTURE_THRESHOLD) { |
| if (mBrightnessRect.contains((int) startX, (int) startY)) { |
| return Type.BRIGHTNESS; |
| } else if (mVolumeRect.contains((int) startX, (int) startY)) { |
| return Type.VOLUME; |
| } |
| } |
| return Type.NONE; |
| } |
| } |