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

Commit d28a31b1 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 8953730 from 820db998 to tm-qpr1-release

Change-Id: Ib90b1776f7ed3f894ada7652f8d8c0c394a5fc82
parents 5bc5973e 820db998
Loading
Loading
Loading
Loading
+58 −39
Original line number Diff line number Diff line
@@ -77,8 +77,7 @@ static std::string toLower(std::string s) {
}

static bool isFromTouchscreen(int32_t source) {
    return isFromSource(source, AINPUT_SOURCE_TOUCHSCREEN) &&
            !isFromSource(source, AINPUT_SOURCE_STYLUS);
    return isFromSource(source, AINPUT_SOURCE_TOUCHSCREEN);
}

static ::base::TimeTicks toChromeTimestamp(nsecs_t eventTime) {
@@ -142,23 +141,6 @@ static int32_t resolveActionForPointer(uint8_t pointerIndex, int32_t action) {
    return AMOTION_EVENT_ACTION_MOVE;
}

/**
 * Remove the data for the provided pointers from the args. The pointers are identified by their
 * pointerId, not by the index inside the array.
 * Return the new NotifyMotionArgs struct that has the remaining pointers.
 * The only fields that may be different in the returned args from the provided args are:
 *     - action
 *     - pointerCount
 *     - pointerProperties
 *     - pointerCoords
 * Action might change because it contains a pointer index. If another pointer is removed, the
 * active pointer index would be shifted.
 * Do not call this function for events with POINTER_UP or POINTER_DOWN events when removed pointer
 * id is the acting pointer id.
 *
 * @param args the args from which the pointers should be removed
 * @param pointerIds the pointer ids of the pointers that should be removed
 */
NotifyMotionArgs removePointerIds(const NotifyMotionArgs& args,
                                  const std::set<int32_t>& pointerIds) {
    const uint8_t actionIndex = MotionEvent::getActionIndex(args.action);
@@ -204,6 +186,26 @@ NotifyMotionArgs removePointerIds(const NotifyMotionArgs& args,
    return newArgs;
}

/**
 * Remove stylus pointers from the provided NotifyMotionArgs.
 *
 * Return NotifyMotionArgs where the stylus pointers have been removed.
 * If this results in removal of the active pointer, then return nullopt.
 */
static std::optional<NotifyMotionArgs> removeStylusPointerIds(const NotifyMotionArgs& args) {
    std::set<int32_t> stylusPointerIds;
    for (uint32_t i = 0; i < args.pointerCount; i++) {
        if (args.pointerProperties[i].toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS) {
            stylusPointerIds.insert(args.pointerProperties[i].id);
        }
    }
    NotifyMotionArgs withoutStylusPointers = removePointerIds(args, stylusPointerIds);
    if (withoutStylusPointers.pointerCount == 0 || withoutStylusPointers.action == ACTION_UNKNOWN) {
        return std::nullopt;
    }
    return withoutStylusPointers;
}

std::optional<AndroidPalmFilterDeviceInfo> createPalmFilterDeviceInfo(
        const InputDeviceInfo& deviceInfo) {
    if (!isFromTouchscreen(deviceInfo.getSources())) {
@@ -616,23 +618,7 @@ std::vector<::ui::InProgressTouchEvdev> getTouches(const NotifyMotionArgs& args,
    return touches;
}

std::vector<NotifyMotionArgs> PalmRejector::processMotion(const NotifyMotionArgs& args) {
    if (mPalmDetectionFilter == nullptr) {
        return {args};
    }
    const bool skipThisEvent = args.action == AMOTION_EVENT_ACTION_HOVER_ENTER ||
            args.action == AMOTION_EVENT_ACTION_HOVER_MOVE ||
            args.action == AMOTION_EVENT_ACTION_HOVER_EXIT ||
            args.action == AMOTION_EVENT_ACTION_BUTTON_PRESS ||
            args.action == AMOTION_EVENT_ACTION_BUTTON_RELEASE ||
            args.action == AMOTION_EVENT_ACTION_SCROLL;
    if (skipThisEvent) {
        // Lets not process hover events, button events, or scroll for now.
        return {args};
    }
    if (args.action == AMOTION_EVENT_ACTION_DOWN) {
        mSuppressedPointerIds.clear();
    }
std::set<int32_t> PalmRejector::detectPalmPointers(const NotifyMotionArgs& args) {
    std::bitset<::ui::kNumTouchEvdevSlots> slotsToHold;
    std::bitset<::ui::kNumTouchEvdevSlots> slotsToSuppress;

@@ -640,6 +626,7 @@ std::vector<NotifyMotionArgs> PalmRejector::processMotion(const NotifyMotionArgs
    // the slots that have been removed due to the incoming event.
    SlotState oldSlotState = mSlotState;
    mSlotState.update(args);

    std::vector<::ui::InProgressTouchEvdev> touches =
            getTouches(args, mDeviceInfo, oldSlotState, mSlotState);
    ::base::TimeTicks chromeTimestamp = toChromeTimestamp(args.eventTime);
@@ -651,14 +638,14 @@ std::vector<NotifyMotionArgs> PalmRejector::processMotion(const NotifyMotionArgs
        }
        ALOGD("Filter: touches = %s", touchesStream.str().c_str());
    }

    mPalmDetectionFilter->Filter(touches, chromeTimestamp, &slotsToHold, &slotsToSuppress);

    ALOGD_IF(DEBUG_MODEL, "Response: slotsToHold = %s, slotsToSuppress = %s",
             slotsToHold.to_string().c_str(), slotsToSuppress.to_string().c_str());

    // Now that we know which slots should be suppressed, let's convert those to pointer id's.
    std::set<int32_t> oldSuppressedIds;
    std::swap(oldSuppressedIds, mSuppressedPointerIds);
    std::set<int32_t> newSuppressedIds;
    for (size_t i = 0; i < args.pointerCount; i++) {
        const int32_t pointerId = args.pointerProperties[i].id;
        std::optional<size_t> slot = oldSlotState.getSlotForPointerId(pointerId);
@@ -667,9 +654,41 @@ std::vector<NotifyMotionArgs> PalmRejector::processMotion(const NotifyMotionArgs
            LOG_ALWAYS_FATAL_IF(!slot, "Could not find slot for pointer id %" PRId32, pointerId);
        }
        if (slotsToSuppress.test(*slot)) {
            mSuppressedPointerIds.insert(pointerId);
            newSuppressedIds.insert(pointerId);
        }
    }
    return newSuppressedIds;
}

std::vector<NotifyMotionArgs> PalmRejector::processMotion(const NotifyMotionArgs& args) {
    if (mPalmDetectionFilter == nullptr) {
        return {args};
    }
    const bool skipThisEvent = args.action == AMOTION_EVENT_ACTION_HOVER_ENTER ||
            args.action == AMOTION_EVENT_ACTION_HOVER_MOVE ||
            args.action == AMOTION_EVENT_ACTION_HOVER_EXIT ||
            args.action == AMOTION_EVENT_ACTION_BUTTON_PRESS ||
            args.action == AMOTION_EVENT_ACTION_BUTTON_RELEASE ||
            args.action == AMOTION_EVENT_ACTION_SCROLL;
    if (skipThisEvent) {
        // Lets not process hover events, button events, or scroll for now.
        return {args};
    }
    if (args.action == AMOTION_EVENT_ACTION_DOWN) {
        mSuppressedPointerIds.clear();
    }

    std::set<int32_t> oldSuppressedIds;
    std::swap(oldSuppressedIds, mSuppressedPointerIds);

    std::optional<NotifyMotionArgs> touchOnlyArgs = removeStylusPointerIds(args);
    if (touchOnlyArgs) {
        mSuppressedPointerIds = detectPalmPointers(*touchOnlyArgs);
    } else {
        // This is a stylus-only event.
        // We can skip this event and just keep the suppressed pointer ids the same as before.
        mSuppressedPointerIds = oldSuppressedIds;
    }

    std::vector<NotifyMotionArgs> argsWithoutUnwantedPointers =
            cancelSuppressedPointers(args, oldSuppressedIds, mSuppressedPointerIds);
+27 −0
Original line number Diff line number Diff line
@@ -43,6 +43,25 @@ std::optional<AndroidPalmFilterDeviceInfo> createPalmFilterDeviceInfo(

static constexpr int32_t ACTION_UNKNOWN = -1;

/**
 * Remove the data for the provided pointers from the args. The pointers are identified by their
 * pointerId, not by the index inside the array.
 * Return the new NotifyMotionArgs struct that has the remaining pointers.
 * The only fields that may be different in the returned args from the provided args are:
 *     - action
 *     - pointerCount
 *     - pointerProperties
 *     - pointerCoords
 * Action might change because it contains a pointer index. If another pointer is removed, the
 * active pointer index would be shifted.
 *
 * If the active pointer id is removed (for example, for events like
 * POINTER_UP or POINTER_DOWN), then the action is set to ACTION_UNKNOWN. It is up to the caller
 * to set the action appropriately after the call.
 *
 * @param args the args from which the pointers should be removed
 * @param pointerIds the pointer ids of the pointers that should be removed
 */
NotifyMotionArgs removePointerIds(const NotifyMotionArgs& args,
                                  const std::set<int32_t>& pointerIds);

@@ -154,6 +173,14 @@ private:
    PalmRejector(const PalmRejector&) = delete;
    PalmRejector& operator=(const PalmRejector&) = delete;

    /**
     * Update the slot state and send this event to the palm rejection model for palm detection.
     * Return the pointer ids that should be suppressed.
     *
     * This function is not const because it has side-effects. It will update the slot state using
     * the incoming args! Also, it will call Filter(..), which has side-effects.
     */
    std::set<int32_t> detectPalmPointers(const NotifyMotionArgs& args);
    std::unique_ptr<::ui::SharedPalmDetectionFilterState> mSharedPalmState;
    AndroidPalmFilterDeviceInfo mDeviceInfo;
    std::unique_ptr<::ui::PalmDetectionFilter> mPalmDetectionFilter;
+88 −0
Original line number Diff line number Diff line
@@ -66,6 +66,10 @@ MATCHER_P(WithAction, action, "MotionEvent with specified action") {
    return result;
}

MATCHER_P(WithFlags, flags, "MotionEvent with specified flags") {
    return arg.flags == flags;
}

static nsecs_t toNs(std::chrono::nanoseconds duration) {
    return duration.count();
}
@@ -616,6 +620,90 @@ TEST_F(UnwantedInteractionBlockerTest, HeuristicFilterWorks) {
    mTestListener.assertNotifyMotionWasCalled(WithAction(CANCEL));
}

/**
 * Send a stylus event that would have triggered the heuristic palm detector if it were a touch
 * event. However, since it's a stylus event, it should propagate without being canceled through
 * the blocker.
 * This is similar to `HeuristicFilterWorks` test, but for stylus tool.
 */
TEST_F(UnwantedInteractionBlockerTest, StylusIsNotBlocked) {
    InputDeviceInfo info = generateTestDeviceInfo();
    info.addSource(AINPUT_SOURCE_STYLUS);
    mBlocker->notifyInputDevicesChanged({info});
    NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
    args1.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
    mBlocker->notifyMotion(&args1);
    mTestListener.assertNotifyMotionWasCalled(WithAction(DOWN));

    // Move the stylus, setting large TOUCH_MAJOR/TOUCH_MINOR dimensions
    NotifyMotionArgs args2 =
            generateMotionArgs(0 /*downTime*/, RESAMPLE_PERIOD, MOVE, {{4, 5, 200}});
    args2.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
    mBlocker->notifyMotion(&args2);
    mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));

    // Lift up the stylus. If it were a touch event, this would force the model to decide on whether
    // it's a palm.
    NotifyMotionArgs args3 =
            generateMotionArgs(0 /*downTime*/, 2 * RESAMPLE_PERIOD, UP, {{4, 5, 200}});
    args3.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
    mBlocker->notifyMotion(&args3);
    mTestListener.assertNotifyMotionWasCalled(WithAction(UP));
}

/**
 * Send a mixed touch and stylus event.
 * The touch event goes first, and is a palm. The stylus event goes down after.
 * Stylus event should continue to work even after touch is detected as a palm.
 */
TEST_F(UnwantedInteractionBlockerTest, TouchIsBlockedWhenMixedWithStylus) {
    InputDeviceInfo info = generateTestDeviceInfo();
    info.addSource(AINPUT_SOURCE_STYLUS);
    mBlocker->notifyInputDevicesChanged({info});

    // Touch down
    NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
    mBlocker->notifyMotion(&args1);
    mTestListener.assertNotifyMotionWasCalled(WithAction(DOWN));

    // Stylus pointer down
    NotifyMotionArgs args2 = generateMotionArgs(0 /*downTime*/, RESAMPLE_PERIOD, POINTER_1_DOWN,
                                                {{1, 2, 3}, {10, 20, 30}});
    args2.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
    mBlocker->notifyMotion(&args2);
    mTestListener.assertNotifyMotionWasCalled(WithAction(POINTER_1_DOWN));

    // Large touch oval on the next finger move
    NotifyMotionArgs args3 = generateMotionArgs(0 /*downTime*/, 2 * RESAMPLE_PERIOD, MOVE,
                                                {{1, 2, 300}, {11, 21, 30}});
    args3.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
    mBlocker->notifyMotion(&args3);
    mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));

    // Lift up the finger pointer. It should be canceled due to the heuristic filter.
    NotifyMotionArgs args4 = generateMotionArgs(0 /*downTime*/, 3 * RESAMPLE_PERIOD, POINTER_0_UP,
                                                {{1, 2, 300}, {11, 21, 30}});
    args4.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
    mBlocker->notifyMotion(&args4);
    mTestListener.assertNotifyMotionWasCalled(
            AllOf(WithAction(POINTER_0_UP), WithFlags(FLAG_CANCELED)));

    NotifyMotionArgs args5 =
            generateMotionArgs(0 /*downTime*/, 4 * RESAMPLE_PERIOD, MOVE, {{12, 22, 30}});
    args5.pointerProperties[0].id = args4.pointerProperties[1].id;
    args5.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
    mBlocker->notifyMotion(&args5);
    mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));

    // Lift up the stylus pointer
    NotifyMotionArgs args6 =
            generateMotionArgs(0 /*downTime*/, 5 * RESAMPLE_PERIOD, UP, {{4, 5, 200}});
    args6.pointerProperties[0].id = args4.pointerProperties[1].id;
    args6.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
    mBlocker->notifyMotion(&args6);
    mTestListener.assertNotifyMotionWasCalled(WithAction(UP));
}

using UnwantedInteractionBlockerTestDeathTest = UnwantedInteractionBlockerTest;

/**
+2 −1
Original line number Diff line number Diff line
@@ -55,7 +55,8 @@ public:
    MOCK_METHOD(void, setRequiresClientComposition,
                (DisplayId displayId, bool requiresClientComposition), (override));
    MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override));
    MOCK_METHOD(void, setPresentFenceTime, (nsecs_t presentFenceTime), (override));
    MOCK_METHOD(void, setSfPresentTiming, (nsecs_t presentFenceTime, nsecs_t presentEndTime),
                (override));
    MOCK_METHOD(void, setHwcPresentDelayedTime,
                (DisplayId displayId,
                 std::chrono::steady_clock::time_point earliestFrameStartTime));
+11 −10
Original line number Diff line number Diff line
@@ -315,7 +315,8 @@ void PowerAdvisor::setExpectedPresentTime(nsecs_t expectedPresentTime) {
    mExpectedPresentTimes.append(expectedPresentTime);
}

void PowerAdvisor::setPresentFenceTime(nsecs_t presentFenceTime) {
void PowerAdvisor::setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) {
    mLastSfPresentEndTime = presentEndTime;
    mLastPresentFenceTime = presentFenceTime;
}

@@ -334,13 +335,7 @@ void PowerAdvisor::setCommitStart(nsecs_t commitStartTime) {
}

void PowerAdvisor::setCompositeEnd(nsecs_t compositeEnd) {
    mLastCompositeEndTime = compositeEnd;
    // calculate the postcomp time here as well
    std::vector<DisplayId>&& displays = getOrderedDisplayIds(&DisplayTimingData::hwcPresentEndTime);
    DisplayTimingData& timingData = mDisplayTimingData[displays.back()];
    mLastPostcompDuration = compositeEnd -
            (timingData.skippedValidate ? *timingData.hwcValidateEndTime
                                        : *timingData.hwcPresentEndTime);
    mLastPostcompDuration = compositeEnd - mLastSfPresentEndTime;
}

void PowerAdvisor::setDisplays(std::vector<DisplayId>& displayIds) {
@@ -399,7 +394,7 @@ std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) {
            getOrderedDisplayIds(&DisplayTimingData::hwcPresentStartTime);
    DisplayTimeline referenceTiming, estimatedTiming;

    // Iterate over the displays in the same order they are presented
    // Iterate over the displays that use hwc in the same order they are presented
    for (DisplayId displayId : displayIds) {
        if (mDisplayTimingData.count(displayId) == 0) {
            continue;
@@ -451,8 +446,11 @@ std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) {
    }
    ATRACE_INT64("Idle duration", idleDuration);

    nsecs_t estimatedFlingerEndTime = earlyHint ? estimatedEndTime : mLastSfPresentEndTime;

    // Don't count time spent idly waiting in the estimate as we could do more work in that time
    estimatedEndTime -= idleDuration;
    estimatedFlingerEndTime -= idleDuration;

    // We finish the frame when both present and the gpu are done, so wait for the later of the two
    // Also add the frame delay duration since the target did not move while we were delayed
@@ -460,7 +458,10 @@ std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) {
            std::max(estimatedEndTime, estimatedGpuEndTime.value_or(0)) - mCommitStartTimes[0];

    // We finish SurfaceFlinger when post-composition finishes, so add that in here
    nsecs_t flingerDuration = estimatedEndTime + mLastPostcompDuration - mCommitStartTimes[0];
    nsecs_t flingerDuration =
            estimatedFlingerEndTime + mLastPostcompDuration - mCommitStartTimes[0];

    // Combine the two timings into a single normalized one
    nsecs_t combinedDuration = combineTimingEstimates(totalDuration, flingerDuration);

    return std::make_optional(combinedDuration);
Loading