1 /* 2 * Copyright (C) 2020 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 package com.android.server.wm; 17 18 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 19 import static android.view.Display.DEFAULT_DISPLAY; 20 21 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT; 22 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 23 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 24 import static com.android.server.wm.WindowManagerService.H.ON_POINTER_DOWN_OUTSIDE_FOCUS; 25 26 import android.annotation.NonNull; 27 import android.os.Debug; 28 import android.os.IBinder; 29 import android.util.Slog; 30 import android.view.InputApplicationHandle; 31 import android.view.KeyEvent; 32 import android.view.WindowManager; 33 34 import com.android.internal.util.function.pooled.PooledLambda; 35 import com.android.server.input.InputManagerService; 36 37 import java.io.PrintWriter; 38 39 final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks { 40 private static final String TAG = TAG_WITH_CLASS_NAME ? "InputManagerCallback" : TAG_WM; 41 42 private final WindowManagerService mService; 43 44 // Set to true when the first input device configuration change notification 45 // is received to indicate that the input devices are ready. 46 private final Object mInputDevicesReadyMonitor = new Object(); 47 private boolean mInputDevicesReady; 48 49 // When true, prevents input dispatch from proceeding until set to false again. 50 private boolean mInputDispatchFrozen; 51 52 // The reason the input is currently frozen or null if the input isn't frozen. 53 private String mInputFreezeReason = null; 54 55 // When true, input dispatch proceeds normally. Otherwise all events are dropped. 56 // Initially false, so that input does not get dispatched until boot is finished at 57 // which point the ActivityManager will enable dispatching. 58 private boolean mInputDispatchEnabled; 59 InputManagerCallback(WindowManagerService service)60 public InputManagerCallback(WindowManagerService service) { 61 mService = service; 62 } 63 64 /** 65 * Notifies the window manager about a broken input channel. 66 * 67 * Called by the InputManager. 68 */ 69 @Override notifyInputChannelBroken(IBinder token)70 public void notifyInputChannelBroken(IBinder token) { 71 if (token == null) { 72 return; 73 } 74 75 synchronized (mService.mGlobalLock) { 76 WindowState windowState = mService.mInputToWindowMap.get(token); 77 if (windowState != null) { 78 Slog.i(TAG_WM, "WINDOW DIED " + windowState); 79 windowState.removeIfPossible(); 80 } 81 } 82 } 83 84 /** 85 * Notifies the window manager about an application that is not responding because it has 86 * no focused window. 87 * 88 * Called by the InputManager. 89 */ 90 @Override notifyNoFocusedWindowAnr(@onNull InputApplicationHandle applicationHandle)91 public void notifyNoFocusedWindowAnr(@NonNull InputApplicationHandle applicationHandle) { 92 mService.mAnrController.notifyAppUnresponsive( 93 applicationHandle, "Application does not have a focused window"); 94 } 95 96 @Override notifyGestureMonitorUnresponsive(int pid, @NonNull String reason)97 public void notifyGestureMonitorUnresponsive(int pid, @NonNull String reason) { 98 mService.mAnrController.notifyGestureMonitorUnresponsive(pid, reason); 99 } 100 101 @Override notifyWindowUnresponsive(@onNull IBinder token, String reason)102 public void notifyWindowUnresponsive(@NonNull IBinder token, String reason) { 103 mService.mAnrController.notifyWindowUnresponsive(token, reason); 104 } 105 106 @Override notifyGestureMonitorResponsive(int pid)107 public void notifyGestureMonitorResponsive(int pid) { 108 mService.mAnrController.notifyGestureMonitorResponsive(pid); 109 } 110 111 @Override notifyWindowResponsive(@onNull IBinder token)112 public void notifyWindowResponsive(@NonNull IBinder token) { 113 mService.mAnrController.notifyWindowResponsive(token); 114 } 115 116 /** Notifies that the input device configuration has changed. */ 117 @Override notifyConfigurationChanged()118 public void notifyConfigurationChanged() { 119 synchronized (mService.mGlobalLock) { 120 mService.mRoot.forAllDisplays(DisplayContent::sendNewConfiguration); 121 } 122 123 synchronized (mInputDevicesReadyMonitor) { 124 if (!mInputDevicesReady) { 125 mInputDevicesReady = true; 126 mInputDevicesReadyMonitor.notifyAll(); 127 } 128 } 129 } 130 131 /** Notifies that the lid switch changed state. */ 132 @Override notifyLidSwitchChanged(long whenNanos, boolean lidOpen)133 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { 134 mService.mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen); 135 } 136 137 /** Notifies that the camera lens cover state has changed. */ 138 @Override notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered)139 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered) { 140 mService.mPolicy.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered); 141 } 142 143 /** 144 * Provides an opportunity for the window manager policy to intercept early key 145 * processing as soon as the key has been read from the device. 146 */ 147 @Override interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)148 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { 149 return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags); 150 } 151 152 /** {@inheritDoc} */ 153 @Override interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, int policyFlags)154 public int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, 155 int policyFlags) { 156 return mService.mPolicy.interceptMotionBeforeQueueingNonInteractive( 157 displayId, whenNanos, policyFlags); 158 } 159 160 /** 161 * Provides an opportunity for the window manager policy to process a key before 162 * ordinary dispatch. 163 */ 164 @Override interceptKeyBeforeDispatching( IBinder focusedToken, KeyEvent event, int policyFlags)165 public long interceptKeyBeforeDispatching( 166 IBinder focusedToken, KeyEvent event, int policyFlags) { 167 return mService.mPolicy.interceptKeyBeforeDispatching(focusedToken, event, policyFlags); 168 } 169 170 /** 171 * Provides an opportunity for the window manager policy to process a key that 172 * the application did not handle. 173 */ 174 @Override dispatchUnhandledKey( IBinder focusedToken, KeyEvent event, int policyFlags)175 public KeyEvent dispatchUnhandledKey( 176 IBinder focusedToken, KeyEvent event, int policyFlags) { 177 return mService.mPolicy.dispatchUnhandledKey(focusedToken, event, policyFlags); 178 } 179 180 /** Callback to get pointer layer. */ 181 @Override getPointerLayer()182 public int getPointerLayer() { 183 return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_POINTER) 184 * WindowManagerService.TYPE_LAYER_MULTIPLIER 185 + WindowManagerService.TYPE_LAYER_OFFSET; 186 } 187 188 /** Callback to get pointer display id. */ 189 @Override getPointerDisplayId()190 public int getPointerDisplayId() { 191 synchronized (mService.mGlobalLock) { 192 // If desktop mode is not enabled, show on the default display. 193 if (!mService.mForceDesktopModeOnExternalDisplays) { 194 return DEFAULT_DISPLAY; 195 } 196 197 // Look for the topmost freeform display. 198 int firstExternalDisplayId = DEFAULT_DISPLAY; 199 for (int i = mService.mRoot.mChildren.size() - 1; i >= 0; --i) { 200 final DisplayContent displayContent = mService.mRoot.mChildren.get(i); 201 // Heuristic solution here. Currently when "Freeform windows" developer option is 202 // enabled we automatically put secondary displays in freeform mode and emulating 203 // "desktop mode". It also makes sense to show the pointer on the same display. 204 if (displayContent.getWindowingMode() == WINDOWING_MODE_FREEFORM) { 205 return displayContent.getDisplayId(); 206 } 207 208 if (firstExternalDisplayId == DEFAULT_DISPLAY 209 && displayContent.getDisplayId() != DEFAULT_DISPLAY) { 210 firstExternalDisplayId = displayContent.getDisplayId(); 211 } 212 } 213 214 // Look for the topmost non-default display 215 return firstExternalDisplayId; 216 } 217 } 218 219 @Override onPointerDownOutsideFocus(IBinder touchedToken)220 public void onPointerDownOutsideFocus(IBinder touchedToken) { 221 mService.mH.obtainMessage(ON_POINTER_DOWN_OUTSIDE_FOCUS, touchedToken).sendToTarget(); 222 } 223 224 @Override notifyFocusChanged(IBinder oldToken, IBinder newToken)225 public void notifyFocusChanged(IBinder oldToken, IBinder newToken) { 226 mService.mH.sendMessage(PooledLambda.obtainMessage( 227 mService::reportFocusChanged, oldToken, newToken)); 228 } 229 230 @Override notifyDropWindow(IBinder token, float x, float y)231 public void notifyDropWindow(IBinder token, float x, float y) { 232 mService.mH.sendMessage(PooledLambda.obtainMessage( 233 mService.mDragDropController::reportDropWindow, token, x, y)); 234 } 235 236 /** Waits until the built-in input devices have been configured. */ waitForInputDevicesReady(long timeoutMillis)237 public boolean waitForInputDevicesReady(long timeoutMillis) { 238 synchronized (mInputDevicesReadyMonitor) { 239 if (!mInputDevicesReady) { 240 try { 241 mInputDevicesReadyMonitor.wait(timeoutMillis); 242 } catch (InterruptedException ex) { 243 } 244 } 245 return mInputDevicesReady; 246 } 247 } 248 freezeInputDispatchingLw()249 public void freezeInputDispatchingLw() { 250 if (!mInputDispatchFrozen) { 251 if (DEBUG_INPUT) { 252 Slog.v(TAG_WM, "Freezing input dispatching"); 253 } 254 255 mInputDispatchFrozen = true; 256 257 if (DEBUG_INPUT) { 258 mInputFreezeReason = Debug.getCallers(6); 259 } 260 updateInputDispatchModeLw(); 261 } 262 } 263 thawInputDispatchingLw()264 public void thawInputDispatchingLw() { 265 if (mInputDispatchFrozen) { 266 if (DEBUG_INPUT) { 267 Slog.v(TAG_WM, "Thawing input dispatching"); 268 } 269 270 mInputDispatchFrozen = false; 271 mInputFreezeReason = null; 272 updateInputDispatchModeLw(); 273 } 274 } 275 setEventDispatchingLw(boolean enabled)276 public void setEventDispatchingLw(boolean enabled) { 277 if (mInputDispatchEnabled != enabled) { 278 if (DEBUG_INPUT) { 279 Slog.v(TAG_WM, "Setting event dispatching to " + enabled); 280 } 281 282 mInputDispatchEnabled = enabled; 283 updateInputDispatchModeLw(); 284 } 285 } 286 updateInputDispatchModeLw()287 private void updateInputDispatchModeLw() { 288 mService.mInputManager.setInputDispatchMode(mInputDispatchEnabled, mInputDispatchFrozen); 289 } 290 dump(PrintWriter pw, String prefix)291 void dump(PrintWriter pw, String prefix) { 292 if (mInputFreezeReason != null) { 293 pw.println(prefix + "mInputFreezeReason=" + mInputFreezeReason); 294 } 295 } 296 } 297