content: /*
   * Created by LuaView.
   * Copyright (c) 2017, Alibaba Group. All rights reserved.
   *
   * This source code is licensed under the MIT.
   * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
   */
  
  package com.taobao.luaview.view.viewpager;
  
  import android.content.Context;
  import android.os.Handler;
  import android.os.Message;
  import android.support.v4.view.MotionEventCompat;
  import android.support.v4.view.PagerAdapter;
  import android.view.MotionEvent;
  import android.view.View;
  
  import java.lang.ref.WeakReference;
  
  public class AutoScrollViewPager extends LoopViewPager {
  
      public static final int DEFAULT_INTERVAL = 3000;
  
      public static final int LEFT = 0;
      public static final int RIGHT = 1;
  
      /**
       * do nothing when sliding at the last or first item
       **/
      public static final int SLIDE_BORDER_MODE_NONE = 0;
      /**
       * cycle when sliding at the last or first item
       **/
      public static final int SLIDE_BORDER_MODE_CYCLE = 1;
      /**
       * deliver event to parent when sliding at the last or first item
       **/
      public static final int SLIDE_BORDER_MODE_TO_PARENT = 2;
  
      /**
       * auto scroll time in milliseconds, default is {@link #DEFAULT_INTERVAL}
       **/
      private long interval = DEFAULT_INTERVAL;
      /**
       * auto scroll direction, default is {@link #RIGHT}
       **/
      private int direction = RIGHT;
      /**
       * whether stop auto scroll when touching, default is true
       **/
      private boolean stopScrollWhenTouch = true;
      /**
       * how to process when sliding at the last or first item, default is {@link #SLIDE_BORDER_MODE_NONE}
       **/
      private int slideBorderMode = SLIDE_BORDER_MODE_NONE;
  
      private Handler handler;
      private boolean reverseDirection = false;
      private boolean isAutoScroll = false;
      private boolean isStopByUIChange = false;
      private boolean isStopByTouch = false;
      private float touchX = 0f, downX = 0f;
  
      private boolean canAutoScroll = false;
  
      public static final int SCROLL_WHAT = 0;
  
      public AutoScrollViewPager(Context context) {
          super(context);
          init();
      }
  
      private void init() {
          handler = new MyHandler(this);
      }
  
      /**
       * 设置是否可以自动滚动，所有自动滚动的逻辑都受该参数影响
       *
       * @param canAutoScroll
       */
      public void setCanAutoScroll(boolean canAutoScroll) {
          this.canAutoScroll = canAutoScroll;
      }
  
      /**
       * start auto scroll, first scroll delay time is {@link #getInterval()}
       */
      public void startAutoScroll() {
          isAutoScroll = true;
          sendScrollMessage(interval);
      }
  
      /**
       * start auto scroll
       *
       * @param delayTimeInMills first scroll delay time
       */
      public void startAutoScroll(int delayTimeInMills) {
          isAutoScroll = true;
          sendScrollMessage(delayTimeInMills);
      }
  
      /**
       * stop auto scroll
       */
      public void stopAutoScroll() {
          isAutoScroll = false;
          handler.removeMessages(SCROLL_WHAT);
      }
  
  
      private void sendScrollMessage(long delayTimeInMills) {
          /** remove messages before, keeps one message is running at most **/
          handler.removeMessages(SCROLL_WHAT);
          handler.sendEmptyMessageDelayed(SCROLL_WHAT, delayTimeInMills);
      }
  
      /**
       * scroll only once
       */
      public void scrollOnce() {
          PagerAdapter adapter = getAdapter();
          int realPosition = getCurrentItem();
          int realCount;
          if (adapter == null || (realCount = getRealCount()) <= 1) {
              return;
          }
  
          //调整方向
          if (reverseDirection) {
              if (direction == RIGHT && realPosition + 1 >= realCount) {
                  direction = LEFT;
              } else if (direction == LEFT && realPosition - 1 < 0) {
                  direction = RIGHT;
              }
          }
  
          if (isLooping()) {
              setCurrentItem(direction == LEFT ? (realPosition - 1) % getCount() : (realPosition + 1) % getCount(), true);
          } else {
              int nextItem = (direction == LEFT) ? --realPosition : ++realPosition;
              if (nextItem < 0) {
                  setCurrentItem(realCount - 1, true);
              } else if (nextItem == realCount) {
                  setCurrentItem(0, true);
              } else {
                  setCurrentItem(nextItem, true);
              }
          }
      }
  
      /**
       * <ul>
       * if stopScrollWhenTouch is true
       * <li>if event is down, stop auto scroll.</li>
       * <li>if event is up, start auto scroll again.</li>
       * </ul>
       *
       * bugfix: 增加ev.getAction() == MotionEvent.ACTION_CANCEL条件判断,Action Cancel事件发生的时候也要重新开始自动滚动
       *
       */
      @Override
      public boolean dispatchTouchEvent(MotionEvent ev) {
          if (!canAutoScroll) {
              return super.dispatchTouchEvent(ev);
          }
          int action = MotionEventCompat.getActionMasked(ev);
  
          if (stopScrollWhenTouch) {
              if ((action == MotionEvent.ACTION_DOWN) && isAutoScroll) {
                  isStopByTouch = true;
                  stopAutoScroll();
              } else if ((ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) && isStopByTouch) {
                  startAutoScroll();
              }
          }
  
  //        if (slideBorderMode == SLIDE_BORDER_MODE_TO_PARENT || slideBorderMode == SLIDE_BORDER_MODE_CYCLE) {
  //            touchX = ev.getX();
  //            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
  //                downX = touchX;
  //            }
  //            int currentItem = getCurrentItem();
  //            PagerAdapter adapter = getAdapter();
  //            int pageCount = adapter == null ? 0 : adapter.getCount();
  //            /**
  //             * current index is first one and slide to right or current index is last one and slide to left.<br/>
  //             * if slide border mode is to parent, then requestDisallowInterceptTouchEvent false.<br/>
  //             * else scroll to last one when current item is first one, scroll to first one when current item is last
  //             * one.
  //             */
  //            if ((currentItem == 0 && downX <= touchX) || (currentItem == pageCount - 1 && downX >= touchX)) {
  //                if (slideBorderMode == SLIDE_BORDER_MODE_TO_PARENT) {
  //                    getParent().requestDisallowInterceptTouchEvent(false);
  //                } else {
  //                    if (pageCount > 1) {
  //                        setCurrentItem(pageCount - currentItem - 1, false);
  //                    }
  ////                    getParent().requestDisallowInterceptTouchEvent(true);
  //                }
  //                return super.dispatchTouchEvent(ev);
  //            }
  //        }
  ////        getParent().requestDisallowInterceptTouchEvent(true);
  
          return super.dispatchTouchEvent(ev);
      }
  
      private static class MyHandler extends Handler {
  
          private final WeakReference<AutoScrollViewPager> autoScrollViewPager;
  
          public MyHandler(AutoScrollViewPager autoScrollViewPager) {
              this.autoScrollViewPager = new WeakReference<AutoScrollViewPager>(autoScrollViewPager);
          }
  
          @Override
          public void handleMessage(Message msg) {
              super.handleMessage(msg);
  
              switch (msg.what) {
                  case SCROLL_WHAT:
                      AutoScrollViewPager pager = this.autoScrollViewPager.get();
                      if (pager != null) {
                          pager.scrollOnce();
                          pager.sendScrollMessage(pager.interval);
                      }
                  default:
                      break;
              }
          }
      }
  
      /**
       * get auto scroll time in milliseconds, default is {@link #DEFAULT_INTERVAL}
       *
       * @return the interval
       */
      public long getInterval() {
          return interval;
      }
  
      /**
       * set auto scroll time in milliseconds, default is {@link #DEFAULT_INTERVAL}
       *
       * @param interval the interval to set
       */
      public void setInterval(long interval) {
          this.interval = interval;
      }
  
      /**
       * get auto scroll direction
       *
       * @return {@link #LEFT} or {@link #RIGHT}, default is {@link #RIGHT}
       */
      public int getDirection() {
          return (direction == LEFT) ? LEFT : RIGHT;
      }
  
      /**
       * set auto scroll direction
       *
       * @param direction {@link #LEFT} or {@link #RIGHT}, default is {@link #RIGHT}
       */
      public void setDirection(int direction) {
          this.direction = direction;
      }
  
      /**
       * whether stop auto scroll when touching, default is true
       *
       * @return the stopScrollWhenTouch
       */
      public boolean isStopScrollWhenTouch() {
          return stopScrollWhenTouch;
      }
  
      /**
       * set whether stop auto scroll when touching, default is true
       *
       * @param stopScrollWhenTouch
       */
      public void setStopScrollWhenTouch(boolean stopScrollWhenTouch) {
          this.stopScrollWhenTouch = stopScrollWhenTouch;
      }
  
      /**
       * get how to process when sliding at the last or first item
       *
       * @return the slideBorderMode {@link #SLIDE_BORDER_MODE_NONE}, {@link #SLIDE_BORDER_MODE_TO_PARENT},
       * {@link #SLIDE_BORDER_MODE_CYCLE}, default is {@link #SLIDE_BORDER_MODE_NONE}
       */
      public int getSlideBorderMode() {
          return slideBorderMode;
      }
  
      /**
       * set how to process when sliding at the last or first item
       *
       * @param slideBorderMode {@link #SLIDE_BORDER_MODE_NONE}, {@link #SLIDE_BORDER_MODE_TO_PARENT},
       *                        {@link #SLIDE_BORDER_MODE_CYCLE}, default is {@link #SLIDE_BORDER_MODE_NONE}
       */
      public void setSlideBorderMode(int slideBorderMode) {
          this.slideBorderMode = slideBorderMode;
      }
  
      public void setReverseDirection(boolean reverseDirection) {
          this.reverseDirection = reverseDirection;
      }
  
      @Override
      protected void onVisibilityChanged(View changedView, int visibility) {
          if (canAutoScroll && visibility == View.VISIBLE && isStopByUIChange) {
              isStopByUIChange = false;
              startAutoScroll();
          }
          super.onVisibilityChanged(changedView, visibility);
          if (canAutoScroll && visibility != View.VISIBLE) {
              isStopByUIChange = true;
              stopAutoScroll();
          }
      }
  
      @Override
      protected void onDetachedFromWindow() {
          super.onDetachedFromWindow();
          if (!canAutoScroll) {
              return;
          }
          isStopByUIChange = true;
          stopAutoScroll();
      }
  }