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

Commit 3b134ccf authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

Add orientation configuration for touchscreen devices

There are many instances where devices have display panels installed in
a different orientation than the device's default orientation. In these
cases, there is an SF flag to change the device's default orientation,
using ro.surface_flinger.primary_display_orientation. However, when that
is used, the touchscreens don't work in the expected orientation.

This CL adds the ability to configure the orientation of a touchscreen
device using an Input Device Configuration (IDC) file.

Bug: 196357204
Test: atest inputflinger_tests
Test: manual: ensure touch works as expected with
ro.sf.primary_display_orientation and touch.orientation set to 90

Merged-In: I1267f2b3fdb6faaef2923789bcaf5a6141971431
Change-Id: I1267f2b3fdb6faaef2923789bcaf5a6141971431
parent a3970b8d
Loading
Loading
Loading
Loading
+29 −1
Original line number Diff line number Diff line
@@ -470,6 +470,23 @@ void TouchInputMapper::configureParameters() {
    getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientationAware"),
                                                         mParameters.orientationAware);

    mParameters.orientation = Parameters::Orientation::ORIENTATION_0;
    String8 orientationString;
    if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientation"),
                                                             orientationString)) {
        if (mParameters.deviceType != Parameters::DeviceType::TOUCH_SCREEN) {
            ALOGW("The configuration 'touch.orientation' is only supported for touchscreens.");
        } else if (orientationString == "ORIENTATION_90") {
            mParameters.orientation = Parameters::Orientation::ORIENTATION_90;
        } else if (orientationString == "ORIENTATION_180") {
            mParameters.orientation = Parameters::Orientation::ORIENTATION_180;
        } else if (orientationString == "ORIENTATION_270") {
            mParameters.orientation = Parameters::Orientation::ORIENTATION_270;
        } else if (orientationString != "ORIENTATION_0") {
            ALOGW("Invalid value for touch.orientation: '%s'", orientationString.string());
        }
    }

    mParameters.hasAssociatedDisplay = false;
    mParameters.associatedDisplayIsExternal = false;
    if (mParameters.orientationAware ||
@@ -508,6 +525,7 @@ void TouchInputMapper::dumpParameters(std::string& dump) {
                         toString(mParameters.associatedDisplayIsExternal),
                         mParameters.uniqueDisplayId.c_str());
    dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
    dump += INDENT4 "Orientation: " + NamedEnum::string(mParameters.orientation) + "\n";
}

void TouchInputMapper::configureRawPointerAxes() {
@@ -669,7 +687,13 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
            int32_t naturalPhysicalWidth, naturalPhysicalHeight;
            int32_t naturalPhysicalLeft, naturalPhysicalTop;
            int32_t naturalDeviceWidth, naturalDeviceHeight;
            switch (mViewport.orientation) {

            // Apply the inverse of the input device orientation so that the surface is configured
            // in the same orientation as the device. The input device orientation will be
            // re-applied to mSurfaceOrientation.
            const int32_t naturalSurfaceOrientation =
                    (mViewport.orientation - static_cast<int32_t>(mParameters.orientation) + 4) % 4;
            switch (naturalSurfaceOrientation) {
                case DISPLAY_ORIENTATION_90:
                    naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
                    naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
@@ -752,6 +776,10 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
                mSurfaceOrientation = mParameters.orientationAware ? mViewport.orientation
                                                                   : DISPLAY_ORIENTATION_0;
            }

            // Apply the input device orientation for the device.
            mSurfaceOrientation =
                    (mSurfaceOrientation + static_cast<int32_t>(mParameters.orientation)) % 4;
        } else {
            mPhysicalWidth = rawWidth;
            mPhysicalHeight = rawHeight;
+9 −0
Original line number Diff line number Diff line
@@ -204,6 +204,15 @@ protected:
        bool hasAssociatedDisplay;
        bool associatedDisplayIsExternal;
        bool orientationAware;

        enum class Orientation : int32_t {
            ORIENTATION_0 = DISPLAY_ORIENTATION_0,
            ORIENTATION_90 = DISPLAY_ORIENTATION_90,
            ORIENTATION_180 = DISPLAY_ORIENTATION_180,
            ORIENTATION_270 = DISPLAY_ORIENTATION_270,
        };
        Orientation orientation;

        bool hasButtonUnderPad;
        std::string uniqueDisplayId;

+176 −0
Original line number Diff line number Diff line
@@ -4659,6 +4659,8 @@ protected:
    void prepareLocationCalibration();
    int32_t toRawX(float displayX);
    int32_t toRawY(float displayY);
    int32_t toRotatedRawX(float displayX);
    int32_t toRotatedRawY(float displayY);
    float toCookedX(float rawX, float rawY);
    float toCookedY(float rawX, float rawY);
    float toDisplayX(int32_t rawX);
@@ -4741,6 +4743,14 @@ int32_t TouchInputMapperTest::toRawY(float displayY) {
    return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT + RAW_Y_MIN);
}

int32_t TouchInputMapperTest::toRotatedRawX(float displayX) {
    return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_HEIGHT + RAW_X_MIN);
}

