summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Siarhei Vishniakou <svv@google.com> 2020-12-14 09:49:56 -1000
committer Siarhei Vishniakou <svv@google.com> 2021-01-05 11:11:23 -1000
commitd7965fd114bc05cbf1503a8426e95649432f3721 (patch)
tree75297d3deb254fc301e4d43cdbd888074fdc02a3
parent250c00cd96359f6c00d5b09682faa7badf706f98 (diff)
Add detailed reasons for dropping events in ViewRootImpl
Currently, ViewRootImpl drops events for several reasons. However, just one reason is written to the log: "dropping event because the window does not have focus". But even if the window has focus, the event can be dropped. Improve the logging by refactoring the "if" check inside ViewRootImpl Test: atest ViewRootImplTest Bug: 173675649 Change-Id: I2ba8270ba09dea63e6497bc830af4c704ada52ef
-rw-r--r--core/java/android/view/ViewRootImpl.java45
-rw-r--r--core/tests/coretests/src/android/view/ViewRootImplTest.java91
2 files changed, 118 insertions, 18 deletions
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0fc2d7a75ee1..b1eedd8e4eec 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5535,26 +5535,39 @@ public final class ViewRootImpl implements ViewParent,
if (mView == null || !mAdded) {
Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
return true;
- } else if ((!mAttachInfo.mHasWindowFocus
+ }
+
+ // Find a reason for dropping or canceling the event.
+ final String reason;
+ if (!mAttachInfo.mHasWindowFocus
&& !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
- && !isAutofillUiShowing()) || mStopped
- || (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
- || (mPausedForTransition && !isBack(q.mEvent))) {
- // This is a focus event and the window doesn't currently have input focus or
- // has stopped. This could be an event that came back from the previous stage
+ && !isAutofillUiShowing()) {
+ // This is a non-pointer event and the window doesn't currently have input focus
+ // This could be an event that came back from the previous stage
// but the window has lost focus or stopped in the meantime.
- if (isTerminalInputEvent(q.mEvent)) {
- // Don't drop terminal input events, however mark them as canceled.
- q.mEvent.cancel();
- Slog.w(mTag, "Cancelling event due to no window focus: " + q.mEvent);
- return false;
- }
+ reason = "no window focus";
+ } else if (mStopped) {
+ reason = "window is stopped";
+ } else if (mIsAmbientMode
+ && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON)) {
+ reason = "non-button event in ambient mode";
+ } else if (mPausedForTransition && !isBack(q.mEvent)) {
+ reason = "paused for transition";
+ } else {
+ // Most common path: no reason to drop or cancel the event
+ return false;
+ }
- // Drop non-terminal input events.
- Slog.w(mTag, "Dropping event due to no window focus: " + q.mEvent);
- return true;
+ if (isTerminalInputEvent(q.mEvent)) {
+ // Don't drop terminal input events, however mark them as canceled.
+ q.mEvent.cancel();
+ Slog.w(mTag, "Cancelling event (" + reason + "):" + q.mEvent);
+ return false;
}
- return false;
+
+ // Drop non-terminal input events.
+ Slog.w(mTag, "Dropping event (" + reason + "):" + q.mEvent);
+ return true;
}
void dump(String prefix, PrintWriter writer) {
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 4cf6715ba0ca..8fa212a59984 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -26,6 +26,7 @@ import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -35,12 +36,14 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.Context;
+import android.os.Binder;
import android.platform.test.annotations.Presubmit;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Type;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Before;
import org.junit.Test;
@@ -58,13 +61,15 @@ import org.junit.runner.RunWith;
public class ViewRootImplTest {
private ViewRootImpl mViewRootImpl;
+ private Context mContext;
+ private volatile boolean mKeyReceived = false;
@Before
public void setUp() throws Exception {
- final Context context = getInstrumentation().getTargetContext();
+ mContext = getInstrumentation().getTargetContext();
getInstrumentation().runOnMainSync(() ->
- mViewRootImpl = new ViewRootImpl(context, context.getDisplayNoVerify()));
+ mViewRootImpl = new ViewRootImpl(mContext, mContext.getDisplayNoVerify()));
}
@Test
@@ -178,4 +183,86 @@ public class ViewRootImplTest {
// setSystemBarsBehavior.
assertEquals(behavior, controller.getSystemBarsBehavior());
}
+
+ /**
+ * When window doesn't have focus, keys should be dropped.
+ */
+ @Test
+ public void whenWindowDoesNotHaveFocus_keysAreDropped() {
+ checkKeyEvent(() -> {
+ mViewRootImpl.windowFocusChanged(false /*hasFocus*/, true /*inTouchMode*/);
+ }, false /*shouldReceiveKey*/);
+ }
+
+ /**
+ * When window has focus, keys should be received
+ */
+ @Test
+ public void whenWindowHasFocus_keysAreReceived() {
+ checkKeyEvent(() -> {
+ mViewRootImpl.windowFocusChanged(true /*hasFocus*/, true /*inTouchMode*/);
+ }, true /*shouldReceiveKey*/);
+ }
+
+ /**
+ * When window is in ambient mode, keys should be dropped
+ */
+ @Test
+ public void whenWindowIsInAmbientMode_keysAreDropped() {
+ checkKeyEvent(() -> {
+ mViewRootImpl.setIsAmbientMode(true /*ambient*/);
+ }, false /*shouldReceiveKey*/);
+ }
+
+ /**
+ * When window is paused for transition, keys should be dropped
+ */
+ @Test
+ public void whenWindowIsPausedForTransition_keysAreDropped() {
+ checkKeyEvent(() -> {
+ mViewRootImpl.setPausedForTransition(true /*paused*/);
+ }, false /*shouldReceiveKey*/);
+ }
+
+ class KeyView extends View {
+ KeyView(Context context) {
+ super(context);
+ }
+
+ @Override
+ public boolean dispatchKeyEventPreIme(KeyEvent event) {
+ mKeyReceived = true;
+ return true /*handled*/;
+ }
+ }
+
+ /**
+ * Create a new view, and add it to window manager.
+ * Run the precondition 'setup'.
+ * Next, inject an event into this view, and check whether it is received.
+ */
+ private void checkKeyEvent(Runnable setup, boolean shouldReceiveKey) {
+ final KeyView view = new KeyView(mContext);
+
+ WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
+ wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ WindowManager wm = mContext.getSystemService(WindowManager.class);
+ wm.addView(view, wmlp);
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ mViewRootImpl = view.getViewRootImpl();
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(setup);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ // Inject a key event, and wait for it to be processed
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A);
+ mViewRootImpl.dispatchInputEvent(event);
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ assertEquals(mKeyReceived, shouldReceiveKey);
+ }
}