HeadsUpTouchHelper.java revision 3d395c69fa67732ceb2c045d03ea81efa3710afa
1b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek/* 2b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * Copyright (C) 2015 The Android Open Source Project 3b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * 4b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * Licensed under the Apache License, Version 2.0 (the "License"); 5b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * you may not use this file except in compliance with the License. 6b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * You may obtain a copy of the License at 7b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * 8b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * http://www.apache.org/licenses/LICENSE-2.0 9b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * 10b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * Unless required by applicable law or agreed to in writing, software 11b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * distributed under the License is distributed on an "AS IS" BASIS, 12b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * See the License for the specific language governing permissions and 14b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * limitations under the License 15b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek */ 16b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 17b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekpackage com.android.systemui.statusbar.phone; 18b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 19b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.content.Context; 20b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.view.MotionEvent; 21b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.view.ViewConfiguration; 22b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 23b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport com.android.systemui.Gefingerpoken; 2479d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinekimport com.android.systemui.R; 25b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport com.android.systemui.statusbar.ExpandableNotificationRow; 26b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport com.android.systemui.statusbar.ExpandableView; 27b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport com.android.systemui.statusbar.policy.HeadsUpManager; 28b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport com.android.systemui.statusbar.stack.NotificationStackScrollLayout; 29b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 30b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek/** 31684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek * A helper class to handle touches on the heads-up views. 32b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek */ 33b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekpublic class HeadsUpTouchHelper implements Gefingerpoken { 34b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 35b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private HeadsUpManager mHeadsUpManager; 36b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private NotificationStackScrollLayout mStackScroller; 37b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private int mTrackingPointer; 38b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private float mTouchSlop; 39b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private float mInitialTouchX; 40b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private float mInitialTouchY; 41684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek private boolean mTouchingHeadsUpView; 42b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private boolean mTrackingHeadsUp; 43b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private boolean mCollapseSnoozes; 44b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private NotificationPanelView mPanel; 45b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private ExpandableNotificationRow mPickedChild; 4679d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek private final int mNotificationsTopPadding; 47b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 48684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek public HeadsUpTouchHelper(HeadsUpManager headsUpManager, 49684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek NotificationStackScrollLayout stackScroller, 50684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek NotificationPanelView notificationPanelView) { 51684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mHeadsUpManager = headsUpManager; 52684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mStackScroller = stackScroller; 53684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mPanel = notificationPanelView; 54684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek Context context = stackScroller.getContext(); 55684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek final ViewConfiguration configuration = ViewConfiguration.get(context); 56684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mTouchSlop = configuration.getScaledTouchSlop(); 5779d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek mNotificationsTopPadding = context.getResources() 5879d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek .getDimensionPixelSize(R.dimen.notifications_top_padding); 59684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek } 60684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek 61b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean isTrackingHeadsUp() { 62b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return mTrackingHeadsUp; 63b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 64b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 65b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek @Override 66b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean onInterceptTouchEvent(MotionEvent event) { 67684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek if (!mTouchingHeadsUpView && event.getActionMasked() != MotionEvent.ACTION_DOWN) { 68b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return false; 69b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 70b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek int pointerIndex = event.findPointerIndex(mTrackingPointer); 71b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (pointerIndex < 0) { 72b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek pointerIndex = 0; 73b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTrackingPointer = event.getPointerId(pointerIndex); 74b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 75b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final float x = event.getX(pointerIndex); 76b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final float y = event.getY(pointerIndex); 77b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek switch (event.getActionMasked()) { 78b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_DOWN: 79b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchY = y; 80b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchX = x; 81b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek setTrackingHeadsUp(false); 8235b7771fcbe57574d812adbc98acbba96ba47ae2Selim Cinek ExpandableView child = mStackScroller.getChildAtRawPosition(x, y); 8379d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek if (child == null && y < mNotificationsTopPadding) { 8479d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek // We should also allow drags from the margin above the heads up 8579d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek child = mStackScroller.getChildAtRawPosition(x, y + mNotificationsTopPadding); 8679d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek } 87684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mTouchingHeadsUpView = false; 88b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (child instanceof ExpandableNotificationRow) { 89b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mPickedChild = (ExpandableNotificationRow) child; 90684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mTouchingHeadsUpView = mPickedChild.isHeadsUp() && mPickedChild.isPinned(); 91b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 92b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 93b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_POINTER_UP: 94b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final int upPointer = event.getPointerId(event.getActionIndex()); 95b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (mTrackingPointer == upPointer) { 96b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek // gesture is ongoing, find a new pointer to track 97b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1; 98b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTrackingPointer = event.getPointerId(newIndex); 99b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchX = event.getX(newIndex); 100b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchY = event.getY(newIndex); 101b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 102b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 103b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 104b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_MOVE: 105b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final float h = y - mInitialTouchY; 106131c1e2960fa5bdf54bfb6fcd5ac98c9f728f796Selim Cinek if (mTouchingHeadsUpView && Math.abs(h) > mTouchSlop 107131c1e2960fa5bdf54bfb6fcd5ac98c9f728f796Selim Cinek && Math.abs(h) > Math.abs(x - mInitialTouchX)) { 108b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek setTrackingHeadsUp(true); 109b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mCollapseSnoozes = h < 0; 110b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchX = x; 111b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchY = y; 112b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek int expandedHeight = mPickedChild.getActualHeight(); 1133d395c69fa67732ceb2c045d03ea81efa3710afaSelim Cinek mPanel.setPanelScrimMinFraction((float) expandedHeight 1143d395c69fa67732ceb2c045d03ea81efa3710afaSelim Cinek / mPanel.getMaxPanelHeight()); 11579d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight 11679d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek + mNotificationsTopPadding); 117131c1e2960fa5bdf54bfb6fcd5ac98c9f728f796Selim Cinek mHeadsUpManager.unpinAll(); 118b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 119b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 120b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 121b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 122b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_CANCEL: 123b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_UP: 124684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek if (mPickedChild != null && mTouchingHeadsUpView) { 125684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek // We may swallow this click if the heads up just came in. 126b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (mHeadsUpManager.shouldSwallowClick( 127b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mPickedChild.getStatusBarNotification().getKey())) { 128b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek endMotion(); 129b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 130b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 131b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 132b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek endMotion(); 133b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 134b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 135b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return false; 136b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 137b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 138b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private void setTrackingHeadsUp(boolean tracking) { 139b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTrackingHeadsUp = tracking; 140b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mHeadsUpManager.setTrackingHeadsUp(tracking); 141b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mPanel.setTrackingHeadsUp(tracking); 142b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 143b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 144b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void notifyFling(boolean collapse) { 145b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (collapse && mCollapseSnoozes) { 146b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mHeadsUpManager.snooze(); 147b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 148b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mCollapseSnoozes = false; 149b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 150b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 151b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek @Override 152b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean onTouchEvent(MotionEvent event) { 153b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (!mTrackingHeadsUp) { 154b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return false; 155b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 156b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek switch (event.getActionMasked()) { 157b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_UP: 158b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_CANCEL: 159b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek endMotion(); 160b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek setTrackingHeadsUp(false); 161b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 162b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 163b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 164b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 165b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 166b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private void endMotion() { 167b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTrackingPointer = -1; 168b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mPickedChild = null; 169684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mTouchingHeadsUpView = false; 170b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 171b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek} 172