1 /*
2  * Copyright (C) 2022 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 
17 package com.android.systemui.dreams.touch;
18 
19 import static com.android.systemui.dreams.touch.dagger.DreamTouchModule.INPUT_SESSION_NAME;
20 import static com.android.systemui.dreams.touch.dagger.DreamTouchModule.PILFER_ON_GESTURE_CONSUME;
21 
22 import android.os.Looper;
23 import android.view.Choreographer;
24 import android.view.GestureDetector;
25 import android.view.MotionEvent;
26 
27 import com.android.systemui.settings.DisplayTracker;
28 import com.android.systemui.shared.system.InputChannelCompat;
29 import com.android.systemui.shared.system.InputMonitorCompat;
30 
31 import javax.inject.Inject;
32 import javax.inject.Named;
33 
34 /**
35  * {@link InputSession} encapsulates components behind input monitoring and handles their lifecycle.
36  * Sessions are meant to be disposable; actions such as exclusively capturing touch events is modal
37  * and destroying the sessions allows a reset. Additionally, {@link InputSession} is meant to have
38  * a single listener for input and gesture. Any broadcasting must be accomplished elsewhere.
39  */
40 public class InputSession {
41     private final InputMonitorCompat mInputMonitor;
42     private final InputChannelCompat.InputEventReceiver mInputEventReceiver;
43     private final GestureDetector mGestureDetector;
44 
45     /**
46      * Default session constructor.
47      * @param sessionName The session name that will be applied to the underlying
48      * {@link InputMonitorCompat}.
49      * @param inputEventListener A listener to receive input events.
50      * @param gestureListener A listener to receive gesture events.
51      * @param pilferOnGestureConsume Whether touch events should be pilfered after a gesture has
52      *                               been consumed.
53      */
54     @Inject
InputSession(@amedINPUT_SESSION_NAME) String sessionName, InputChannelCompat.InputEventListener inputEventListener, GestureDetector.OnGestureListener gestureListener, DisplayTracker displayTracker, @Named(PILFER_ON_GESTURE_CONSUME) boolean pilferOnGestureConsume)55     public InputSession(@Named(INPUT_SESSION_NAME) String sessionName,
56             InputChannelCompat.InputEventListener inputEventListener,
57             GestureDetector.OnGestureListener gestureListener,
58             DisplayTracker displayTracker,
59             @Named(PILFER_ON_GESTURE_CONSUME) boolean pilferOnGestureConsume) {
60         mInputMonitor = new InputMonitorCompat(sessionName, displayTracker.getDefaultDisplayId());
61         mGestureDetector = new GestureDetector(gestureListener);
62 
63         mInputEventReceiver = mInputMonitor.getInputReceiver(Looper.getMainLooper(),
64                 Choreographer.getInstance(),
65                 ev -> {
66                     // Process event. Since sometimes input may be a prerequisite for some
67                     // gesture logic, process input first.
68                     inputEventListener.onInputEvent(ev);
69 
70                     if (ev instanceof MotionEvent
71                             && mGestureDetector.onTouchEvent((MotionEvent) ev)
72                             && pilferOnGestureConsume) {
73                         mInputMonitor.pilferPointers();
74                     }
75                 });
76     }
77 
78     /**
79      * Destroys the {@link InputSession}, removing any component from listening to future touch
80      * events.
81      */
dispose()82     public void dispose() {
83         if (mInputEventReceiver != null) {
84             mInputEventReceiver.dispose();
85         }
86 
87         if (mInputMonitor != null) {
88             mInputMonitor.dispose();
89         }
90     }
91 }
92