mirror of
https://github.com/google/pebble.git
synced 2025-03-21 03:11:21 +00:00
285 lines
9.6 KiB
C
285 lines
9.6 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 "kernel/events.h"
|
|
#include "services/common/comm_session/session.h"
|
|
#include "services/normal/notifications/alerts.h"
|
|
#include "services/normal/phone_call.h"
|
|
#include "services/normal/phone_call_util.h"
|
|
|
|
extern T_STATIC void prv_handle_phone_event(PebbleEvent *e, void *context);
|
|
extern T_STATIC void prv_handle_mobile_app_event(PebbleEvent *e, void *context);
|
|
extern T_STATIC void prv_handle_ancs_disconnected_event(PebbleEvent *e, void *context);
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Stubs
|
|
///////////////////////////////////////////////////////////
|
|
#include "stubs_analytics.h"
|
|
#include "stubs_event_service_client.h"
|
|
#include "stubs_logging.h"
|
|
#include "stubs_new_timer.h"
|
|
#include "stubs_pbl_malloc.h"
|
|
#include "stubs_phone_call_util.h"
|
|
#include "stubs_session.h"
|
|
#include "stubs_system_task.h"
|
|
|
|
bool alerts_should_notify_for_type(AlertType type) {
|
|
return true;
|
|
}
|
|
|
|
void ancs_perform_action(uint32_t notification_uid, uint8_t action_id) {}
|
|
|
|
void ancs_phone_call_temporarily_block_missed_calls(void) {}
|
|
|
|
void pp_answer_call(uint32_t cookie) {}
|
|
|
|
void pp_decline_call(uint32_t cookie) {}
|
|
|
|
void pp_get_phone_state(void) {}
|
|
|
|
void pp_get_phone_state_set_enabled(bool enabled) {}
|
|
|
|
// Phone UI stubs that allow us to track what phone_call.c is doing
|
|
static PhoneEventType s_last_phone_ui_event;
|
|
void phone_ui_handle_incoming_call(PebblePhoneCaller *caller, bool can_answer,
|
|
bool show_ongoing_call_ui) {
|
|
s_last_phone_ui_event = PhoneEventType_Incoming;
|
|
}
|
|
|
|
void phone_ui_handle_outgoing_call(PebblePhoneCaller *caller) {
|
|
s_last_phone_ui_event = PhoneEventType_Outgoing;
|
|
}
|
|
|
|
void phone_ui_handle_missed_call(void) {
|
|
s_last_phone_ui_event = PhoneEventType_Missed;
|
|
}
|
|
|
|
void phone_ui_handle_call_start(bool can_decline) {
|
|
s_last_phone_ui_event = PhoneEventType_Start;
|
|
}
|
|
|
|
void phone_ui_handle_call_end(bool call_accepted, bool disconnected) {
|
|
s_last_phone_ui_event = PhoneEventType_End;
|
|
}
|
|
|
|
void phone_ui_handle_call_hide(void) {
|
|
s_last_phone_ui_event = PhoneEventType_Hide;
|
|
}
|
|
|
|
void phone_ui_handle_caller_id(PebblePhoneCaller *caller) {
|
|
s_last_phone_ui_event = PhoneEventType_CallerID;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Helpers
|
|
///////////////////////////////////////////////////////////
|
|
|
|
#define ANCS_CALL_UID 1
|
|
#define ANCS_UNUSED_UID 2
|
|
|
|
// Whenever we check the last phone ui event, we reset s_last_phone_ui_event so we don't end up
|
|
// checking the same event twice and assume everything went well
|
|
#define ASSERT_LAST_EVENT(event) \
|
|
cl_assert_equal_i(s_last_phone_ui_event, event); \
|
|
s_last_phone_ui_event = PhoneEventType_Invalid;
|
|
|
|
static void prv_put_comm_session_event(bool app_connected) {
|
|
PebbleEvent comm_session_event = {
|
|
.type = PEBBLE_COMM_SESSION_EVENT,
|
|
.bluetooth.comm_session_event = (PebbleCommSessionEvent) {
|
|
.is_system = true,
|
|
.is_open = app_connected,
|
|
}
|
|
};
|
|
prv_handle_mobile_app_event(&comm_session_event, NULL);
|
|
}
|
|
|
|
static void prv_put_phone_event(PhoneEventType type, PhoneCallSource source,
|
|
uint32_t call_identifier) {
|
|
PebbleEvent phone_event = {
|
|
.type = PEBBLE_PHONE_EVENT,
|
|
.phone = {
|
|
.type = type,
|
|
.source = source,
|
|
.call_identifier = call_identifier,
|
|
.caller = NULL,
|
|
}
|
|
};
|
|
prv_handle_phone_event(&phone_event, NULL);
|
|
}
|
|
|
|
static void prv_put_incoming_call_event(PhoneCallSource source, bool app_connected) {
|
|
prv_put_comm_session_event(app_connected);
|
|
prv_put_phone_event(PhoneEventType_Incoming, source, ANCS_CALL_UID);
|
|
}
|
|
|
|
static void prv_call_end(void) {
|
|
// Note: the source doesn't matter here, phone_call.c ignores it
|
|
prv_put_phone_event(PhoneEventType_End, PhoneCallSource_PP, ANCS_CALL_UID);
|
|
}
|
|
|
|
static void prv_call_start(void) {
|
|
// Note: the source doesn't matter here, phone_call.c ignores it
|
|
prv_put_phone_event(PhoneEventType_Start, PhoneCallSource_PP, ANCS_CALL_UID);
|
|
}
|
|
|
|
static void prv_call_hide(uint32_t call_identifier) {
|
|
// Note: the source doesn't matter here, phone_call.c ignores it
|
|
prv_put_phone_event(PhoneEventType_Hide, PhoneCallSource_PP, call_identifier);
|
|
}
|
|
|
|
static void prv_ancs_disconnect(void) {
|
|
PebbleEvent ancs_event = {
|
|
.type = PEBBLE_ANCS_DISCONNECTED_EVENT,
|
|
};
|
|
prv_handle_ancs_disconnected_event(&ancs_event, NULL);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Tests
|
|
///////////////////////////////////////////////////////////
|
|
|
|
void test_phone_call__initialize(void) {
|
|
//fake_comm_session_init();
|
|
phone_call_service_init();
|
|
prv_call_end();
|
|
s_last_phone_ui_event = PhoneEventType_Invalid;
|
|
// s_transport = fake_transport_create(TransportDestinationSystem, NULL, NULL);
|
|
// s_session = fake_transport_set_connected(s_transport, true /* connected */);
|
|
// pp_get_phone_state_set_enabled(false);
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
void test_phone_call__cleanup(void) {
|
|
// fake_comm_session_cleanup();
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// Basic test for incoming calls over PP
|
|
void test_phone_call__pp_incoming(void) {
|
|
// We should only allow incoming calls when connected to the mobile app (this should never really
|
|
// happen for PP)
|
|
prv_put_incoming_call_event(PhoneCallSource_PP, false);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Invalid);
|
|
|
|
prv_put_incoming_call_event(PhoneCallSource_PP, true);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Incoming);
|
|
|
|
// Make sure we don't process incoming calls while we're in a call
|
|
prv_put_incoming_call_event(PhoneCallSource_PP, true);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Invalid);
|
|
|
|
// Losing ANCS connectivity in this case shouldn't matter
|
|
prv_ancs_disconnect();
|
|
ASSERT_LAST_EVENT(PhoneEventType_Invalid);
|
|
|
|
// Losing mobile connection should end the call
|
|
prv_put_comm_session_event(false /* app_connected */);
|
|
ASSERT_LAST_EVENT(PhoneEventType_End);
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// Basic test for incoming calls over ANCS on iOS 8 and below
|
|
void test_phone_call__ancs_legacy_incoming(void) {
|
|
// We should only allow the incoming call if we're connected to the app for polling reasons
|
|
prv_put_incoming_call_event(PhoneCallSource_ANCS_Legacy, false);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Invalid);
|
|
|
|
prv_put_incoming_call_event(PhoneCallSource_ANCS_Legacy, true);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Incoming);
|
|
|
|
// Make sure we don't process incoming calls while we're in a call
|
|
prv_put_incoming_call_event(PhoneCallSource_ANCS_Legacy, true);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Invalid);
|
|
|
|
// Losing ANCS connectivity in this case shouldn't matter
|
|
prv_ancs_disconnect();
|
|
ASSERT_LAST_EVENT(PhoneEventType_Invalid);
|
|
|
|
// Losing mobile app connection should end the call on the watch
|
|
prv_put_comm_session_event(false /* app_connected */);
|
|
ASSERT_LAST_EVENT(PhoneEventType_End);
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// Basic test for incoming calls on iOS 9 and up
|
|
void test_phone_call__ancs_incoming(void) {
|
|
// We should allow incoming calls with or without a mobile app on iOS 9
|
|
prv_put_incoming_call_event(PhoneCallSource_ANCS, false);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Incoming);
|
|
|
|
prv_call_end();
|
|
ASSERT_LAST_EVENT(PhoneEventType_End);
|
|
|
|
prv_put_incoming_call_event(PhoneCallSource_ANCS, true);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Incoming);
|
|
|
|
// Make sure we don't process incoming calls while we're in a call
|
|
prv_put_incoming_call_event(PhoneCallSource_ANCS, true);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Invalid);
|
|
|
|
// Losing connection to mobile app should have no effect if iOS 9
|
|
prv_put_comm_session_event(false /* app_connected */);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Invalid);
|
|
|
|
// Losing ANCS here should end the call
|
|
prv_ancs_disconnect();
|
|
ASSERT_LAST_EVENT(PhoneEventType_End);
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// Basic test for call start events
|
|
void test_phone_call__call_start(void) {
|
|
// A call start event with ANCS should act as a call end in order to hide the phone ui
|
|
prv_put_incoming_call_event(PhoneCallSource_ANCS_Legacy, true);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Incoming);
|
|
|
|
prv_call_start();
|
|
ASSERT_LAST_EVENT(PhoneEventType_End);
|
|
|
|
// A call start event with PP should keep the phone ui up
|
|
prv_put_incoming_call_event(PhoneCallSource_PP, true);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Incoming);
|
|
|
|
prv_call_start();
|
|
ASSERT_LAST_EVENT(PhoneEventType_Start);
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
// Make sure we handle ANCS notification removals properly
|
|
void test_phone_call__ancs_hide(void) {
|
|
// Make sure we hide the call when ANCS tells us the notification was removed (but only if the
|
|
// call id matches the current call)
|
|
prv_put_incoming_call_event(PhoneCallSource_ANCS, false);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Incoming);
|
|
|
|
prv_call_hide(ANCS_UNUSED_UID);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Invalid);
|
|
|
|
prv_call_hide(ANCS_CALL_UID);
|
|
ASSERT_LAST_EVENT(PhoneEventType_Hide);
|
|
}
|