Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d85ed8a authored by Antonio Kantek's avatar Antonio Kantek Committed by Android (Google) Code Review
Browse files

Merge "Roll forward of "Revert "TouchMode (5/n) Implementing onTouchModeChanged"""

parents bc588699 5d9adbcb
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -174,10 +174,10 @@ public abstract class InputEventReceiver {
     * Called when the display for the window associated with the input channel has entered or
     * exited touch mode.
     *
     * @param isInTouchMode {@code true} if the display showing the window associated with the
     * @param inTouchMode {@code true} if the display showing the window associated with the
     *                                  input channel entered touch mode.
     */
    public void onTouchModeChanged(boolean isInTouchMode) {
    public void onTouchModeChanged(boolean inTouchMode) {
    }

    /**
+39 −8
Original line number Diff line number Diff line
@@ -3376,14 +3376,12 @@ public final class ViewRootImpl implements ViewParent,

    private void handleWindowFocusChanged() {
        final boolean hasWindowFocus;
        final boolean inTouchMode;
        synchronized (this) {
            if (!mWindowFocusChanged) {
                return;
            }
            mWindowFocusChanged = false;
            hasWindowFocus = mUpcomingWindowFocus;
            inTouchMode = mUpcomingInTouchMode;
        }
        // TODO (b/131181940): Make sure this doesn't leak Activity with mActivityConfigCallback
        // config changes.
@@ -3396,9 +3394,7 @@ public final class ViewRootImpl implements ViewParent,

        if (mAdded) {
            profileRendering(hasWindowFocus);

            if (hasWindowFocus) {
                ensureTouchModeLocally(inTouchMode);
                if (mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) {
                    mFullRedrawNeeded = true;
                    try {
@@ -3470,6 +3466,14 @@ public final class ViewRootImpl implements ViewParent,
        }
    }

    private void handleWindowTouchModeChanged() {
        final boolean inTouchMode;
        synchronized (this) {
            inTouchMode = mUpcomingInTouchMode;
        }
        ensureTouchModeLocally(inTouchMode);
    }

    private void fireAccessibilityFocusEventIfHasFocusedNode() {
        if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
            return;
@@ -5127,6 +5131,7 @@ public final class ViewRootImpl implements ViewParent,
    private static final int MSG_SHOW_INSETS = 34;
    private static final int MSG_HIDE_INSETS = 35;
    private static final int MSG_REQUEST_SCROLL_CAPTURE = 36;
    private static final int MSG_WINDOW_TOUCH_MODE_CHANGED = 37;


    final class ViewRootHandler extends Handler {
@@ -5193,6 +5198,8 @@ public final class ViewRootImpl implements ViewParent,
                    return "MSG_SHOW_INSETS";
                case MSG_HIDE_INSETS:
                    return "MSG_HIDE_INSETS";
                case MSG_WINDOW_TOUCH_MODE_CHANGED:
                    return "MSG_WINDOW_TOUCH_MODE_CHANGED";
            }
            return super.getMessageName(message);
        }
@@ -5315,9 +5322,12 @@ public final class ViewRootImpl implements ViewParent,
                case MSG_WINDOW_FOCUS_CHANGED: {
                    handleWindowFocusChanged();
                } break;
                case MSG_DIE:
                case MSG_WINDOW_TOUCH_MODE_CHANGED: {
                    handleWindowTouchModeChanged();
                } break;
                case MSG_DIE: {
                    doDie();
                    break;
                } break;
                case MSG_DISPATCH_INPUT_EVENT: {
                    SomeArgs args = (SomeArgs) msg.obj;
                    InputEvent event = (InputEvent) args.arg1;
@@ -8687,6 +8697,11 @@ public final class ViewRootImpl implements ViewParent,
            windowFocusChanged(hasFocus, inTouchMode);
        }

        @Override
        public void onTouchModeChanged(boolean inTouchMode) {
            touchModeChanged(inTouchMode);
        }

        @Override
        public void onPointerCaptureEvent(boolean pointerCaptureEnabled) {
            dispatchPointerCaptureChanged(pointerCaptureEnabled);
@@ -8945,17 +8960,33 @@ public final class ViewRootImpl implements ViewParent,
        mHandler.sendMessage(msg);
    }

    public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
    /**
     * Notifies this {@link ViewRootImpl} object that window focus has changed.
     */
    public void windowFocusChanged(boolean hasFocus, boolean unusedInTouchMode) {
        // TODO(b/193718270): Remove inTouchMode parameter from this method and update related code
        //     accordingly.
        synchronized (this) {
            mWindowFocusChanged = true;
            mUpcomingWindowFocus = hasFocus;
            mUpcomingInTouchMode = inTouchMode;
        }
        Message msg = Message.obtain();
        msg.what = MSG_WINDOW_FOCUS_CHANGED;
        mHandler.sendMessage(msg);
    }

    /**
     * Notifies this {@link ViewRootImpl} object that touch mode state has changed.
     */
    public void touchModeChanged(boolean inTouchMode) {
        synchronized (this) {
            mUpcomingInTouchMode = inTouchMode;
        }
        Message msg = Message.obtain();
        msg.what = MSG_WINDOW_TOUCH_MODE_CHANGED;
        mHandler.sendMessage(msg);
    }

    public void dispatchWindowShown() {
        mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
    }
+3 −2
Original line number Diff line number Diff line
@@ -1841,8 +1841,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {

    @Override
    public void setLocalFocus(boolean hasFocus, boolean inTouchMode) {
        getViewRootImpl().windowFocusChanged(hasFocus, inTouchMode);

        ViewRootImpl viewRoot = getViewRootImpl();
        viewRoot.windowFocusChanged(hasFocus, inTouchMode);
        viewRoot.touchModeChanged(inTouchMode);
    }

    @Override
+70 −22
Original line number Diff line number Diff line
@@ -31,12 +31,14 @@ 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;

import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import android.app.Instrumentation;
import android.content.Context;
import android.os.Binder;
import android.platform.test.annotations.Presubmit;
@@ -47,7 +49,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;

import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

@@ -66,15 +70,32 @@ import java.util.concurrent.TimeUnit;
public class ViewRootImplTest {

    private ViewRootImpl mViewRootImpl;
    private Context mContext;
    private volatile boolean mKeyReceived = false;

    private static Context sContext;
    private static Instrumentation sInstrumentation = InstrumentationRegistry.getInstrumentation();

    // The touch mode state before the test was started, needed to return the system to the original
    // state after the test completes.
    private static boolean sOriginalTouchMode;

    @BeforeClass
    public static void setUpClass() {
        sContext = sInstrumentation.getTargetContext();
        View view = new View(sContext);
        sOriginalTouchMode = view.isInTouchMode();
    }

    @AfterClass
    public static void tearDownClass() {
        sInstrumentation.setInTouchMode(sOriginalTouchMode);
    }

    @Before
    public void setUp() throws Exception {
        mContext = getInstrumentation().getTargetContext();

        getInstrumentation().runOnMainSync(() ->
                mViewRootImpl = new ViewRootImpl(mContext, mContext.getDisplayNoVerify()));
        sInstrumentation.setInTouchMode(true);
        sInstrumentation.runOnMainSync(() ->
                mViewRootImpl = new ViewRootImpl(sContext, sContext.getDisplayNoVerify()));
    }

    @Test
@@ -224,9 +245,9 @@ public class ViewRootImplTest {
     */
    @Test
    public void requestScrollCapture_timeout() {
        final View view = new View(mContext);
        final View view = new View(sContext);
        view.setScrollCaptureCallback(new TestScrollCaptureCallback()); // Does nothing
        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
        sInstrumentation.runOnMainSync(() -> {
            WindowManager.LayoutParams wmlp =
                    new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
            // Set a fake token to bypass 'is your activity running' check
@@ -250,6 +271,29 @@ public class ViewRootImplTest {
        } catch (InterruptedException e) { /* ignore */ }
    }

    @Test
    public void whenTouchModeChanges_viewRootIsNotified() throws Exception {
        View view = new View(sContext);
        attachViewToWindow(view);
        ViewTreeObserver viewTreeObserver = view.getRootView().getViewTreeObserver();
        CountDownLatch latch = new CountDownLatch(1);
        ViewTreeObserver.OnTouchModeChangeListener touchModeListener = (boolean inTouchMode) -> {
            assertWithMessage("addOnTouchModeChangeListener parameter").that(
                    inTouchMode).isFalse();
            latch.countDown();
        };
        viewTreeObserver.addOnTouchModeChangeListener(touchModeListener);

        try {
            view.requestFocusFromTouch();

            assertThat(latch.await(1, TimeUnit.SECONDS)).isTrue();
            assertThat(view.isInTouchMode()).isFalse();
        } finally {
            viewTreeObserver.removeOnTouchModeChangeListener(touchModeListener);
        }
    }

    /**
     * When window doesn't have focus, keys should be dropped.
     */
@@ -308,27 +352,31 @@ public class ViewRootImplTest {
     * 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);
        final KeyView view = new KeyView(sContext);

        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();
        attachViewToWindow(view);

        mViewRootImpl = view.getViewRootImpl();
        InstrumentationRegistry.getInstrumentation().runOnMainSync(setup);
        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
        sInstrumentation.runOnMainSync(setup);
        sInstrumentation.waitForIdleSync();

        // Inject a key event, and wait for it to be processed
        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
        sInstrumentation.runOnMainSync(() -> {
            KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A);
            mViewRootImpl.dispatchInputEvent(event);
        });
        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
        sInstrumentation.waitForIdleSync();
        assertEquals(mKeyReceived, shouldReceiveKey);
    }

    private void attachViewToWindow(View view) {
        WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
        wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check

        sInstrumentation.runOnMainSync(() -> {
            WindowManager wm = sContext.getSystemService(WindowManager.class);
            wm.addView(view, wmlp);
        });
        sInstrumentation.waitForIdleSync();
    }
}