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; 268032708409dbc7dfd072823b185cd5118368309fSelim Cinekimport com.android.systemui.statusbar.NotificationData; 27b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport com.android.systemui.statusbar.stack.NotificationStackScrollLayout; 28b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 29b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek/** 30684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek * A helper class to handle touches on the heads-up views. 31b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek */ 32b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekpublic class HeadsUpTouchHelper implements Gefingerpoken { 33b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 344e30e763473859bbe1755e446af08fc7325267b4yoshiki iguchi private HeadsUpManagerPhone mHeadsUpManager; 35b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private NotificationStackScrollLayout mStackScroller; 36b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private int mTrackingPointer; 37b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private float mTouchSlop; 38b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private float mInitialTouchX; 39b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private float mInitialTouchY; 40684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek private boolean mTouchingHeadsUpView; 41b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private boolean mTrackingHeadsUp; 42b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private boolean mCollapseSnoozes; 43b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private NotificationPanelView mPanel; 44b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private ExpandableNotificationRow mPickedChild; 45b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 464e30e763473859bbe1755e446af08fc7325267b4yoshiki iguchi public HeadsUpTouchHelper(HeadsUpManagerPhone headsUpManager, 47684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek NotificationStackScrollLayout stackScroller, 48684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek NotificationPanelView notificationPanelView) { 49684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mHeadsUpManager = headsUpManager; 50684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mStackScroller = stackScroller; 51684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mPanel = notificationPanelView; 52684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek Context context = stackScroller.getContext(); 53684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek final ViewConfiguration configuration = ViewConfiguration.get(context); 54684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mTouchSlop = configuration.getScaledTouchSlop(); 55684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek } 56684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek 57b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean isTrackingHeadsUp() { 58b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return mTrackingHeadsUp; 59b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 60b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 61b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek @Override 62b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean onInterceptTouchEvent(MotionEvent event) { 63684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek if (!mTouchingHeadsUpView && event.getActionMasked() != MotionEvent.ACTION_DOWN) { 64b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return false; 65b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 66b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek int pointerIndex = event.findPointerIndex(mTrackingPointer); 67b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (pointerIndex < 0) { 68b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek pointerIndex = 0; 69b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTrackingPointer = event.getPointerId(pointerIndex); 70b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 71b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final float x = event.getX(pointerIndex); 72b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final float y = event.getY(pointerIndex); 73b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek switch (event.getActionMasked()) { 74b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_DOWN: 75b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchY = y; 76b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchX = x; 77b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek setTrackingHeadsUp(false); 7835b7771fcbe57574d812adbc98acbba96ba47ae2Selim Cinek ExpandableView child = mStackScroller.getChildAtRawPosition(x, y); 79684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mTouchingHeadsUpView = false; 80b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (child instanceof ExpandableNotificationRow) { 81b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mPickedChild = (ExpandableNotificationRow) child; 823776fe007550451bb237c705d333247eab2a291cSelim Cinek mTouchingHeadsUpView = !mStackScroller.isExpanded() 833776fe007550451bb237c705d333247eab2a291cSelim Cinek && mPickedChild.isHeadsUp() && mPickedChild.isPinned(); 848032708409dbc7dfd072823b185cd5118368309fSelim Cinek } else if (child == null && !mStackScroller.isExpanded()) { 858032708409dbc7dfd072823b185cd5118368309fSelim Cinek // We might touch above the visible heads up child, but then we still would 868032708409dbc7dfd072823b185cd5118368309fSelim Cinek // like to capture it. 878032708409dbc7dfd072823b185cd5118368309fSelim Cinek NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry(); 888032708409dbc7dfd072823b185cd5118368309fSelim Cinek if (topEntry != null && topEntry.row.isPinned()) { 898032708409dbc7dfd072823b185cd5118368309fSelim Cinek mPickedChild = topEntry.row; 908032708409dbc7dfd072823b185cd5118368309fSelim Cinek mTouchingHeadsUpView = true; 918032708409dbc7dfd072823b185cd5118368309fSelim Cinek } 92b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 93b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 94b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_POINTER_UP: 95b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final int upPointer = event.getPointerId(event.getActionIndex()); 96b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (mTrackingPointer == upPointer) { 97b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek // gesture is ongoing, find a new pointer to track 98b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1; 99b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTrackingPointer = event.getPointerId(newIndex); 100b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchX = event.getX(newIndex); 101b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchY = event.getY(newIndex); 102b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 103b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 104b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 105b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_MOVE: 106b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final float h = y - mInitialTouchY; 107131c1e2960fa5bdf54bfb6fcd5ac98c9f728f796Selim Cinek if (mTouchingHeadsUpView && Math.abs(h) > mTouchSlop 108131c1e2960fa5bdf54bfb6fcd5ac98c9f728f796Selim Cinek && Math.abs(h) > Math.abs(x - mInitialTouchX)) { 109b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek setTrackingHeadsUp(true); 110b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mCollapseSnoozes = h < 0; 111b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchX = x; 112b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mInitialTouchY = y; 113aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek int startHeight = (int) (mPickedChild.getActualHeight() 114aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek + mPickedChild.getTranslationY()); 115aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek mPanel.setPanelScrimMinFraction((float) startHeight 1163d395c69fa67732ceb2c045d03ea81efa3710afaSelim Cinek / mPanel.getMaxPanelHeight()); 117aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek mPanel.startExpandMotion(x, y, true /* startTracking */, startHeight); 118621933fd7bd276c536e6c5c2dd8f5d411283006cChris Wren mPanel.startExpandingFromPeek(); 119def35a86530200958384191d43d321dbcda16e2aSelim Cinek // This call needs to be after the expansion start otherwise we will get a 120def35a86530200958384191d43d321dbcda16e2aSelim Cinek // flicker of one frame as it's not expanded yet. 121def35a86530200958384191d43d321dbcda16e2aSelim Cinek mHeadsUpManager.unpinAll(); 1229528f43e481e6daf07e1b66aa0740982b3b08903Xiaohui Chen mPanel.clearNotificationEffects(); 12331f708c4dc0d2ee2db1bc23a16d761275ccedf8cSelim Cinek endMotion(); 124b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 125b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 126b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 127b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 128b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_CANCEL: 129b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_UP: 130684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek if (mPickedChild != null && mTouchingHeadsUpView) { 131684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek // We may swallow this click if the heads up just came in. 132b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (mHeadsUpManager.shouldSwallowClick( 133b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mPickedChild.getStatusBarNotification().getKey())) { 134b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek endMotion(); 135b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 136b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 137b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 138b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek endMotion(); 139b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 140b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 141b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return false; 142b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 143b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 144b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private void setTrackingHeadsUp(boolean tracking) { 145b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTrackingHeadsUp = tracking; 146b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mHeadsUpManager.setTrackingHeadsUp(tracking); 147aa9db1f34fe8b4a2d143c1379ec6c0c304bbd40bSelim Cinek mPanel.setTrackedHeadsUp(tracking ? mPickedChild : null); 148b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 149b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 150b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void notifyFling(boolean collapse) { 151b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (collapse && mCollapseSnoozes) { 152b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mHeadsUpManager.snooze(); 153b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 154b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mCollapseSnoozes = false; 155b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 156b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 157b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek @Override 158b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean onTouchEvent(MotionEvent event) { 159b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (!mTrackingHeadsUp) { 160b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return false; 161b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 162b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek switch (event.getActionMasked()) { 163b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_UP: 164b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek case MotionEvent.ACTION_CANCEL: 165b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek endMotion(); 166b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek setTrackingHeadsUp(false); 167b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek break; 168b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 169b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 170b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 171b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 172b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private void endMotion() { 173b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTrackingPointer = -1; 174b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mPickedChild = null; 175684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mTouchingHeadsUpView = false; 176b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 177b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek} 178