1 /*
2  * Copyright (C) 2011 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.server.wm;
18 
19 import android.graphics.Point;
20 import android.graphics.Rect;
21 import android.os.Binder;
22 import android.os.IBinder;
23 import android.os.Process;
24 import android.os.RemoteException;
25 import android.os.UserHandle;
26 import android.view.InputApplicationHandle;
27 import android.view.InputChannel;
28 import android.view.InputWindowHandle;
29 import android.view.SurfaceControl;
30 import android.view.WindowManager;
31 
32 import java.io.PrintWriter;
33 
34 class InputConsumerImpl implements IBinder.DeathRecipient {
35     final WindowManagerService mService;
36     final InputChannel mServerChannel, mClientChannel;
37     final InputApplicationHandle mApplicationHandle;
38     final InputWindowHandle mWindowHandle;
39 
40     final IBinder mToken;
41     final String mName;
42     final int mClientPid;
43     final UserHandle mClientUser;
44 
45     final SurfaceControl mInputSurface;
46     Rect mTmpClipRect = new Rect();
47     private final Rect mTmpRect = new Rect();
48     private final Point mOldPosition = new Point();
49     private final Rect mOldWindowCrop = new Rect();
50 
InputConsumerImpl(WindowManagerService service, IBinder token, String name, InputChannel inputChannel, int clientPid, UserHandle clientUser, int displayId)51     InputConsumerImpl(WindowManagerService service, IBinder token, String name,
52             InputChannel inputChannel, int clientPid, UserHandle clientUser, int displayId) {
53         mService = service;
54         mToken = token;
55         mName = name;
56         mClientPid = clientPid;
57         mClientUser = clientUser;
58 
59         InputChannel[] channels = InputChannel.openInputChannelPair(name);
60         mServerChannel = channels[0];
61         if (inputChannel != null) {
62             channels[1].transferTo(inputChannel);
63             channels[1].dispose();
64             mClientChannel = inputChannel;
65         } else {
66             mClientChannel = channels[1];
67         }
68         mService.mInputManager.registerInputChannel(mServerChannel);
69 
70         mApplicationHandle = new InputApplicationHandle(new Binder());
71         mApplicationHandle.name = name;
72         mApplicationHandle.dispatchingTimeoutNanos =
73                 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
74 
75         mWindowHandle = new InputWindowHandle(mApplicationHandle, displayId);
76         mWindowHandle.name = name;
77         mWindowHandle.token = mServerChannel.getToken();
78         mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
79         mWindowHandle.layoutParamsFlags = 0;
80         mWindowHandle.dispatchingTimeoutNanos =
81                 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
82         mWindowHandle.visible = true;
83         mWindowHandle.canReceiveKeys = false;
84         mWindowHandle.hasFocus = false;
85         mWindowHandle.hasWallpaper = false;
86         mWindowHandle.paused = false;
87         mWindowHandle.ownerPid = Process.myPid();
88         mWindowHandle.ownerUid = Process.myUid();
89         mWindowHandle.inputFeatures = 0;
90         mWindowHandle.scaleFactor = 1.0f;
91 
92         mInputSurface = mService.makeSurfaceBuilder(mService.mRoot.getDisplayContent(displayId).getSession())
93                 .setContainerLayer()
94                 .setName("Input Consumer " + name)
95                 .setCallsite("InputConsumerImpl")
96                 .build();
97     }
98 
linkToDeathRecipient()99     void linkToDeathRecipient() {
100         if (mToken == null) {
101             return;
102         }
103 
104         try {
105             mToken.linkToDeath(this, 0);
106         } catch (RemoteException e) {
107             // Client died, do nothing
108         }
109     }
110 
unlinkFromDeathRecipient()111     void unlinkFromDeathRecipient() {
112         if (mToken == null) {
113             return;
114         }
115 
116         mToken.unlinkToDeath(this, 0);
117     }
118 
layout(SurfaceControl.Transaction t, int dw, int dh)119     void layout(SurfaceControl.Transaction t, int dw, int dh) {
120         mTmpRect.set(0, 0, dw, dh);
121         layout(t, mTmpRect);
122     }
123 
layout(SurfaceControl.Transaction t, Rect r)124     void layout(SurfaceControl.Transaction t, Rect r) {
125         mTmpClipRect.set(0, 0, r.width(), r.height());
126 
127         if (mOldPosition.equals(r.left, r.top) && mOldWindowCrop.equals(mTmpClipRect)) {
128             return;
129         }
130 
131         t.setPosition(mInputSurface, r.left, r.top);
132         t.setWindowCrop(mInputSurface, mTmpClipRect);
133 
134         mOldPosition.set(r.left, r.top);
135         mOldWindowCrop.set(mTmpClipRect);
136     }
137 
hide(SurfaceControl.Transaction t)138     void hide(SurfaceControl.Transaction t) {
139         t.hide(mInputSurface);
140     }
141 
show(SurfaceControl.Transaction t, WindowState w)142     void show(SurfaceControl.Transaction t, WindowState w) {
143         t.show(mInputSurface);
144         t.setInputWindowInfo(mInputSurface, mWindowHandle);
145         t.setRelativeLayer(mInputSurface, w.getSurfaceControl(), 1);
146     }
147 
show(SurfaceControl.Transaction t, int layer)148     void show(SurfaceControl.Transaction t, int layer) {
149         t.show(mInputSurface);
150         t.setInputWindowInfo(mInputSurface, mWindowHandle);
151         t.setLayer(mInputSurface, layer);
152     }
153 
reparent(SurfaceControl.Transaction t, WindowContainer wc)154     void reparent(SurfaceControl.Transaction t, WindowContainer wc) {
155         t.reparent(mInputSurface, wc.getSurfaceControl());
156     }
157 
disposeChannelsLw(SurfaceControl.Transaction t)158     void disposeChannelsLw(SurfaceControl.Transaction t) {
159         mService.mInputManager.unregisterInputChannel(mServerChannel);
160         mClientChannel.dispose();
161         mServerChannel.dispose();
162         t.remove(mInputSurface);
163         unlinkFromDeathRecipient();
164     }
165 
166     @Override
binderDied()167     public void binderDied() {
168         synchronized (mService.getWindowManagerLock()) {
169             // Clean up the input consumer
170             final InputMonitor inputMonitor =
171                     mService.mRoot.getDisplayContent(mWindowHandle.displayId).getInputMonitor();
172             inputMonitor.destroyInputConsumer(mName);
173             unlinkFromDeathRecipient();
174         }
175     }
176 
dump(PrintWriter pw, String name, String prefix)177     void dump(PrintWriter pw, String name, String prefix) {
178         pw.println(prefix + "  name=" + name + " pid=" + mClientPid + " user=" + mClientUser);
179     }
180 }
181