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 32 private float mDownY; 33 private boolean mScrollEnabled = true; 34 private boolean mPreventingIntercept; 35 NonInterceptingScrollView(Context context, AttributeSet attrs)36 public NonInterceptingScrollView(Context context, AttributeSet attrs) { 37 super(context, attrs); 38 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 39 } 40 isPreventingIntercept()41 public boolean isPreventingIntercept() { 42 return mPreventingIntercept; 43 } 44 45 @Override onTouchEvent(MotionEvent ev)46 public boolean onTouchEvent(MotionEvent ev) { 47 int action = ev.getActionMasked(); 48 switch (action) { 49 case MotionEvent.ACTION_DOWN: 50 mPreventingIntercept = false; 51 if (canScrollVertically(1)) { 52 // If we can scroll down, make sure we're not intercepted by the parent 53 mPreventingIntercept = true; 54 final ViewParent parent = getParent(); 55 if (parent != null) { 56 parent.requestDisallowInterceptTouchEvent(true); 57 } 58 } else if (!canScrollVertically(-1)) { 59 // Don't pass on the touch to the view, because scrolling will unconditionally 60 // disallow interception even if we can't scroll. 61 // if a user can't scroll at all, we should never listen to the touch. 62 return false; 63 } 64 break; 65 } 66 return super.onTouchEvent(ev); 67 } 68 69 @Override onInterceptTouchEvent(MotionEvent ev)70 public boolean onInterceptTouchEvent(MotionEvent ev) { 71 // If there's a touch on this view and we can scroll down, we don't want to be intercepted 72 int action = ev.getActionMasked(); 73 74 switch (action) { 75 case MotionEvent.ACTION_DOWN: 76 mPreventingIntercept = false; 77 // If we can scroll down, make sure none of our parents intercepts us. 78 if (canScrollVertically(1)) { 79 mPreventingIntercept = true; 80 final ViewParent parent = getParent(); 81 if (parent != null) { 82 parent.requestDisallowInterceptTouchEvent(true); 83 } 84 } 85 mDownY = ev.getY(); 86 break; 87 case MotionEvent.ACTION_MOVE: { 88 final int y = (int) ev.getY(); 89 final float yDiff = y - mDownY; 90 if (yDiff < -mTouchSlop && !canScrollVertically(1)) { 91 // Don't intercept touches that are overscrolling. 92 return false; 93 } 94 break; 95 } 96 } 97 return super.onInterceptTouchEvent(ev); 98 } 99 100 @Override canScrollVertically(int direction)101 public boolean canScrollVertically(int direction) { 102 return mScrollEnabled && super.canScrollVertically(direction); 103 } 104 105 @Override canScrollHorizontally(int direction)106 public boolean canScrollHorizontally(int direction) { 107 return mScrollEnabled && super.canScrollHorizontally(direction); 108 } 109 getScrollRange()110 public int getScrollRange() { 111 int scrollRange = 0; 112 if (getChildCount() > 0) { 113 View child = getChildAt(0); 114 scrollRange = Math.max(0, 115 child.getHeight() - (getHeight() - mPaddingBottom - mPaddingTop)); 116 } 117 return scrollRange; 118 } 119 120 /** 121 * Enable scrolling for this view. Needed because the view might be clipped but still intercepts 122 * touches on the lockscreen. 123 */ setScrollingEnabled(boolean enabled)124 public void setScrollingEnabled(boolean enabled) { 125 mScrollEnabled = enabled; 126 } 127 } 128