diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 98cef95885bdb..2e155ddfd3d99 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -248,6 +248,7 @@ public final class SurfaceControl implements Parcelable { private static native void nativeSetFixedTransformHint(long transactionObj, long nativeObject, int transformHint); + private static native void nativeRemoveCurrentInputFocus(long nativeObject, int displayId); private static native void nativeSetFocusedWindow(long transactionObj, IBinder toToken, String windowName, IBinder focusedToken, String focusedWindowName, int displayId); private static native void nativeSetFrameTimelineVsync(long transactionObj, @@ -3652,6 +3653,17 @@ public final class SurfaceControl implements Parcelable { return this; } + /** + * Removes the input focus from the current window which is having the input focus. Should + * only be called when the current focused app is not responding and the current focused + * window is not beloged to the current focused app. + * @hide + */ + public Transaction removeCurrentInputFocus(int displayId) { + nativeRemoveCurrentInputFocus(mNativeObject, displayId); + return this; + } + /** * Adds or removes the flag SKIP_SCREENSHOT of the surface. Setting the flag is equivalent * to creating the Surface with the {@link #SKIP_SCREENSHOT} flag. diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index fb5b5ffaac48c..64571adac2ef6 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -1833,6 +1833,15 @@ static jlong nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) { return reinterpret_cast(surfaceControl->getHandle().get()); } +static void nativeRemoveCurrentInputFocus(JNIEnv* env, jclass clazz, jlong transactionObj, + jint displayId) { + auto transaction = reinterpret_cast(transactionObj); + FocusRequest request; + request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC); + request.displayId = displayId; + transaction->setFocusedWindow(request); +} + static void nativeSetFocusedWindow(JNIEnv* env, jclass clazz, jlong transactionObj, jobject toTokenObj, jstring windowNameJstr, jobject focusedTokenObj, jstring focusedWindowNameJstr, @@ -2167,6 +2176,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetFixedTransformHint}, {"nativeSetFocusedWindow", "(JLandroid/os/IBinder;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;I)V", (void*)nativeSetFocusedWindow}, + {"nativeRemoveCurrentInputFocus", "(JI)V", + (void*)nativeRemoveCurrentInputFocus}, {"nativeSetFrameTimelineVsync", "(JJ)V", (void*)nativeSetFrameTimelineVsync }, {"nativeAddJankDataListener", "(JJ)V", diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 177965534b184..ed8986993ab0e 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -3793,6 +3793,12 @@ "group": "WM_DEBUG_REMOTE_ANIMATIONS", "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java" }, + "2001473656": { + "message": "App %s is focused, but the window is not ready. Start a transaction to remove focus from the window of non-focused apps.", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/InputMonitor.java" + }, "2018454757": { "message": "WS.removeImmediately: %s Already removed...", "level": "VERBOSE", diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 44818a8c9ee45..31ae864fc0909 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -414,6 +414,17 @@ final class InputMonitor { final IBinder focusToken = focus != null ? focus.mInputChannelToken : null; if (focusToken == null) { mInputFocus = null; + // When an app is focused, but its window is not showing yet, remove the input focus + // from the current window. + if (mDisplayContent.mFocusedApp != null) { + ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "App %s is focused," + + " but the window is not ready. Start a transaction to remove focus from" + + " the window of non-focused apps.", + mDisplayContent.mFocusedApp.getName()); + EventLog.writeEvent(LOGTAG_INPUT_FOCUS, "Requesting to set focus to null window", + "reason=UpdateInputWindows"); + mInputTransaction.removeCurrentInputFocus(mDisplayId); + } return; }