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

Commit 2ce50165 authored by Riddle Hsu's avatar Riddle Hsu Committed by Android (Google) Code Review
Browse files

Merge "Reduce unnecessary calculation from input device change" into main

parents 73169890 714eee2e
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -172,6 +172,16 @@ flag {
  bug: "357141415"
}

flag {
  name: "filter_irrelevant_input_device_change"
  namespace: "windowing_frontend"
  description: "Recompute display configuration only for necessary input device changes"
  bug: "368461853"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}

flag {
  name: "respect_non_top_visible_fixed_orientation"
  namespace: "windowing_frontend"
+54 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.server.wm;

import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;

import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
@@ -28,9 +29,12 @@ import android.annotation.Nullable;
import android.gui.StalledTransactionInfo;
import android.os.Debug;
import android.os.IBinder;
import android.os.Trace;
import android.util.Slog;
import android.util.SparseIntArray;
import android.view.Display;
import android.view.InputApplicationHandle;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -64,6 +68,12 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
    // which point the ActivityManager will enable dispatching.
    private boolean mInputDispatchEnabled;

    /**
     * The last input devices info which may affect display configuration. This is a quick lookup
     * to detect interested changes without entering WM lock.
     */
    private SparseIntArray mLastInputConfigurationSources;

    public InputManagerCallback(WindowManagerService service) {
        mService = service;
    }
@@ -117,8 +127,16 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
    /** Notifies that the input device configuration has changed. */
    @Override
    public void notifyConfigurationChanged() {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "notifyConfigurationChanged");
        final boolean changed = !com.android.window.flags.Flags.filterIrrelevantInputDeviceChange()
                || updateLastInputConfigurationSources();

        if (changed) {
            synchronized (mService.mGlobalLock) {
                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "inputDeviceConfigChanged");
                mService.mRoot.forAllDisplays(DisplayContent::sendNewConfiguration);
                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            }
        }

        synchronized (mInputDevicesReadyMonitor) {
@@ -127,6 +145,40 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
                mInputDevicesReadyMonitor.notifyAll();
            }
        }
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }

    /** Returns {@code true} if the change of input devices may affect display configuration. */
    private boolean updateLastInputConfigurationSources() {
        final InputDevice[] devices = mService.mInputManager.getInputDevices();
        final SparseIntArray newSources = new SparseIntArray(8);
        final SparseIntArray lastSources = mLastInputConfigurationSources;
        boolean changed = lastSources == null;
        for (InputDevice device : devices) {
            final String descriptor = device.getDescriptor();
            if (descriptor == null || device.isVirtual()) {
                continue;
            }
            final int key = descriptor.hashCode();
            // The interested attributes from DisplayContent#computeScreenConfiguration.
            int newSourceHash = device.getSources();
            newSourceHash = newSourceHash * 31 + device.getKeyboardType();
            newSourceHash = newSourceHash * 31 + device.getAssociatedDisplayId();
            newSourceHash = newSourceHash * 31 + (device.isExternal() ? 1 : 0);
            newSourceHash = newSourceHash * 31 + (device.isEnabled() ? 1 : 0);
            newSources.put(key, newSourceHash);
            if (lastSources != null && !changed) {
                final int lastSource = lastSources.get(key, 0 /* valueIfKeyNotFound */);
                if (lastSource != newSourceHash) {
                    changed = true;
                }
            }
        }
        if (lastSources != null && lastSources.size() != newSources.size()) {
            changed = true;
        }
        mLastInputConfigurationSources = newSources;
        return changed;
    }

    /** Notifies that the pointer location configuration has changed. */
+43 −0
Original line number Diff line number Diff line
@@ -94,6 +94,7 @@ import android.util.MergedConfiguration;
import android.view.ContentRecordingSession;
import android.view.IWindow;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.Surface;
@@ -1274,6 +1275,48 @@ public class WindowManagerServiceTests extends WindowTestsBase {
        verify(window, times(2)).requestAppKeyboardShortcuts(receiver, 0);
    }

    @Test
    public void testInputDeviceNotifyConfigurationChanged() {
        mSetFlagsRule.enableFlags(Flags.FLAG_FILTER_IRRELEVANT_INPUT_DEVICE_CHANGE);
        spyOn(mDisplayContent);
        doReturn(false).when(mDisplayContent).sendNewConfiguration();
        final InputDevice deviceA = mock(InputDevice.class);
        final InputDevice deviceB = mock(InputDevice.class);
        doReturn("deviceA").when(deviceA).getDescriptor();
        doReturn("deviceB").when(deviceB).getDescriptor();
        final InputDevice[] devices1 = { deviceA };
        final InputDevice[] devices2 = { deviceB, deviceA };
        final Runnable verifySendNewConfiguration = () -> {
            clearInvocations(mDisplayContent);
            mWm.mInputManagerCallback.notifyConfigurationChanged();
            verify(mDisplayContent).sendNewConfiguration();
        };
        doReturn(devices1).when(mWm.mInputManager).getInputDevices();
        verifySendNewConfiguration.run();

        doReturn(devices2).when(mWm.mInputManager).getInputDevices();
        verifySendNewConfiguration.run();

        doReturn(true).when(deviceB).isEnabled();
        verifySendNewConfiguration.run();

        doReturn(true).when(deviceA).isExternal();
        verifySendNewConfiguration.run();

        doReturn(1).when(deviceA).getSources();
        verifySendNewConfiguration.run();

        doReturn(1).when(deviceA).getAssociatedDisplayId();
        verifySendNewConfiguration.run();

        doReturn(1).when(deviceA).getKeyboardType();
        verifySendNewConfiguration.run();

        clearInvocations(mDisplayContent);
        mWm.mInputManagerCallback.notifyConfigurationChanged();
        verify(mDisplayContent, never()).sendNewConfiguration();
    }

    @Test
    public void testReportSystemGestureExclusionChanged_invalidWindow() {
        final Session session = mock(Session.class);