1 package com.android.server.wm; 2 3 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 4 import static android.view.Display.DEFAULT_DISPLAY; 5 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 6 7 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT; 8 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 9 import static com.android.server.wm.WindowManagerService.H.ON_POINTER_DOWN_OUTSIDE_FOCUS; 10 11 import android.os.Debug; 12 import android.os.IBinder; 13 import android.util.Slog; 14 import android.view.KeyEvent; 15 import android.view.WindowManager; 16 17 import com.android.server.input.InputManagerService; 18 19 import java.io.PrintWriter; 20 21 final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks { 22 private final WindowManagerService mService; 23 24 // Set to true when the first input device configuration change notification 25 // is received to indicate that the input devices are ready. 26 private final Object mInputDevicesReadyMonitor = new Object(); 27 private boolean mInputDevicesReady; 28 29 // When true, prevents input dispatch from proceeding until set to false again. 30 private boolean mInputDispatchFrozen; 31 32 // The reason the input is currently frozen or null if the input isn't frozen. 33 private String mInputFreezeReason = null; 34 35 // When true, input dispatch proceeds normally. Otherwise all events are dropped. 36 // Initially false, so that input does not get dispatched until boot is finished at 37 // which point the ActivityManager will enable dispatching. 38 private boolean mInputDispatchEnabled; 39 InputManagerCallback(WindowManagerService service)40 public InputManagerCallback(WindowManagerService service) { 41 mService = service; 42 } 43 44 /** 45 * Notifies the window manager about a broken input channel. 46 * 47 * Called by the InputManager. 48 */ 49 @Override notifyInputChannelBroken(IBinder token)50 public void notifyInputChannelBroken(IBinder token) { 51 if (token == null) { 52 return; 53 } 54 55 synchronized (mService.mGlobalLock) { 56 WindowState windowState = mService.windowForClientLocked(null, token, false); 57 if (windowState != null) { 58 Slog.i(TAG_WM, "WINDOW DIED " + windowState); 59 windowState.removeIfPossible(); 60 } 61 } 62 } 63 64 /** 65 * Notifies the window manager about an application that is not responding. 66 * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch. 67 * 68 * Called by the InputManager. 69 */ 70 @Override notifyANR(IBinder token, String reason)71 public long notifyANR(IBinder token, String reason) { 72 AppWindowToken appWindowToken = null; 73 WindowState windowState = null; 74 boolean aboveSystem = false; 75 synchronized (mService.mGlobalLock) { 76 if (token != null) { 77 windowState = mService.windowForClientLocked(null, token, false); 78 if (windowState != null) { 79 appWindowToken = windowState.mAppToken; 80 } 81 } 82 83 if (windowState != null) { 84 Slog.i(TAG_WM, "Input event dispatching timed out " 85 + "sending to " + windowState.mAttrs.getTitle() 86 + ". Reason: " + reason); 87 // Figure out whether this window is layered above system windows. 88 // We need to do this here to help the activity manager know how to 89 // layer its ANR dialog. 90 int systemAlertLayer = mService.mPolicy.getWindowLayerFromTypeLw( 91 TYPE_APPLICATION_OVERLAY, windowState.mOwnerCanAddInternalSystemWindow); 92 aboveSystem = windowState.mBaseLayer > systemAlertLayer; 93 } else if (appWindowToken != null) { 94 Slog.i(TAG_WM, "Input event dispatching timed out " 95 + "sending to application " + appWindowToken.stringName 96 + ". Reason: " + reason); 97 } else { 98 Slog.i(TAG_WM, "Input event dispatching timed out " 99 + ". Reason: " + reason); 100 } 101 102 mService.saveANRStateLocked(appWindowToken, windowState, reason); 103 } 104 105 // All the calls below need to happen without the WM lock held since they call into AM. 106 mService.mAtmInternal.saveANRState(reason); 107 108 if (appWindowToken != null && appWindowToken.appToken != null) { 109 // Notify the activity manager about the timeout and let it decide whether 110 // to abort dispatching or keep waiting. 111 final boolean abort = appWindowToken.keyDispatchingTimedOut(reason, 112 (windowState != null) ? windowState.mSession.mPid : -1); 113 if (!abort) { 114 // The activity manager declined to abort dispatching. 115 // Wait a bit longer and timeout again later. 116 return appWindowToken.mInputDispatchingTimeoutNanos; 117 } 118 } else if (windowState != null) { 119 // Notify the activity manager about the timeout and let it decide whether 120 // to abort dispatching or keep waiting. 121 long timeout = mService.mAmInternal.inputDispatchingTimedOut( 122 windowState.mSession.mPid, aboveSystem, reason); 123 if (timeout >= 0) { 124 // The activity manager declined to abort dispatching. 125 // Wait a bit longer and timeout again later. 126 return timeout * 1000000L; // nanoseconds 127 } 128 } 129 return 0; // abort dispatching 130 } 131 132 /** Notifies that the input device configuration has changed. */ 133 @Override notifyConfigurationChanged()134 public void notifyConfigurationChanged() { 135 // TODO(multi-display): Notify proper displays that are associated with this input device. 136 mService.sendNewConfiguration(DEFAULT_DISPLAY); 137 138 synchronized (mInputDevicesReadyMonitor) { 139 if (!mInputDevicesReady) { 140 mInputDevicesReady = true; 141 mInputDevicesReadyMonitor.notifyAll(); 142 } 143 } 144 } 145 146 /** Notifies that the lid switch changed state. */ 147 @Override notifyLidSwitchChanged(long whenNanos, boolean lidOpen)148 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { 149 mService.mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen); 150 } 151 152 /** Notifies that the camera lens cover state has changed. */ 153 @Override notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered)154 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered) { 155 mService.mPolicy.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered); 156 } 157 158 /** 159 * Provides an opportunity for the window manager policy to intercept early key 160 * processing as soon as the key has been read from the device. 161 */ 162 @Override interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)163 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { 164 return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags); 165 } 166 167 /** {@inheritDoc} */ 168 @Override interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, int policyFlags)169 public int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, 170 int policyFlags) { 171 return mService.mPolicy.interceptMotionBeforeQueueingNonInteractive( 172 displayId, whenNanos, policyFlags); 173 } 174 175 /** 176 * Provides an opportunity for the window manager policy to process a key before 177 * ordinary dispatch. 178 */ 179 @Override interceptKeyBeforeDispatching( IBinder focus, KeyEvent event, int policyFlags)180 public long interceptKeyBeforeDispatching( 181 IBinder focus, KeyEvent event, int policyFlags) { 182 WindowState windowState = mService.windowForClientLocked(null, focus, false); 183 return mService.mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags); 184 } 185 186 /** 187 * Provides an opportunity for the window manager policy to process a key that 188 * the application did not handle. 189 */ 190 @Override dispatchUnhandledKey( IBinder focus, KeyEvent event, int policyFlags)191 public KeyEvent dispatchUnhandledKey( 192 IBinder focus, KeyEvent event, int policyFlags) { 193 WindowState windowState = mService.windowForClientLocked(null, focus, false); 194 return mService.mPolicy.dispatchUnhandledKey(windowState, event, policyFlags); 195 } 196 197 /** Callback to get pointer layer. */ 198 @Override getPointerLayer()199 public int getPointerLayer() { 200 return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_POINTER) 201 * WindowManagerService.TYPE_LAYER_MULTIPLIER 202 + WindowManagerService.TYPE_LAYER_OFFSET; 203 } 204 205 /** Callback to get pointer display id. */ 206 @Override getPointerDisplayId()207 public int getPointerDisplayId() { 208 synchronized (mService.mGlobalLock) { 209 // If desktop mode is not enabled, show on the default display. 210 if (!mService.mForceDesktopModeOnExternalDisplays) { 211 return DEFAULT_DISPLAY; 212 } 213 214 // Look for the topmost freeform display. 215 int firstExternalDisplayId = DEFAULT_DISPLAY; 216 for (int i = mService.mRoot.mChildren.size() - 1; i >= 0; --i) { 217 final DisplayContent displayContent = mService.mRoot.mChildren.get(i); 218 // Heuristic solution here. Currently when "Freeform windows" developer option is 219 // enabled we automatically put secondary displays in freeform mode and emulating 220 // "desktop mode". It also makes sense to show the pointer on the same display. 221 if (displayContent.getWindowingMode() == WINDOWING_MODE_FREEFORM) { 222 return displayContent.getDisplayId(); 223 } 224 225 if (firstExternalDisplayId == DEFAULT_DISPLAY 226 && displayContent.getDisplayId() != DEFAULT_DISPLAY) { 227 firstExternalDisplayId = displayContent.getDisplayId(); 228 } 229 } 230 231 // Look for the topmost non-default display 232 return firstExternalDisplayId; 233 } 234 } 235 236 @Override onPointerDownOutsideFocus(IBinder touchedToken)237 public void onPointerDownOutsideFocus(IBinder touchedToken) { 238 mService.mH.obtainMessage(ON_POINTER_DOWN_OUTSIDE_FOCUS, touchedToken).sendToTarget(); 239 } 240 241 /** Waits until the built-in input devices have been configured. */ waitForInputDevicesReady(long timeoutMillis)242 public boolean waitForInputDevicesReady(long timeoutMillis) { 243 synchronized (mInputDevicesReadyMonitor) { 244 if (!mInputDevicesReady) { 245 try { 246 mInputDevicesReadyMonitor.wait(timeoutMillis); 247 } catch (InterruptedException ex) { 248 } 249 } 250 return mInputDevicesReady; 251 } 252 } 253 freezeInputDispatchingLw()254 public void freezeInputDispatchingLw() { 255 if (!mInputDispatchFrozen) { 256 if (DEBUG_INPUT) { 257 Slog.v(TAG_WM, "Freezing input dispatching"); 258 } 259 260 mInputDispatchFrozen = true; 261 262 if (DEBUG_INPUT) { 263 mInputFreezeReason = Debug.getCallers(6); 264 } 265 updateInputDispatchModeLw(); 266 } 267 } 268 thawInputDispatchingLw()269 public void thawInputDispatchingLw() { 270 if (mInputDispatchFrozen) { 271 if (DEBUG_INPUT) { 272 Slog.v(TAG_WM, "Thawing input dispatching"); 273 } 274 275 mInputDispatchFrozen = false; 276 mInputFreezeReason = null; 277 updateInputDispatchModeLw(); 278 } 279 } 280 setEventDispatchingLw(boolean enabled)281 public void setEventDispatchingLw(boolean enabled) { 282 if (mInputDispatchEnabled != enabled) { 283 if (DEBUG_INPUT) { 284 Slog.v(TAG_WM, "Setting event dispatching to " + enabled); 285 } 286 287 mInputDispatchEnabled = enabled; 288 updateInputDispatchModeLw(); 289 } 290 } 291 updateInputDispatchModeLw()292 private void updateInputDispatchModeLw() { 293 mService.mInputManager.setInputDispatchMode(mInputDispatchEnabled, mInputDispatchFrozen); 294 } 295 dump(PrintWriter pw, String prefix)296 void dump(PrintWriter pw, String prefix) { 297 if (mInputFreezeReason != null) { 298 pw.println(prefix + "mInputFreezeReason=" + mInputFreezeReason); 299 } 300 } 301 } 302