1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.systemui.qs; 16 17 import android.content.Context; 18 import android.util.AttributeSet; 19 import android.view.MotionEvent; 20 import android.view.View; 21 import android.view.ViewConfiguration; 22 import android.view.ViewParent; 23 import android.widget.ScrollView; 24 25 /** 26 * ScrollView that disallows intercepting for touches that can cause scrolling. 27 */ 28 public class NonInterceptingScrollView extends ScrollView { 29 30 private final int mTouchSlop; 31 private float mDownY; 32 NonInterceptingScrollView(Context context, AttributeSet attrs)33 public NonInterceptingScrollView(Context context, AttributeSet attrs) { 34 super(context, attrs); 35 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 36 } 37 38 @Override onTouchEvent(MotionEvent ev)39 public boolean onTouchEvent(MotionEvent ev) { 40 int action = ev.getActionMasked(); 41 switch (action) { 42 case MotionEvent.ACTION_DOWN: 43 if (canScrollVertically(1)) { 44 // If we can scroll down, make sure we're not intercepted by the parent 45 final ViewParent parent = getParent(); 46 if (parent != null) { 47 parent.requestDisallowInterceptTouchEvent(true); 48 } 49 } else if (!canScrollVertically(-1)) { 50 // Don't pass on the touch to the view, because scrolling will unconditionally 51 // disallow interception even if we can't scroll. 52 // if a user can't scroll at all, we should never listen to the touch. 53 return false; 54 } 55 break; 56 } 57 return super.onTouchEvent(ev); 58 } 59 60 @Override onInterceptTouchEvent(MotionEvent ev)61 public boolean onInterceptTouchEvent(MotionEvent ev) { 62 // If there's a touch on this view and we can scroll down, we don't want to be intercepted 63 int action = ev.getActionMasked(); 64 switch (action) { 65 case MotionEvent.ACTION_DOWN: 66 // If we can scroll down, make sure non of our parents intercepts us. 67 if (canScrollVertically(1)) { 68 final ViewParent parent = getParent(); 69 if (parent != null) { 70 parent.requestDisallowInterceptTouchEvent(true); 71 } 72 } 73 mDownY = ev.getY(); 74 break; 75 case MotionEvent.ACTION_MOVE: { 76 final int y = (int) ev.getY(); 77 final float yDiff = y - mDownY; 78 if (yDiff < -mTouchSlop && !canScrollVertically(1)) { 79 // Don't intercept touches that are overscrolling. 80 return false; 81 } 82 break; 83 } 84 } 85 return super.onInterceptTouchEvent(ev); 86 } 87 getScrollRange()88 public int getScrollRange() { 89 int scrollRange = 0; 90 if (getChildCount() > 0) { 91 View child = getChildAt(0); 92 scrollRange = Math.max(0, 93 child.getHeight() - (getHeight() - mPaddingBottom - mPaddingTop)); 94 } 95 return scrollRange; 96 } 97 } 98