int32_t TouchInputMapperTest::toRotatedRawY(float displayY) {
    return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_WIDTH + RAW_Y_MIN);
}

float TouchInputMapperTest::toCookedX(float rawX, float rawY) {
    AFFINE_TRANSFORM.applyTo(rawX, rawY);
    return rawX;
@@ -5487,6 +5497,172 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_RotatesMotion
    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
}

TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation0_RotatesMotions) {
    addConfigurationProperty("touch.deviceType", "touchScreen");
    prepareButtons();
    prepareAxes(POSITION);
    addConfigurationProperty("touch.orientationAware", "1");
    addConfigurationProperty("touch.orientation", "ORIENTATION_0");
    clearViewports();
    prepareDisplay(DISPLAY_ORIENTATION_0);
    auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
    NotifyMotionArgs args;

    // Orientation 0.
    processDown(mapper, toRawX(50), toRawY(75));
    processSync(mapper);

    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
    EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
    EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);

    processUp(mapper);
    processSync(mapper);
    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
}

TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation90_RotatesMotions) {
    addConfigurationProperty("touch.deviceType", "touchScreen");
    prepareButtons();
    prepareAxes(POSITION);
    addConfigurationProperty("touch.orientationAware", "1");
    addConfigurationProperty("touch.orientation", "ORIENTATION_90");
    clearViewports();
    prepareDisplay(DISPLAY_ORIENTATION_0);
    auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
    NotifyMotionArgs args;

    // Orientation 90.
    processDown(mapper, RAW_X_MAX - toRotatedRawX(75) + RAW_X_MIN, toRotatedRawY(50));
    processSync(mapper);

    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
    EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
    EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);

    processUp(mapper);
    processSync(mapper);
    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
}

TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation180_RotatesMotions) {
    addConfigurationProperty("touch.deviceType", "touchScreen");
    prepareButtons();
    prepareAxes(POSITION);
    addConfigurationProperty("touch.orientationAware", "1");
    addConfigurationProperty("touch.orientation", "ORIENTATION_180");
    clearViewports();
    prepareDisplay(DISPLAY_ORIENTATION_0);
    auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
    NotifyMotionArgs args;

    // Orientation 180.
    processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN);
    processSync(mapper);

    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
    EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
    EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);

    processUp(mapper);
    processSync(mapper);
    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
}

TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation270_RotatesMotions) {
    addConfigurationProperty("touch.deviceType", "touchScreen");
    prepareButtons();
    prepareAxes(POSITION);
    addConfigurationProperty("touch.orientationAware", "1");
    addConfigurationProperty("touch.orientation", "ORIENTATION_270");
    clearViewports();
    prepareDisplay(DISPLAY_ORIENTATION_0);
    auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
    NotifyMotionArgs args;

    // Orientation 270.
    processDown(mapper, toRotatedRawX(75), RAW_Y_MAX - toRotatedRawY(50) + RAW_Y_MIN);
    processSync(mapper);

    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
    EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
    EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);

    processUp(mapper);
    processSync(mapper);
    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
}

TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationSpecified_RotatesMotionWithDisplay) {
    addConfigurationProperty("touch.deviceType", "touchScreen");
    prepareButtons();
    prepareAxes(POSITION);
    // Since InputReader works in the un-rotated coordinate space, only devices that are not
    // orientation-aware are affected by display rotation.
    addConfigurationProperty("touch.orientationAware", "0");
    addConfigurationProperty("touch.orientation", "ORIENTATION_90");
    auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();

    NotifyMotionArgs args;

    // Orientation 90, Rotation 0.
    clearViewports();
    prepareDisplay(DISPLAY_ORIENTATION_0);
    processDown(mapper, RAW_X_MAX - toRotatedRawX(75) + RAW_X_MIN, toRotatedRawY(50));
    processSync(mapper);

    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
    EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
    EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);

    processUp(mapper);
    processSync(mapper);
    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());

    // Orientation 90, Rotation 90.
    clearViewports();
    prepareDisplay(DISPLAY_ORIENTATION_90);
    processDown(mapper, toRotatedRawX(50), toRotatedRawY(75));
    processSync(mapper);

    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
    EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
    EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);

    processUp(mapper);
    processSync(mapper);
    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());

    // Orientation 90, Rotation 180.
    clearViewports();
    prepareDisplay(DISPLAY_ORIENTATION_180);
    processDown(mapper, toRotatedRawX(75), RAW_Y_MAX - toRotatedRawY(50) + RAW_Y_MIN);
    processSync(mapper);

    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
    EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
    EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);

    processUp(mapper);
    processSync(mapper);
    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());

    // Orientation 90, Rotation 270.
    clearViewports();
    prepareDisplay(DISPLAY_ORIENTATION_270);
    processDown(mapper, RAW_X_MAX - toRotatedRawX(50) + RAW_X_MIN,
                RAW_Y_MAX - toRotatedRawY(75) + RAW_Y_MIN);
    processSync(mapper);

    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
    EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
    EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);

    processUp(mapper);
    processSync(mapper);
    EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
}

TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) {
    addConfigurationProperty("touch.deviceType", "touchScreen");
    prepareDisplay(DISPLAY_ORIENTATION_0);