mirror of
https://github.com/google/pebble.git
synced 2025-03-19 18:41:21 +00:00
385 lines
17 KiB
C
385 lines
17 KiB
C
/*
|
|
* Copyright 2024 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "clar.h"
|
|
|
|
#include "applib/graphics/gtypes.h"
|
|
#include "kernel/events.h"
|
|
#include "services/common/touch/touch.h"
|
|
#include "services/common/touch/touch_event.h"
|
|
#include "services/common/touch/touch_client.h"
|
|
#include "util/size.h"
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
|
|
#include "fake_events.h"
|
|
|
|
// Stubs
|
|
#include "stubs_logging.h"
|
|
#include "stubs_mutex.h"
|
|
#include "stubs_passert.h"
|
|
|
|
bool gpoint_equal(const GPoint * const point_a, const GPoint * const point_b) {
|
|
return (point_a->x == point_b->x && point_a->y == point_b->y);
|
|
}
|
|
|
|
void kernel_free(void *p) {
|
|
|
|
}
|
|
|
|
extern TouchEvent *touch_event_queue_get_event(TouchIdx touch_idx, uint32_t queue_idx);
|
|
extern void touch_set_touch_state(TouchIdx touch_idx, TouchState touch_state, GPoint touch_down_pos,
|
|
uint64_t touch_down_time_ms, TouchPressure touch_down_pressure);
|
|
|
|
// setup and teardown
|
|
void test_touch__initialize(void) {
|
|
fake_event_init();
|
|
touch_reset();
|
|
}
|
|
|
|
void test_touch__cleanup(void) {
|
|
|
|
}
|
|
|
|
void prv_test_touch_event(TouchEvent *touch_event, TouchIdx idx, TouchEventType type, GPoint *start_pos,
|
|
uint64_t start_time_ms, TouchPressure start_pressure, GPoint *diff_pos,
|
|
uint64_t diff_time_ms, TouchPressure diff_pressure, bool test_diff) {
|
|
cl_assert(touch_event);
|
|
cl_assert_equal_i(touch_event->type, type);
|
|
cl_assert_equal_i(touch_event->index, idx);
|
|
cl_assert_equal_i(touch_event->start_time_ms, start_time_ms);
|
|
cl_assert(gpoint_equal(&touch_event->start_pos, start_pos));
|
|
cl_assert_equal_i(touch_event->start_pressure, start_pressure);
|
|
if (type != TouchEvent_Touchdown) {
|
|
cl_assert_equal_i(touch_event->diff_time_ms, diff_time_ms);
|
|
cl_assert(gpoint_equal(&touch_event->diff_pos, diff_pos));
|
|
cl_assert_equal_i(touch_event->diff_pressure, diff_pressure);
|
|
}
|
|
}
|
|
|
|
// tests
|
|
void test_touch__handle_update_touchdown(void) {
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(15, 100), 3, 3686400);
|
|
PebbleEvent event = fake_event_get_last();
|
|
cl_assert_equal_i(event.type, PEBBLE_TOUCH_EVENT);
|
|
cl_assert_equal_i(event.touch.type, PebbleTouchEvent_TouchesAvailable);
|
|
TouchEvent *touch_event = touch_event_queue_get_event(0, 0);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_Touchdown, &GPoint(15, 100), 3686400, 3,
|
|
&GPointZero, 0, 0, true);
|
|
|
|
touch_event = touch_event_queue_get_event(1, 0);
|
|
cl_assert_equal_p(touch_event, NULL);
|
|
|
|
// Test second touch
|
|
touch_handle_update(1, TouchState_FingerDown, &GPoint(1, 13), 5, 3686401);
|
|
event = fake_event_get_last();
|
|
cl_assert_equal_i(event.type, PEBBLE_TOUCH_EVENT);
|
|
cl_assert_equal_i(event.touch.type, PebbleTouchEvent_TouchesAvailable);
|
|
touch_event = touch_event_queue_get_event(1, 0);
|
|
prv_test_touch_event(touch_event, 1, TouchEvent_Touchdown, &GPoint(1, 13), 3686401, 5,
|
|
&GPointZero, 0, 0, true);
|
|
}
|
|
|
|
void test_touch__handle_update_liftoff(void) {
|
|
// Test first touch
|
|
touch_set_touch_state(0, TouchState_FingerDown, GPointZero, 3686380, 0);
|
|
touch_handle_update(0, TouchState_FingerUp, &GPoint(15, 100), 0, 3686400);
|
|
PebbleEvent event = fake_event_get_last();
|
|
cl_assert_equal_i(event.type, PEBBLE_TOUCH_EVENT);
|
|
cl_assert_equal_i(event.touch.type, PebbleTouchEvent_TouchesAvailable);
|
|
TouchEvent *touch_event = touch_event_queue_get_event(0, 0);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_Liftoff, &GPointZero, 3686380, 0,
|
|
&GPoint(15, 100), 20, 0, true);
|
|
|
|
// Ensure nothing recorded for second touch
|
|
touch_event = touch_event_queue_get_event(1, 0);
|
|
cl_assert_equal_p(touch_event, NULL);
|
|
|
|
// Test second touch
|
|
touch_set_touch_state(1, TouchState_FingerDown, GPointZero, 0, 0);
|
|
touch_handle_update(1, TouchState_FingerUp, &GPoint(1, 13), 0, 3686401);
|
|
event = fake_event_get_last();
|
|
cl_assert_equal_i(event.type, PEBBLE_TOUCH_EVENT);
|
|
cl_assert_equal_i(event.touch.type, PebbleTouchEvent_TouchesAvailable);
|
|
touch_event = touch_event_queue_get_event(1, 0);
|
|
prv_test_touch_event(touch_event, 1, TouchEvent_Liftoff, &GPointZero, 0, 0, &GPoint(1, 13),
|
|
3686401, 0, true);
|
|
}
|
|
|
|
void test_touch__handle_update_liftoff_null_pos(void) {
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(1, 13), 5, 3686400);
|
|
TouchEvent *touch_event = touch_event_queue_get_event(0, 0);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_Touchdown, &GPoint(1, 13), 3686400, 5,
|
|
&GPointZero, 0, 0, false);
|
|
touch_handle_update(0, TouchState_FingerUp, NULL, 0, 3686410);
|
|
touch_event = touch_event_queue_get_event(0, 1);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_Liftoff, &GPoint(1, 13), 3686400, 5, &GPointZero,
|
|
10, -5, true);
|
|
}
|
|
|
|
void test_touch__handle_update_position(void) {
|
|
touch_set_touch_state(0, TouchState_FingerDown, GPointZero, 3686380, 0);
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(10, 10), 5, 3686400);
|
|
PebbleEvent event = fake_event_get_last();
|
|
cl_assert_equal_i(event.type, PEBBLE_TOUCH_EVENT);
|
|
cl_assert_equal_i(event.touch.type, PebbleTouchEvent_TouchesAvailable);
|
|
TouchEvent *touch_event = touch_event_queue_get_event(0, 0);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_PositionUpdate, &GPointZero, 3686380, 0,
|
|
&GPoint(10, 10), 20, 5, true);
|
|
|
|
fake_event_reset_count();
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(13, 13), 6, 3686420);
|
|
cl_assert_equal_i(fake_event_get_count(), 0); // no event if previous one not handled
|
|
|
|
touch_event = touch_event_queue_get_event(0, 1);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_PositionUpdate, &GPointZero, 3686380, 0,
|
|
&GPoint(13, 13), 40, 6, true);
|
|
|
|
}
|
|
|
|
void test_touch__handle_update_position_stationary(void) {
|
|
touch_set_touch_state(0, TouchState_FingerDown, GPointZero, 3686380, 0);
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(10, 10), 5, 3686400);
|
|
TouchEvent *touch_event = touch_event_queue_get_event(0, 0);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_PositionUpdate, &GPointZero, 3686380, 0,
|
|
&GPoint(10, 10), 20, 5, true);
|
|
// No touch event generated when finger remains stationary
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(10, 10), 5, 3686420);
|
|
touch_event = touch_event_queue_get_event(0, 1);
|
|
cl_assert_equal_p(touch_event, NULL);
|
|
}
|
|
|
|
void test_touch__handle_update_merge_position(void) {
|
|
touch_set_touch_state(0, TouchState_FingerDown, GPointZero, 3686380, 0);
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(10, 10), 5, 3686400);
|
|
TouchEvent *touch_event = touch_event_queue_get_event(0, 0);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_PositionUpdate, &GPointZero, 3686380, 0,
|
|
&GPoint(10, 10), 20, 5, true);
|
|
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(13, 13), 6, 3686420);
|
|
touch_event = touch_event_queue_get_event(0, 1);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_PositionUpdate, &GPointZero, 3686380, 0,
|
|
&GPoint(13, 13), 40, 6, true);
|
|
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(18, 5), 1, 3686440);
|
|
// Test the same event (event at index 1): it should update to reflect the difference between this
|
|
// and the first event
|
|
touch_event = touch_event_queue_get_event(0, 1);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_PositionUpdate, &GPointZero, 3686380, 0,
|
|
&GPoint(18, 5), 60, 1, true);
|
|
}
|
|
|
|
void test_touch__handle_update_merge_liftoff(void) {
|
|
touch_set_touch_state(0, TouchState_FingerDown, GPointZero, 3686380, 0);
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(10, 10), 5, 3686400);
|
|
TouchEvent *touch_event = touch_event_queue_get_event(0, 0);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_PositionUpdate, &GPointZero, 3686380, 0,
|
|
&GPoint(10, 10), 20, 5, true);
|
|
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(13, 13), 6, 3686420);
|
|
touch_event = touch_event_queue_get_event(0, 1);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_PositionUpdate, &GPointZero, 3686380, 0,
|
|
&GPoint(13, 13), 40, 6, true);
|
|
|
|
touch_handle_update(0, TouchState_FingerUp, &GPoint(18, 5), 0, 3686440);
|
|
// Test the same event (event at index 1): it should update to reflect the difference between this
|
|
// and the first event and that it is a liftoff event
|
|
touch_event = touch_event_queue_get_event(0, 1);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_Liftoff, &GPointZero, 3686380, 0, &GPoint(18, 5),
|
|
60, 0, true);
|
|
}
|
|
|
|
void test_touch__handle_update_merge_liftoff_null_pos(void) {
|
|
touch_set_touch_state(0, TouchState_FingerDown, GPointZero, 3686380, 0);
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(10, 10), 5, 3686400);
|
|
TouchEvent *touch_event = touch_event_queue_get_event(0, 0);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_PositionUpdate, &GPointZero, 3686380, 0,
|
|
&GPoint(10, 10), 20, 5, true);
|
|
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(13, 13), 6, 3686420);
|
|
touch_event = touch_event_queue_get_event(0, 1);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_PositionUpdate, &GPointZero, 3686380, 0,
|
|
&GPoint(13, 13), 40, 6, true);
|
|
|
|
touch_handle_update(0, TouchState_FingerUp, NULL, 0, 3686440);
|
|
touch_event = touch_event_queue_get_event(0, 1);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_Liftoff, &GPointZero, 3686380, 0,
|
|
&GPoint(13, 13), 60, 0, true);
|
|
}
|
|
|
|
void test_touch__assert_null_pos_not_liftoff(void) {
|
|
// NULL position not valid for touchdown event
|
|
cl_assert_passert(touch_handle_update(0, TouchState_FingerDown, NULL, 5, 3686400));
|
|
|
|
touch_set_touch_state(0, TouchState_FingerDown, GPointZero, 0, 0);
|
|
// NULL position not valid for position update event
|
|
cl_assert_passert(touch_handle_update(0, TouchState_FingerDown, NULL, 5, 3686400));
|
|
}
|
|
|
|
void test_touch__handle_update_reset_queue_touchdown(void) {
|
|
touch_set_touch_state(0, TouchState_FingerDown, GPointZero, 3686380, 0);
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(13, 13), 6, 3686420);
|
|
touch_handle_update(0, TouchState_FingerUp, &GPoint(15, 100), 0, 3686400);
|
|
TouchEvent *touch_event = touch_event_queue_get_event(0, 1);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_Liftoff, &GPointZero, 3686380, 0,
|
|
&GPoint(15, 100), 20, 0, true);
|
|
|
|
// touchdown event should reset the touch event queue regardless of what is in it
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(31, 1), 6, 3686500);
|
|
touch_event = touch_event_queue_get_event(0, 0);
|
|
prv_test_touch_event(touch_event, 0, TouchEvent_Touchdown, &GPoint(31, 1), 3686500, 6,
|
|
&GPointZero, 0, 0, true);
|
|
touch_event = touch_event_queue_get_event(0, 1);
|
|
cl_assert_equal_p(touch_event, NULL);
|
|
}
|
|
|
|
void test_touch__handle_update_pressure(void) {
|
|
//TODO: We're not passing pressure updates to the UI yet (not so useful?)
|
|
}
|
|
|
|
typedef struct TouchEventContext {
|
|
TouchEvent touch_events[4];
|
|
uint32_t idx;
|
|
} TouchEventContext;
|
|
|
|
static void prv_touch_event_dispatch_cb(const TouchEvent *event, void *context) {
|
|
TouchEventContext *ctx = context;
|
|
cl_assert(ctx->idx < ARRAY_LENGTH(ctx->touch_events));
|
|
ctx->touch_events[ctx->idx++] = *event;
|
|
}
|
|
|
|
void test_touch__dispatch_touch_events_single_finger(void) {
|
|
TouchEventContext ctx = {
|
|
.idx = 0
|
|
};
|
|
touch_dispatch_touch_events(0, prv_touch_event_dispatch_cb, &ctx);
|
|
cl_assert_equal_i(ctx.idx, 0);
|
|
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(13, 13), 6, 3686420);
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(15, 15), 6, 3686440);
|
|
touch_dispatch_touch_events(0, prv_touch_event_dispatch_cb, &ctx);
|
|
cl_assert_equal_i(ctx.idx, 2);
|
|
prv_test_touch_event(&ctx.touch_events[0], 0, TouchEvent_Touchdown, &GPoint(13, 13), 3686420, 6,
|
|
NULL, 0, 0, false);
|
|
prv_test_touch_event(&ctx.touch_events[1], 0, TouchEvent_PositionUpdate, &GPoint(13, 13), 3686420,
|
|
6, &GPoint(2, 2), 20, 0, true);
|
|
TouchEvent *touch_event = touch_event_queue_get_event(0, 0);
|
|
cl_assert_equal_p(touch_event, NULL);
|
|
}
|
|
|
|
void test_touch__dispatch_touch_events_two_fingers(void) {
|
|
TouchEventContext ctx = {
|
|
.idx = 0
|
|
};
|
|
touch_dispatch_touch_events(0, prv_touch_event_dispatch_cb, &ctx);
|
|
cl_assert_equal_i(ctx.idx, 0);
|
|
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(13, 13), 6, 3686420);
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(15, 15), 6, 3686440);
|
|
touch_handle_update(1, TouchState_FingerDown, &GPoint(55, 55), 2, 3686480);
|
|
touch_handle_update(1, TouchState_FingerDown, &GPoint(33, 33), 7, 3686500);
|
|
touch_dispatch_touch_events(0, prv_touch_event_dispatch_cb, &ctx);
|
|
cl_assert_equal_i(ctx.idx, 2);
|
|
prv_test_touch_event(&ctx.touch_events[0], 0, TouchEvent_Touchdown, &GPoint(13, 13), 3686420, 6,
|
|
NULL, 0, 0, false);
|
|
prv_test_touch_event(&ctx.touch_events[1], 0, TouchEvent_PositionUpdate, &GPoint(13, 13), 3686420,
|
|
6, &GPoint(2, 2), 20, 0, true);
|
|
|
|
touch_dispatch_touch_events(1, prv_touch_event_dispatch_cb, &ctx);
|
|
cl_assert_equal_i(ctx.idx, 4);
|
|
prv_test_touch_event(&ctx.touch_events[2], 1, TouchEvent_Touchdown, &GPoint(55, 55), 3686480, 2,
|
|
NULL, 0, 0, false);
|
|
prv_test_touch_event(&ctx.touch_events[3], 1, TouchEvent_PositionUpdate, &GPoint(55, 55),
|
|
3686480, 2, &GPoint(-22, -22), 20, 5, true);
|
|
TouchEvent *touch_event = touch_event_queue_get_event(0, 0);
|
|
cl_assert_equal_p(touch_event, NULL);
|
|
}
|
|
|
|
void test_touch__cancel_touches(void) {
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(13, 13), 6, 3686420);
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(15, 15), 6, 3686440);
|
|
touch_handle_update(1, TouchState_FingerDown, &GPoint(55, 55), 2, 3686480);
|
|
touch_handle_update(1, TouchState_FingerDown, &GPoint(33, 33), 7, 3686500);
|
|
|
|
touch_handle_driver_event(TouchDriverEvent_ControllerError);
|
|
PebbleEvent event = fake_event_get_last();
|
|
// Touches cancelled event generated
|
|
cl_assert_equal_i(event.type, PEBBLE_TOUCH_EVENT);
|
|
cl_assert_equal_i(event.touch.type, PebbleTouchEvent_TouchesCancelled);
|
|
|
|
// no more touches
|
|
TouchEvent *touch_event = touch_event_queue_get_event(0, 0);
|
|
cl_assert_equal_p(touch_event, NULL);
|
|
touch_event = touch_event_queue_get_event(1, 0);
|
|
cl_assert_equal_p(touch_event, NULL);
|
|
}
|
|
|
|
// test that the first dispatch after a cancel event is pended does not return any touches, even
|
|
// if new touches have arrived - this is to ensure that the valid new touches are not cancelled
|
|
// by the cancellation event if it is pended before previous touches
|
|
void test_touch__cancel_touches_handle_first_dispatch(void) {
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(13, 13), 6, 3686420);
|
|
touch_handle_driver_event(TouchDriverEvent_ControllerError);
|
|
PebbleEvent event = fake_event_get_last();
|
|
cl_assert_equal_i(event.type, PEBBLE_TOUCH_EVENT);
|
|
cl_assert_equal_i(event.touch.type, PebbleTouchEvent_TouchesCancelled);
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(15, 15), 6, 3686440);
|
|
// make sure that another event is, in fact, pended
|
|
event = fake_event_get_last();
|
|
cl_assert_equal_i(event.type, PEBBLE_TOUCH_EVENT);
|
|
cl_assert_equal_i(event.touch.type, PebbleTouchEvent_TouchesAvailable);
|
|
|
|
TouchEventContext ctx = {
|
|
.idx = 0
|
|
};
|
|
// handle first TouchesAvailable event
|
|
touch_dispatch_touch_events(0, prv_touch_event_dispatch_cb, &ctx);
|
|
cl_assert_equal_i(ctx.idx, 0);
|
|
|
|
// handle second TouchesAvailable event
|
|
touch_dispatch_touch_events(0, prv_touch_event_dispatch_cb, &ctx);
|
|
cl_assert_equal_i(ctx.idx, 1);
|
|
prv_test_touch_event(&ctx.touch_events[0], 0, TouchEvent_Touchdown, &GPoint(15, 15), 3686440, 6,
|
|
NULL, 0, 0, false);
|
|
}
|
|
|
|
static PebbleEvent s_expected_palm_events[2];
|
|
static int s_palm_event_count = 0;
|
|
|
|
static void prv_handle_palm_events(PebbleEvent *e) {
|
|
s_expected_palm_events[s_palm_event_count++] = *e;
|
|
}
|
|
|
|
void test_touch__palm_detect_event(void) {
|
|
touch_handle_update(0, TouchState_FingerDown, &GPoint(13, 13), 6, 3686420);
|
|
touch_handle_update(1, TouchState_FingerDown, &GPoint(55, 55), 2, 3686480);
|
|
|
|
fake_event_set_callback(prv_handle_palm_events);
|
|
touch_handle_driver_event(TouchDriverEvent_PalmDetect);
|
|
|
|
// Cancelled event, followed by a palm detection event
|
|
cl_assert_equal_i(s_expected_palm_events[0].type, PEBBLE_TOUCH_EVENT);
|
|
cl_assert_equal_i(s_expected_palm_events[0].touch.type, PebbleTouchEvent_TouchesCancelled);
|
|
cl_assert_equal_i(s_expected_palm_events[1].type, PEBBLE_TOUCH_EVENT);
|
|
cl_assert_equal_i(s_expected_palm_events[1].touch.type, PebbleTouchEvent_PalmDetected);
|
|
|
|
TouchEvent *touch_event = touch_event_queue_get_event(0, 0);
|
|
cl_assert_equal_p(touch_event, NULL);
|
|
touch_event = touch_event_queue_get_event(1, 0);
|
|
cl_assert_equal_p(touch_event, NULL);
|
|
}
|