blob: 4df1e3bda1a516ea4fe21b4e8db374899c314709 [file] [log] [blame]
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.systemui.statusbar.phone;
18
19import android.content.Context;
20import android.view.MotionEvent;
21import android.view.ViewConfiguration;
22
23import com.android.systemui.Gefingerpoken;
Rohan Shah20790b82018-07-02 17:21:04 -070024import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
25import com.android.systemui.statusbar.notification.row.ExpandableView;
26import com.android.systemui.statusbar.notification.NotificationData;
27import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
Selim Cinekb8f09cf2015-03-16 17:09:28 -070028
29/**
Selim Cinek684a4422015-04-15 16:18:39 -070030 * A helper class to handle touches on the heads-up views.
Selim Cinekb8f09cf2015-03-16 17:09:28 -070031 */
32public class HeadsUpTouchHelper implements Gefingerpoken {
33
yoshiki iguchi4e30e762018-02-06 12:09:23 +090034 private HeadsUpManagerPhone mHeadsUpManager;
Selim Cinekb8f09cf2015-03-16 17:09:28 -070035 private NotificationStackScrollLayout mStackScroller;
36 private int mTrackingPointer;
37 private float mTouchSlop;
38 private float mInitialTouchX;
39 private float mInitialTouchY;
Selim Cinek684a4422015-04-15 16:18:39 -070040 private boolean mTouchingHeadsUpView;
Selim Cinekb8f09cf2015-03-16 17:09:28 -070041 private boolean mTrackingHeadsUp;
42 private boolean mCollapseSnoozes;
43 private NotificationPanelView mPanel;
44 private ExpandableNotificationRow mPickedChild;
45
yoshiki iguchi4e30e762018-02-06 12:09:23 +090046 public HeadsUpTouchHelper(HeadsUpManagerPhone headsUpManager,
Selim Cinek684a4422015-04-15 16:18:39 -070047 NotificationStackScrollLayout stackScroller,
48 NotificationPanelView notificationPanelView) {
49 mHeadsUpManager = headsUpManager;
50 mStackScroller = stackScroller;
51 mPanel = notificationPanelView;
52 Context context = stackScroller.getContext();
53 final ViewConfiguration configuration = ViewConfiguration.get(context);
54 mTouchSlop = configuration.getScaledTouchSlop();
55 }
56
Selim Cinekb8f09cf2015-03-16 17:09:28 -070057 public boolean isTrackingHeadsUp() {
58 return mTrackingHeadsUp;
59 }
60
61 @Override
62 public boolean onInterceptTouchEvent(MotionEvent event) {
Selim Cinek684a4422015-04-15 16:18:39 -070063 if (!mTouchingHeadsUpView && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -070064 return false;
65 }
66 int pointerIndex = event.findPointerIndex(mTrackingPointer);
67 if (pointerIndex < 0) {
68 pointerIndex = 0;
69 mTrackingPointer = event.getPointerId(pointerIndex);
70 }
71 final float x = event.getX(pointerIndex);
72 final float y = event.getY(pointerIndex);
73 switch (event.getActionMasked()) {
74 case MotionEvent.ACTION_DOWN:
75 mInitialTouchY = y;
76 mInitialTouchX = x;
77 setTrackingHeadsUp(false);
Selim Cinek35b77712015-05-11 17:00:39 -070078 ExpandableView child = mStackScroller.getChildAtRawPosition(x, y);
Selim Cinek684a4422015-04-15 16:18:39 -070079 mTouchingHeadsUpView = false;
Selim Cinekb8f09cf2015-03-16 17:09:28 -070080 if (child instanceof ExpandableNotificationRow) {
81 mPickedChild = (ExpandableNotificationRow) child;
Selim Cinek3776fe02016-02-04 13:32:43 -080082 mTouchingHeadsUpView = !mStackScroller.isExpanded()
83 && mPickedChild.isHeadsUp() && mPickedChild.isPinned();
Selim Cinek80327082018-05-04 13:42:46 -070084 } else if (child == null && !mStackScroller.isExpanded()) {
85 // We might touch above the visible heads up child, but then we still would
86 // like to capture it.
87 NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry();
88 if (topEntry != null && topEntry.row.isPinned()) {
89 mPickedChild = topEntry.row;
90 mTouchingHeadsUpView = true;
91 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -070092 }
93 break;
94 case MotionEvent.ACTION_POINTER_UP:
95 final int upPointer = event.getPointerId(event.getActionIndex());
96 if (mTrackingPointer == upPointer) {
97 // gesture is ongoing, find a new pointer to track
98 final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
99 mTrackingPointer = event.getPointerId(newIndex);
100 mInitialTouchX = event.getX(newIndex);
101 mInitialTouchY = event.getY(newIndex);
102 }
103 break;
104
105 case MotionEvent.ACTION_MOVE:
106 final float h = y - mInitialTouchY;
Selim Cinek131c1e22015-05-11 19:04:49 -0700107 if (mTouchingHeadsUpView && Math.abs(h) > mTouchSlop
108 && Math.abs(h) > Math.abs(x - mInitialTouchX)) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700109 setTrackingHeadsUp(true);
110 mCollapseSnoozes = h < 0;
111 mInitialTouchX = x;
112 mInitialTouchY = y;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800113 int startHeight = (int) (mPickedChild.getActualHeight()
114 + mPickedChild.getTranslationY());
115 mPanel.setPanelScrimMinFraction((float) startHeight
Selim Cinek3d395c62015-06-16 19:37:37 -0700116 / mPanel.getMaxPanelHeight());
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800117 mPanel.startExpandMotion(x, y, true /* startTracking */, startHeight);
Chris Wren621933f2017-06-14 15:59:03 -0400118 mPanel.startExpandingFromPeek();
Selim Cinekdef35a82016-05-03 15:52:51 -0700119 // This call needs to be after the expansion start otherwise we will get a
120 // flicker of one frame as it's not expanded yet.
felkachang3e99b0a2018-07-09 11:27:00 +0800121 mHeadsUpManager.unpinAll(true);
Xiaohui Chen9528f432016-02-12 15:03:18 -0800122 mPanel.clearNotificationEffects();
Selim Cinek31f708c2017-08-23 10:59:57 -0700123 endMotion();
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700124 return true;
125 }
126 break;
127
128 case MotionEvent.ACTION_CANCEL:
129 case MotionEvent.ACTION_UP:
Selim Cinek684a4422015-04-15 16:18:39 -0700130 if (mPickedChild != null && mTouchingHeadsUpView) {
131 // We may swallow this click if the heads up just came in.
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700132 if (mHeadsUpManager.shouldSwallowClick(
133 mPickedChild.getStatusBarNotification().getKey())) {
134 endMotion();
135 return true;
136 }
137 }
138 endMotion();
139 break;
140 }
141 return false;
142 }
143
144 private void setTrackingHeadsUp(boolean tracking) {
145 mTrackingHeadsUp = tracking;
146 mHeadsUpManager.setTrackingHeadsUp(tracking);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800147 mPanel.setTrackedHeadsUp(tracking ? mPickedChild : null);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700148 }
149
150 public void notifyFling(boolean collapse) {
151 if (collapse && mCollapseSnoozes) {
152 mHeadsUpManager.snooze();
153 }
154 mCollapseSnoozes = false;
155 }
156
157 @Override
158 public boolean onTouchEvent(MotionEvent event) {
159 if (!mTrackingHeadsUp) {
160 return false;
161 }
162 switch (event.getActionMasked()) {
163 case MotionEvent.ACTION_UP:
164 case MotionEvent.ACTION_CANCEL:
165 endMotion();
166 setTrackingHeadsUp(false);
167 break;
168 }
169 return true;
170 }
171
172 private void endMotion() {
173 mTrackingPointer = -1;
174 mPickedChild = null;
Selim Cinek684a4422015-04-15 16:18:39 -0700175 mTouchingHeadsUpView = false;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700176 }
177}