HeadsUpTouchHelper.java revision aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40b
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; 24b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport com.android.systemui.statusbar.ExpandableNotificationRow; 25b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport com.android.systemui.statusbar.ExpandableView; 26b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport com.android.systemui.statusbar.stack.NotificationStackScrollLayout; 27b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 28b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek/** 29684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek * A helper class to handle touches on the heads-up views. 30b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek */ 31b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekpublic class HeadsUpTouchHelper implements Gefingerpoken { 32b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 334e30e763473859bbe1755e446af08fc7325267b4yoshiki iguchi private HeadsUpManagerPhone mHeadsUpManager; 34b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private NotificationStackScrollLayout mStackScroller; 35b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private int mTrackingPointer; 36b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private float mTouchSlop; 37b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private float mInitialTouchX; 38b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private float mInitialTouchY; 39684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek private boolean mTouchingHeadsUpView; 40b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private boolean mTrackingHeadsUp; 41b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private boolean mCollapseSnoozes; 42b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private NotificationPanelView mPanel; 43b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private ExpandableNotificationRow mPickedChild; 44b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 454e30e763473859bbe1755e446af08fc7325267b4yoshiki iguchi public HeadsUpTouchHelper(HeadsUpManagerPhone headsUpManager, 46684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek NotificationStackScrollLayout stackScroller, 47684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek NotificationPanelView notificationPanelView) { 48684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mHeadsUpManager = headsUpManager; 49684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mStackScroller = stackScroller; 50684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mPanel = notificationPanelView; 51684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek Context context = stackScroller.getContext(); 52684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek final ViewConfiguration configuration = ViewConfiguration.get(context); 53684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mTouchSlop = configuration.getScaledTouchSlop(); 54684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek } 55684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek 56b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean isTrackingHeadsUp() { 57b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return mTrackingHeadsUp; 58b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 59b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 60b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek @Override 61b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean onInterceptTouchEvent(MotionEvent event) { 62684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek if (!mTouchingHeadsUpView && event.getActionMasked() != MotionEvent.ACTION_DOWN) { 63b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return false; 64b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 65b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek int pointerIndex = event.findPointerIndex(mTrackingPointer); 66b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (pointerIndex < 0) { 67b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek pointerIndex = 0; 68b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTrackingPointer = event.getPointerId(pointerIndex); 69b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 70b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final float x = event.getX(pointerIndex); 71b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final float y = event.getY(pointerIndex); 72b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek switch (event.getActionMasked()) { 73b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_DOWN: 74b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchY = y; 75b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchX = x; 76b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek setTrackingHeadsUp(false); 7735b7771fcbe57574d812adbc98acbba96ba47ae2Selim Cinek ExpandableView child = mStackScroller.getChildAtRawPosition(x, y); 78684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mTouchingHeadsUpView = false; 79b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (child instanceof ExpandableNotificationRow) { 80b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mPickedChild = (ExpandableNotificationRow) child; 813776fe007550451bb237c705d333247eab2a291cSelim Cinek mTouchingHeadsUpView = !mStackScroller.isExpanded() 823776fe007550451bb237c705d333247eab2a291cSelim Cinek && mPickedChild.isHeadsUp() && mPickedChild.isPinned(); 83b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 84b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 85b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_POINTER_UP: 86b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final int upPointer = event.getPointerId(event.getActionIndex()); 87b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (mTrackingPointer == upPointer) { 88b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek // gesture is ongoing, find a new pointer to track 89b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1; 90b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTrackingPointer = event.getPointerId(newIndex); 91b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchX = event.getX(newIndex); 92b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchY = event.getY(newIndex); 93b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 94b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 95b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 96b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_MOVE: 97b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final float h = y - mInitialTouchY; 98131c1e2960fa5bdf54bfb6fcd5ac98c9f728f796Selim Cinek if (mTouchingHeadsUpView && Math.abs(h) > mTouchSlop 99131c1e2960fa5bdf54bfb6fcd5ac98c9f728f796Selim Cinek && Math.abs(h) > Math.abs(x - mInitialTouchX)) { 100b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek setTrackingHeadsUp(true); 101b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mCollapseSnoozes = h < 0; 102b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchX = x; 103b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchY = y; 104aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek int startHeight = (int) (mPickedChild.getActualHeight() 105aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek + mPickedChild.getTranslationY()); 106aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek mPanel.setPanelScrimMinFraction((float) startHeight 1073d395c69fa67732ceb2c045d03ea81efa3710afaSelim Cinek / mPanel.getMaxPanelHeight()); 108aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek mPanel.startExpandMotion(x, y, true /* startTracking */, startHeight); 109621933fd7bd276c536e6c5c2dd8f5d411283006cChris Wren mPanel.startExpandingFromPeek(); 110def35a86530200958384191d43d321dbcda16e2aSelim Cinek // This call needs to be after the expansion start otherwise we will get a 111def35a86530200958384191d43d321dbcda16e2aSelim Cinek // flicker of one frame as it's not expanded yet. 112def35a86530200958384191d43d321dbcda16e2aSelim Cinek mHeadsUpManager.unpinAll(); 1139528f43e481e6daf07e1b66aa0740982b3b08903Xiaohui Chen mPanel.clearNotificationEffects(); 11431f708c4dc0d2ee2db1bc23a16d761275ccedf8cSelim Cinek endMotion(); 115b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 116b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 117b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 118b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 119b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_CANCEL: 120b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_UP: 121684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek if (mPickedChild != null && mTouchingHeadsUpView) { 122684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek // We may swallow this click if the heads up just came in. 123b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (mHeadsUpManager.shouldSwallowClick( 124b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mPickedChild.getStatusBarNotification().getKey())) { 125b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek endMotion(); 126b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 127b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 128b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 129b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek endMotion(); 130b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 131b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 132b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return false; 133b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 134b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 135b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private void setTrackingHeadsUp(boolean tracking) { 136b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTrackingHeadsUp = tracking; 137b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mHeadsUpManager.setTrackingHeadsUp(tracking); 138aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek mPanel.setTrackedHeadsUp(tracking ? mPickedChild : null); 139b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 140b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 141b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void notifyFling(boolean collapse) { 142b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (collapse && mCollapseSnoozes) { 143b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mHeadsUpManager.snooze(); 144b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 145b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mCollapseSnoozes = false; 146b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 147b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 148b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek @Override 149b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean onTouchEvent(MotionEvent event) { 150b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (!mTrackingHeadsUp) { 151b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return false; 152b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 153b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek switch (event.getActionMasked()) { 154b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_UP: 155b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_CANCEL: 156b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek endMotion(); 157b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek setTrackingHeadsUp(false); 158b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 159b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 160b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 161b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 162b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 163b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private void endMotion() { 164b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTrackingPointer = -1; 165b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mPickedChild = null; 166684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mTouchingHeadsUpView = false; 167b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 168b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek} 169