content: /*
   * Copyright (C) 2016 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.android.launcher3.util;
  
  import android.content.Context;
  import android.view.MotionEvent;
  import android.view.VelocityTracker;
  import android.view.View;
  import android.view.ViewConfiguration;
  
  public class VerticalFlingDetector implements View.OnTouchListener {
  
      private static final float CUSTOM_SLOP_MULTIPLIER = 2.2f;
      private static final int SEC_IN_MILLIS = 1000;
  
      private VelocityTracker mVelocityTracker;
      private float mMinimumFlingVelocity;
      private float mMaximumFlingVelocity;
      private float mDownX, mDownY;
      private boolean mShouldCheckFling;
      private double mCustomTouchSlop;
  
      public VerticalFlingDetector(Context context) {
          ViewConfiguration vc = ViewConfiguration.get(context);
          mMinimumFlingVelocity = vc.getScaledMinimumFlingVelocity();
          mMaximumFlingVelocity = vc.getScaledMaximumFlingVelocity();
          mCustomTouchSlop = CUSTOM_SLOP_MULTIPLIER * vc.getScaledTouchSlop();
      }
  
      @Override
      public boolean onTouch(View v, MotionEvent ev) {
          if (mVelocityTracker == null) {
              mVelocityTracker = VelocityTracker.obtain();
          }
          mVelocityTracker.addMovement(ev);
          switch (ev.getAction()) {
              case MotionEvent.ACTION_DOWN:
                  mDownX = ev.getX();
                  mDownY = ev.getY();
                  mShouldCheckFling = false;
                  break;
              case MotionEvent.ACTION_MOVE:
                  if (mShouldCheckFling) {
                      break;
                  }
                  if (Math.abs(ev.getY() - mDownY) > mCustomTouchSlop &&
                          Math.abs(ev.getY() - mDownY) > Math.abs(ev.getX() - mDownX)) {
                      mShouldCheckFling = true;
                  }
                  break;
              case MotionEvent.ACTION_UP:
                  if (mShouldCheckFling) {
                      mVelocityTracker.computeCurrentVelocity(SEC_IN_MILLIS, mMaximumFlingVelocity);
                      // only when fling is detected in down direction
                      if (mVelocityTracker.getYVelocity() > mMinimumFlingVelocity) {
                          cleanUp();
                          return true;
                      }
                  }
                  // fall through.
              case MotionEvent.ACTION_CANCEL:
                  cleanUp();
          }
          return false;
      }
  
      private void cleanUp() {
          if (mVelocityTracker == null) {
              return;
          }
          mVelocityTracker.recycle();
          mVelocityTracker = null;
      }
  }
  