• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.example.android.vdmdemo.host;
18 
19 import android.graphics.PointF;
20 import android.hardware.input.VirtualMouseButtonEvent;
21 import android.hardware.input.VirtualMouseRelativeEvent;
22 import android.hardware.input.VirtualMouseScrollEvent;
23 import android.util.Log;
24 import android.view.Display;
25 import android.view.InputEvent;
26 import android.view.MotionEvent;
27 
28 import androidx.annotation.GuardedBy;
29 
30 import com.example.android.vdmdemo.common.RemoteEventProto.InputDeviceType;
31 
32 import java.util.Optional;
33 
34 import javax.inject.Inject;
35 import javax.inject.Singleton;
36 
37 @Singleton
38 final class InputController {
39 
40     private static final String TAG = "InputController";
41 
42     @Inject DisplayRepository mDisplayRepository;
43 
44     private final Object mLock = new Object();
45 
46     @GuardedBy("mLock")
47     private int mFocusedRemoteDisplayId = Display.INVALID_DISPLAY;
48 
49     @GuardedBy("mLock")
50     private RemoteDisplay mFocusedDisplay;
51 
52     @Inject
InputController()53     InputController() {}
54 
setFocusedRemoteDisplayId(int remoteDisplayId)55     void setFocusedRemoteDisplayId(int remoteDisplayId) {
56         synchronized (mLock) {
57             mFocusedRemoteDisplayId = remoteDisplayId;
58             mFocusedDisplay =
59                     mDisplayRepository.getDisplayByRemoteId(remoteDisplayId).orElse(null);
60         }
61     }
62 
sendEventToFocusedDisplay(InputDeviceType deviceType, InputEvent inputEvent)63     void sendEventToFocusedDisplay(InputDeviceType deviceType, InputEvent inputEvent) {
64         synchronized (mLock) {
65             getFocusedDisplayLocked().ifPresent(d -> d.processInputEvent(deviceType, inputEvent));
66         }
67     }
68 
sendHomeToFocusedDisplay()69     void sendHomeToFocusedDisplay() {
70         synchronized (mLock) {
71             getFocusedDisplayLocked().ifPresent(d -> d.goHome());
72         }
73     }
74 
sendMouseButtonEvent(int button)75     void sendMouseButtonEvent(int button) {
76         for (int action : new int[]{
77                 MotionEvent.ACTION_BUTTON_PRESS, MotionEvent.ACTION_BUTTON_RELEASE}) {
78             sendMouseEventToFocusedDisplay(
79                     new VirtualMouseButtonEvent.Builder()
80                             .setButtonCode(button)
81                             .setAction(action)
82                             .build());
83         }
84     }
85 
sendMouseRelativeEvent(float x, float y)86     void sendMouseRelativeEvent(float x, float y) {
87         sendMouseEventToFocusedDisplay(
88                 new VirtualMouseRelativeEvent.Builder()
89                         .setRelativeX(x)
90                         .setRelativeY(y)
91                         .build());
92     }
93 
sendMouseScrollEvent(float x, float y)94     void sendMouseScrollEvent(float x, float y) {
95         sendMouseEventToFocusedDisplay(
96                 new VirtualMouseScrollEvent.Builder()
97                         .setXAxisMovement(clampMouseScroll(x))
98                         .setYAxisMovement(clampMouseScroll(y))
99                         .build());
100     }
101 
sendMouseEventToFocusedDisplay(Object mouseEvent)102     private void sendMouseEventToFocusedDisplay(Object mouseEvent) {
103         synchronized (mLock) {
104             getFocusedDisplayLocked().ifPresent(d -> d.processVirtualMouseEvent(mouseEvent));
105         }
106     }
107 
sendStylusEventToFocusedDisplay(Object stylusEvent)108     void sendStylusEventToFocusedDisplay(Object stylusEvent) {
109         synchronized (mLock) {
110             getFocusedDisplayLocked().ifPresent(d -> d.processVirtualStylusEvent(stylusEvent));
111         }
112     }
113 
getFocusedDisplaySize()114     Optional<PointF> getFocusedDisplaySize() {
115         synchronized (mLock) {
116             Optional<RemoteDisplay> display = getFocusedDisplayLocked();
117             return display.isPresent()
118                     ? Optional.of(display.get().getDisplaySize())
119                     : Optional.empty();
120         }
121     }
122 
123     @GuardedBy("mLock")
getFocusedDisplayLocked()124     private Optional<RemoteDisplay> getFocusedDisplayLocked() {
125         synchronized (mLock) {
126             if (mFocusedDisplay == null) {
127                 mFocusedDisplay = mDisplayRepository.getDisplayByRemoteId(mFocusedRemoteDisplayId)
128                         .orElse(null);
129                 if (mFocusedDisplay == null) {
130                     Log.e(TAG, "Failed to inject input event, no focused display "
131                             + mFocusedRemoteDisplayId);
132                     return Optional.empty();
133                 }
134             }
135             return Optional.of(mFocusedDisplay);
136         }
137     }
138 
clampMouseScroll(float val)139     static float clampMouseScroll(float val) {
140         return Math.max(Math.min(val, 1f), -1f);
141     }
142 }
143