Home | History | Annotate | Download | only in phone
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.systemui.statusbar.phone;
     18 
     19 import android.content.Context;
     20 import android.util.AttributeSet;
     21 import android.view.MotionEvent;
     22 import android.view.View;
     23 import android.widget.ScrollView;
     24 
     25 /**
     26  * A scroll view which can be observed for scroll change events.
     27  */
     28 public class ObservableScrollView extends ScrollView {
     29 
     30     private Listener mListener;
     31     private int mLastOverscrollAmount;
     32     private boolean mTouchEnabled = true;
     33     private boolean mHandlingTouchEvent;
     34     private float mLastX;
     35     private float mLastY;
     36     private boolean mBlockFlinging;
     37     private boolean mTouchCancelled;
     38 
     39     public ObservableScrollView(Context context, AttributeSet attrs) {
     40         super(context, attrs);
     41     }
     42 
     43     public void setListener(Listener listener) {
     44         mListener = listener;
     45     }
     46 
     47     public void setTouchEnabled(boolean touchEnabled) {
     48         mTouchEnabled = touchEnabled;
     49     }
     50 
     51     public boolean isScrolledToBottom() {
     52         return getScrollY() == getMaxScrollY();
     53     }
     54 
     55     public boolean isHandlingTouchEvent() {
     56         return mHandlingTouchEvent;
     57     }
     58 
     59     private int getMaxScrollY() {
     60         int scrollRange = 0;
     61         if (getChildCount() > 0) {
     62             View child = getChildAt(0);
     63             scrollRange = Math.max(0,
     64                     child.getHeight() - (getHeight() - mPaddingBottom - mPaddingTop));
     65         }
     66         return scrollRange;
     67     }
     68 
     69     @Override
     70     public boolean onTouchEvent(MotionEvent ev) {
     71         mHandlingTouchEvent = true;
     72         mLastX = ev.getX();
     73         mLastY = ev.getY();
     74         boolean result = super.onTouchEvent(ev);
     75         mHandlingTouchEvent = false;
     76         return result;
     77     }
     78 
     79     @Override
     80     public boolean onInterceptTouchEvent(MotionEvent ev) {
     81         mHandlingTouchEvent = true;
     82         mLastX = ev.getX();
     83         mLastY = ev.getY();
     84         boolean result = super.onInterceptTouchEvent(ev);
     85         mHandlingTouchEvent = false;
     86         return result;
     87     }
     88 
     89     @Override
     90     public boolean dispatchTouchEvent(MotionEvent ev) {
     91         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
     92             if (!mTouchEnabled) {
     93                 mTouchCancelled = true;
     94                 return false;
     95             }
     96             mTouchCancelled = false;
     97         } else if (mTouchCancelled) {
     98             return false;
     99         } else if (!mTouchEnabled) {
    100             MotionEvent cancel = MotionEvent.obtain(ev);
    101             cancel.setAction(MotionEvent.ACTION_CANCEL);
    102             super.dispatchTouchEvent(cancel);
    103             cancel.recycle();
    104             mTouchCancelled = true;
    105             return false;
    106         }
    107         return super.dispatchTouchEvent(ev);
    108     }
    109 
    110     @Override
    111     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    112         super.onScrollChanged(l, t, oldl, oldt);
    113         if (mListener != null) {
    114             mListener.onScrollChanged();
    115         }
    116     }
    117 
    118     @Override
    119     protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY,
    120             int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY,
    121             boolean isTouchEvent) {
    122         mLastOverscrollAmount = Math.max(0, scrollY + deltaY - getMaxScrollY());
    123         return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY,
    124                         maxOverScrollX, maxOverScrollY, isTouchEvent);
    125     }
    126 
    127     public void setBlockFlinging(boolean blockFlinging) {
    128         mBlockFlinging = blockFlinging;
    129     }
    130 
    131     @Override
    132     public void fling(int velocityY) {
    133         if (!mBlockFlinging) {
    134             super.fling(velocityY);
    135         }
    136     }
    137 
    138     @Override
    139     protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
    140         super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
    141         if (mListener != null && mLastOverscrollAmount > 0) {
    142             mListener.onOverscrolled(mLastX, mLastY, mLastOverscrollAmount);
    143         }
    144     }
    145 
    146     public interface Listener {
    147         void onScrollChanged();
    148         void onOverscrolled(float lastX, float lastY, int amount);
    149     }
    150 }
    151