HeadsUpTouchHelper.java revision b8f09cf5533d458868a335ce334e4880b2b0788d
1/*
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;
24import com.android.systemui.statusbar.ExpandableNotificationRow;
25import com.android.systemui.statusbar.ExpandableView;
26import com.android.systemui.statusbar.policy.HeadsUpManager;
27import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
28
29/**
30 * A Helper class to handle touches on the heads-up views
31 */
32public class HeadsUpTouchHelper implements Gefingerpoken {
33
34    private HeadsUpManager mHeadsUpManager;
35    private NotificationStackScrollLayout mStackScroller;
36    private int mTrackingPointer;
37    private float mTouchSlop;
38    private float mInitialTouchX;
39    private float mInitialTouchY;
40    private boolean mMotionOnHeadsUpView;
41    private boolean mTrackingHeadsUp;
42    private boolean mCollapseSnoozes;
43    private NotificationPanelView mPanel;
44    private ExpandableNotificationRow mPickedChild;
45
46    public boolean isTrackingHeadsUp() {
47        return mTrackingHeadsUp;
48    }
49
50    @Override
51    public boolean onInterceptTouchEvent(MotionEvent event) {
52        if (!mMotionOnHeadsUpView && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
53            return false;
54        }
55        int pointerIndex = event.findPointerIndex(mTrackingPointer);
56        if (pointerIndex < 0) {
57            pointerIndex = 0;
58            mTrackingPointer = event.getPointerId(pointerIndex);
59        }
60        final float x = event.getX(pointerIndex);
61        final float y = event.getY(pointerIndex);
62        switch (event.getActionMasked()) {
63            case MotionEvent.ACTION_DOWN:
64                mInitialTouchY = y;
65                mInitialTouchX = x;
66                setTrackingHeadsUp(false);
67                ExpandableView child = mStackScroller.getChildAtPosition(x, y);
68                mMotionOnHeadsUpView = false;
69                if (child instanceof ExpandableNotificationRow) {
70                    mPickedChild = (ExpandableNotificationRow) child;
71                    mMotionOnHeadsUpView = mPickedChild.isHeadsUp() && !mPickedChild.isInShade();
72                }
73                break;
74            case MotionEvent.ACTION_POINTER_UP:
75                final int upPointer = event.getPointerId(event.getActionIndex());
76                if (mTrackingPointer == upPointer) {
77                    // gesture is ongoing, find a new pointer to track
78                    final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
79                    mTrackingPointer = event.getPointerId(newIndex);
80                    mInitialTouchX = event.getX(newIndex);
81                    mInitialTouchY = event.getY(newIndex);
82                }
83                break;
84
85            case MotionEvent.ACTION_MOVE:
86                final float h = y - mInitialTouchY;
87                if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)) {
88                    setTrackingHeadsUp(true);
89                    mCollapseSnoozes = h < 0;
90                    mInitialTouchX = x;
91                    mInitialTouchY = y;
92                    mHeadsUpManager.releaseAllToShade();
93                    int expandedHeight = mPickedChild.getActualHeight();
94                    mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight);
95                    return true;
96                }
97                break;
98
99            case MotionEvent.ACTION_CANCEL:
100            case MotionEvent.ACTION_UP:
101                if (mPickedChild != null && mMotionOnHeadsUpView) {
102                    if (mHeadsUpManager.shouldSwallowClick(
103                            mPickedChild.getStatusBarNotification().getKey())) {
104                        endMotion();
105                        return true;
106                    }
107                }
108                endMotion();
109                break;
110        }
111        return false;
112    }
113
114    private void setTrackingHeadsUp(boolean tracking) {
115        mTrackingHeadsUp = tracking;
116        mHeadsUpManager.setTrackingHeadsUp(tracking);
117        mPanel.setTrackingHeadsUp(tracking);
118    }
119
120    public void notifyFling(boolean collapse) {
121        if (collapse && mCollapseSnoozes) {
122            mHeadsUpManager.snooze();
123        }
124        mCollapseSnoozes = false;
125    }
126
127    @Override
128    public boolean onTouchEvent(MotionEvent event) {
129        if (!mTrackingHeadsUp) {
130            return false;
131        }
132        switch (event.getActionMasked()) {
133            case MotionEvent.ACTION_UP:
134            case MotionEvent.ACTION_CANCEL:
135                endMotion();
136                setTrackingHeadsUp(false);
137                break;
138        }
139        return true;
140    }
141
142    private void endMotion() {
143        mTrackingPointer = -1;
144        mPickedChild = null;
145        mMotionOnHeadsUpView = false;
146    }
147
148    public ExpandableView getPickedChild() {
149        return mPickedChild;
150    }
151
152    public void bind(HeadsUpManager headsUpManager, NotificationStackScrollLayout stackScroller,
153            NotificationPanelView notificationPanelView) {
154        mHeadsUpManager = headsUpManager;
155        mStackScroller = stackScroller;
156        mPanel = notificationPanelView;
157        Context context = stackScroller.getContext();
158        final ViewConfiguration configuration = ViewConfiguration.get(context);
159        mTouchSlop = configuration.getScaledTouchSlop();
160    }
161}
162