mirror of
https://github.com/google/pebble.git
synced 2025-03-24 20:49:05 +00:00
630 lines
22 KiB
C
630 lines
22 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/ui/menu_layer.h"
|
|
#include "flash_region/flash_region.h"
|
|
#include "process_management/app_install_manager.h"
|
|
#include "process_management/app_menu_data_source.h"
|
|
#include "resource/resource.h"
|
|
#include "resource/resource_storage.h"
|
|
#include "resource/resource_storage_file.h"
|
|
#include "services/common/system_task.h"
|
|
#include "services/normal/app_cache.h"
|
|
#include "services/normal/blob_db/app_db.h"
|
|
#include "services/normal/filesystem/pfs.h"
|
|
#include "util/build_id.h"
|
|
#include "util/size.h"
|
|
#include "fixtures/load_test_resources.h"
|
|
|
|
// access it directly just to test things out
|
|
#include "shell/system_app_registry_list.auto.h"
|
|
|
|
#include <stdio.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
// Stub Includes
|
|
////////////////////////////////////
|
|
#include "stubs_activity.h"
|
|
#include "stubs_analytics.h"
|
|
#include "stubs_app_custom_icon.h"
|
|
#include "stubs_app_fetch_endpoint.h"
|
|
#include "stubs_app_manager.h"
|
|
#include "stubs_app_state.h"
|
|
#include "stubs_bootbits.h"
|
|
#include "stubs_build_id.h"
|
|
#include "stubs_comm_session.h"
|
|
#include "stubs_event_loop.h"
|
|
#include "stubs_event_service_client.h"
|
|
#include "stubs_events.h"
|
|
#include "stubs_fonts.h"
|
|
#include "stubs_gbitmap.h"
|
|
#include "stubs_graphics.h"
|
|
#include "stubs_graphics.h"
|
|
#include "stubs_graphics_context.h"
|
|
#include "stubs_heap.h"
|
|
#include "stubs_hexdump.h"
|
|
#include "stubs_i18n.h"
|
|
#include "stubs_kino_reel.h"
|
|
#include "stubs_logging.h"
|
|
#include "stubs_memory_layout.h"
|
|
#include "stubs_menu_layer.h"
|
|
#include "stubs_mutex.h"
|
|
#include "stubs_passert.h"
|
|
#include "stubs_pbl_malloc.h"
|
|
#include "stubs_pebble_tasks.h"
|
|
#include "stubs_persist.h"
|
|
#include "stubs_pin_db.h"
|
|
#include "stubs_process_loader.h"
|
|
#include "stubs_process_manager.h"
|
|
#include "stubs_process_manager.h"
|
|
#include "stubs_prompt.h"
|
|
#include "stubs_put_bytes.h"
|
|
#include "stubs_queue.h"
|
|
#include "stubs_quick_launch.h"
|
|
#include "stubs_rand_ptr.h"
|
|
#include "stubs_serial.h"
|
|
#include "stubs_shell_prefs.h"
|
|
#include "stubs_sleep.h"
|
|
#include "stubs_system_task.h"
|
|
#include "stubs_task_watchdog.h"
|
|
#include "stubs_watchface.h"
|
|
#include "stubs_worker_manager.h"
|
|
|
|
// Fake Includes
|
|
////////////////////////////////////
|
|
#include "fake_spi_flash.h"
|
|
|
|
const uint32_t g_num_file_resource_stores = 0;
|
|
const FileResourceData g_file_resource_stores[] = {};
|
|
|
|
#define APP_REGISTRY_FIXTURE_PATH "app_registry"
|
|
|
|
#define BG_COUNTER_APP_NAME "Background Counter"
|
|
#define MENU_LAYER_APP_NAME "MenuLayerName"
|
|
#define BIG_TIME_APP_NAME "Big Time"
|
|
|
|
#define BG_COUNTER_APP_ID 1
|
|
#define MENU_LAYER_APP_ID 2
|
|
#define BIG_TIME_APP_ID 3
|
|
|
|
// background counter
|
|
static const AppDBEntry bg_counter_app = {
|
|
.name = BG_COUNTER_APP_NAME,
|
|
.uuid = {0x1e, 0xb1, 0xd3, 0x9b, 0x56, 0x98, 0x48, 0x44,
|
|
0xb3, 0x94, 0x1f, 0x87, 0xb6, 0xbe, 0xae, 0x67},
|
|
.info_flags = PROCESS_INFO_HAS_WORKER | PROCESS_INFO_STANDARD_APP,
|
|
.icon_resource_id = 0,
|
|
.app_version = {
|
|
.major = 1,
|
|
.minor = 0,
|
|
},
|
|
.sdk_version = {
|
|
.major = 5,
|
|
.minor = 13,
|
|
},
|
|
.app_face_bg_color = {0},
|
|
.template_id = 0,
|
|
};
|
|
|
|
// menu layer
|
|
static const AppDBEntry menu_layer_app = {
|
|
.name = MENU_LAYER_APP_NAME,
|
|
.uuid = {0xb8, 0x26, 0x2e, 0x08, 0x57, 0xe9, 0x4e, 0x58,
|
|
0x88, 0x02, 0x45, 0xfd, 0xfe, 0xe0, 0xac, 0x77},
|
|
.info_flags = PROCESS_INFO_STANDARD_APP,
|
|
.icon_resource_id = 0,
|
|
.app_version = {
|
|
.major = 2,
|
|
.minor = 0,
|
|
},
|
|
.sdk_version = {
|
|
.major = 5,
|
|
.minor = 13,
|
|
},
|
|
.app_face_bg_color = {0},
|
|
.template_id = 0,
|
|
};
|
|
|
|
// big time
|
|
static const AppDBEntry big_time_app = {
|
|
.name = BIG_TIME_APP_NAME,
|
|
.uuid = {0xaf, 0xcc, 0x68, 0x76, 0x8f, 0x84, 0x44, 0xe0,
|
|
0xbb, 0x8b, 0x02, 0x3f, 0xfb, 0x2d, 0x7c, 0x2c},
|
|
.info_flags = PROCESS_INFO_WATCH_FACE,
|
|
.icon_resource_id = 0,
|
|
.app_version = {
|
|
.major = 6,
|
|
.minor = 0,
|
|
},
|
|
.sdk_version = {
|
|
.major = 5,
|
|
.minor = 17,
|
|
},
|
|
.app_face_bg_color = {0},
|
|
.template_id = 0,
|
|
};
|
|
|
|
AppInstallId bg_counter_app_id;
|
|
AppInstallId menu_layer_app_id;
|
|
AppInstallId big_time_app_id;
|
|
|
|
// Fakes
|
|
////////////////////////////////////
|
|
uint32_t time_get_uptime_seconds(void) {
|
|
return rtc_get_time();
|
|
}
|
|
|
|
// Tests
|
|
////////////////////////////////////
|
|
static MenuLayer menu_layer;
|
|
static AppMenuDataSource data_source;
|
|
|
|
static bool app_filter_callback(struct AppMenuDataSource *source, AppInstallEntry *entry) {
|
|
if (app_install_entry_is_hidden(entry)) {
|
|
return false;
|
|
}
|
|
if (app_install_entry_is_watchface(entry)) {
|
|
return false; // Only apps
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool watchface_filter_callback(struct AppMenuDataSource *source, AppInstallEntry *entry) {
|
|
if (app_install_entry_is_hidden(entry)) {
|
|
return false;
|
|
}
|
|
if (!app_install_entry_is_watchface(entry)) {
|
|
return false; // Only watchfaces
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool everything_filter_callback(struct AppMenuDataSource *source, AppInstallEntry *entry) {
|
|
return true;
|
|
}
|
|
|
|
void test_app_menu_data_source__initialize(void) {
|
|
fake_spi_flash_init(0, 0x1000000);
|
|
|
|
pfs_init(false);
|
|
pfs_format(false);
|
|
|
|
app_install_manager_init();
|
|
app_db_init();
|
|
app_cache_init();
|
|
|
|
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME, false);
|
|
resource_init();
|
|
|
|
// simulate installing bg_counter_app on flash
|
|
app_db_insert((uint8_t *)&bg_counter_app.uuid, sizeof(Uuid),
|
|
(uint8_t *)&bg_counter_app, sizeof(AppDBEntry));
|
|
bg_counter_app_id = app_db_get_install_id_for_uuid(&bg_counter_app.uuid);
|
|
app_cache_add_entry(bg_counter_app_id, 10701);
|
|
cl_assert_equal_i(BG_COUNTER_APP_ID, bg_counter_app_id);
|
|
|
|
// simulate installing menu_layer_app on flash
|
|
app_db_insert((uint8_t *)&menu_layer_app.uuid, sizeof(Uuid),
|
|
(uint8_t *)&menu_layer_app, sizeof(AppDBEntry));
|
|
menu_layer_app_id = app_db_get_install_id_for_uuid(&menu_layer_app.uuid);
|
|
app_cache_add_entry(menu_layer_app_id, 10701);
|
|
cl_assert_equal_i(MENU_LAYER_APP_ID, menu_layer_app_id);
|
|
|
|
// simulate installing big_time_app on flash
|
|
app_db_insert((uint8_t *)&big_time_app.uuid, sizeof(Uuid),
|
|
(uint8_t *)&big_time_app, sizeof(AppDBEntry));
|
|
big_time_app_id = app_db_get_install_id_for_uuid(&big_time_app.uuid);
|
|
app_cache_add_entry(big_time_app_id, 10701);
|
|
cl_assert_equal_i(BIG_TIME_APP_ID, big_time_app_id);
|
|
|
|
menu_layer_init(&menu_layer, &GRect(0,0,144,76));
|
|
|
|
rtc_set_time(100);
|
|
}
|
|
|
|
extern ListNode *s_head_callback_node_list;
|
|
|
|
void test_app_menu_data_source__cleanup(void) {
|
|
s_head_callback_node_list = NULL;
|
|
app_install_manager_flush_recent_communication_timestamps();
|
|
}
|
|
|
|
/*************************************
|
|
|
|
*************************************/
|
|
|
|
static void prv_menu_layer_reload_data(void *data) {
|
|
cl_assert_equal_p(data, &menu_layer);
|
|
menu_layer_reload_data(&menu_layer);
|
|
}
|
|
|
|
void test_app_menu_data_source__pass_init(void) {
|
|
app_menu_data_source_init(&data_source, &(AppMenuDataSourceCallbacks) {
|
|
.changed = prv_menu_layer_reload_data,
|
|
.filter = everything_filter_callback,
|
|
}, &menu_layer);
|
|
uint16_t num_apps = app_menu_data_source_get_count(&data_source);
|
|
|
|
for (uint16_t i = 0; i < num_apps; i++) {
|
|
AppMenuNode *node = app_menu_data_source_get_node_at_index(&data_source, i);
|
|
cl_assert(node);
|
|
}
|
|
}
|
|
|
|
void test_app_menu_data_source__check_default_order_apps(void) {
|
|
// settings has to be at the beginning. The app_menu_data_source module enforces it
|
|
static const AppInstallId app_default_order[] = {APP_ID_SETTINGS, APP_ID_MUSIC,
|
|
APP_ID_NOTIFICATIONS, APP_ID_ALARMS,
|
|
APP_ID_WATCHFACES, APP_ID_WORKOUT,
|
|
BG_COUNTER_APP_ID, MENU_LAYER_APP_ID};
|
|
app_menu_data_source_init(&data_source, &(AppMenuDataSourceCallbacks) {
|
|
.changed = prv_menu_layer_reload_data,
|
|
.filter = app_filter_callback,
|
|
}, &menu_layer);
|
|
uint16_t num_apps = app_menu_data_source_get_count(&data_source);
|
|
cl_assert_equal_i(num_apps, ARRAY_LENGTH(app_default_order));
|
|
|
|
for (uint16_t i = 0; i < num_apps; i++) {
|
|
AppMenuNode *node = app_menu_data_source_get_node_at_index(&data_source, i);
|
|
cl_assert_equal_i(node->install_id, app_default_order[i]);
|
|
}
|
|
|
|
app_menu_data_source_deinit(&data_source);
|
|
}
|
|
|
|
static uint16_t prv_reverse_index(AppMenuDataSource *data_source, uint16_t original_index,
|
|
void *context) {
|
|
return app_menu_data_source_get_count(data_source) - 1 - original_index;
|
|
}
|
|
|
|
void test_app_menu_data_source__transform_index(void) {
|
|
// settings has to be at the beginning. The app_menu_data_source module enforces it
|
|
static const AppInstallId app_default_order[] = {APP_ID_SETTINGS, APP_ID_MUSIC,
|
|
APP_ID_NOTIFICATIONS, APP_ID_ALARMS,
|
|
APP_ID_WATCHFACES, APP_ID_WORKOUT,
|
|
BG_COUNTER_APP_ID, MENU_LAYER_APP_ID};
|
|
app_menu_data_source_init(&data_source, &(AppMenuDataSourceCallbacks) {
|
|
.changed = prv_menu_layer_reload_data,
|
|
.filter = app_filter_callback,
|
|
.transform_index = prv_reverse_index,
|
|
}, &menu_layer);
|
|
uint16_t num_apps = app_menu_data_source_get_count(&data_source);
|
|
cl_assert_equal_i(num_apps, ARRAY_LENGTH(app_default_order));
|
|
|
|
for (uint16_t i = 0; i < num_apps; i++) {
|
|
AppMenuNode *node = app_menu_data_source_get_node_at_index(&data_source, i);
|
|
cl_assert_equal_i(node->install_id, app_default_order[num_apps - 1 - i]);
|
|
}
|
|
|
|
app_menu_data_source_deinit(&data_source);
|
|
}
|
|
|
|
void test_app_menu_data_source__check_default_order_watchfaces(void) {
|
|
static const AppInstallId watchface_default_order[] = {APP_ID_TICTOC,
|
|
BIG_TIME_APP_ID};
|
|
app_menu_data_source_init(&data_source, &(AppMenuDataSourceCallbacks) {
|
|
.changed = prv_menu_layer_reload_data,
|
|
.filter = watchface_filter_callback,
|
|
}, &menu_layer);
|
|
uint16_t num_apps = app_menu_data_source_get_count(&data_source);
|
|
cl_assert_equal_i(num_apps, ARRAY_LENGTH(watchface_default_order));
|
|
|
|
for (uint16_t i = 0; i < num_apps; i++) {
|
|
AppMenuNode *node = app_menu_data_source_get_node_at_index(&data_source, i);
|
|
cl_assert_equal_i(node->install_id, watchface_default_order[i]);
|
|
}
|
|
app_menu_data_source_deinit(&data_source);
|
|
}
|
|
|
|
void prv_write_order_to_file(const AppInstallId order[], uint8_t num_entries) {
|
|
uint8_t entries_to_write = num_entries + 1;
|
|
uint16_t file_len = sizeof(uint8_t) + (entries_to_write) * sizeof(AppInstallId);
|
|
|
|
pfs_remove("lnc_ord");
|
|
int fd = pfs_open("lnc_ord", OP_FLAG_WRITE, FILE_TYPE_STATIC, file_len);
|
|
pfs_write(fd, &entries_to_write, sizeof(entries_to_write));
|
|
pfs_write(fd, order, sizeof(AppInstallId) * num_entries);
|
|
AppInstallId zero_id = 0;
|
|
pfs_write(fd, &zero_id, sizeof(zero_id));
|
|
pfs_close(fd);
|
|
}
|
|
|
|
void prv_test_new_order_with_filter_callback(const AppInstallId order[], uint8_t num_entries,
|
|
AppMenuFilterCallback filter_callback) {
|
|
prv_write_order_to_file(order, num_entries);
|
|
|
|
app_menu_data_source_init(&data_source, &(AppMenuDataSourceCallbacks) {
|
|
.changed = prv_menu_layer_reload_data,
|
|
.filter = filter_callback,
|
|
}, &menu_layer);
|
|
uint16_t num_apps = app_menu_data_source_get_count(&data_source);
|
|
// cl_assert_equal_i(num_apps, num_entries);
|
|
|
|
for (uint16_t i = 0; i < num_apps; i++) {
|
|
AppMenuNode *node = app_menu_data_source_get_node_at_index(&data_source, i);
|
|
cl_assert_equal_i(node->install_id, order[i]);
|
|
}
|
|
|
|
app_menu_data_source_deinit(&data_source);
|
|
}
|
|
|
|
void prv_shuffle(AppInstallId *array, uint8_t n) {
|
|
for (uint8_t i = 0; i < n - 1; i++) {
|
|
uint8_t j = i + rand() / (RAND_MAX / (n - i) + 1);
|
|
int t = array[j];
|
|
array[j] = array[i];
|
|
array[i] = t;
|
|
}
|
|
}
|
|
|
|
void test_app_menu_data_source__change_order_apps(void) {
|
|
// settings has to be at the beginning. The app_menu_data_source module enforces it
|
|
AppInstallId app_order[] = {APP_ID_SETTINGS, APP_ID_MUSIC, APP_ID_NOTIFICATIONS, APP_ID_ALARMS,
|
|
APP_ID_WATCHFACES, APP_ID_WORKOUT, BG_COUNTER_APP_ID,
|
|
MENU_LAYER_APP_ID};
|
|
|
|
uint8_t num_entries = ARRAY_LENGTH(app_order);
|
|
prv_test_new_order_with_filter_callback(app_order, num_entries,
|
|
app_filter_callback);
|
|
}
|
|
|
|
void test_app_menu_data_source__change_order_watchfaces(void) {
|
|
AppInstallId watchface_order[] = {BIG_TIME_APP_ID, APP_ID_TICTOC};
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
uint8_t num_entries = ARRAY_LENGTH(watchface_order);
|
|
prv_shuffle(watchface_order, num_entries);
|
|
prv_test_new_order_with_filter_callback(watchface_order, num_entries,
|
|
watchface_filter_callback);
|
|
}
|
|
}
|
|
|
|
void test_app_menu_data_source__last_app_not_in_order_file(void) {
|
|
// settings has to be at the beginning. The app_menu_data_source module enforces it
|
|
AppInstallId app_order[] = {APP_ID_SETTINGS, APP_ID_MUSIC, APP_ID_NOTIFICATIONS, APP_ID_ALARMS,
|
|
APP_ID_WATCHFACES, APP_ID_WORKOUT,
|
|
BG_COUNTER_APP_ID};
|
|
|
|
uint8_t num_entries = ARRAY_LENGTH(app_order);
|
|
prv_write_order_to_file(app_order, num_entries);
|
|
|
|
app_menu_data_source_init(&data_source, &(AppMenuDataSourceCallbacks) {
|
|
.changed = prv_menu_layer_reload_data,
|
|
.filter = app_filter_callback,
|
|
}, &menu_layer);
|
|
uint16_t num_apps = app_menu_data_source_get_count(&data_source);
|
|
cl_assert_equal_i(num_apps, num_entries + 1);
|
|
|
|
for (uint16_t i = 0; i < num_apps; i++) {
|
|
AppMenuNode *node = app_menu_data_source_get_node_at_index(&data_source, i);
|
|
|
|
// MENU_LAYER_APP_ID isn't in file, but it should still be in the list at the end.
|
|
if (i == (num_apps - 1)) {
|
|
cl_assert_equal_i(node->install_id, MENU_LAYER_APP_ID);
|
|
} else {
|
|
cl_assert_equal_i(node->install_id, app_order[i]);
|
|
}
|
|
}
|
|
|
|
app_menu_data_source_deinit(&data_source);
|
|
}
|
|
|
|
void test_app_menu_data_source__floating_music_app(void) {
|
|
// settings has to be at the beginning. The app_menu_data_source module enforces it
|
|
// This test will move the music app to the second position
|
|
AppInstallId written_order[] = {APP_ID_SETTINGS, APP_ID_NOTIFICATIONS, APP_ID_ALARMS,
|
|
APP_ID_WATCHFACES, APP_ID_WORKOUT, BG_COUNTER_APP_ID,
|
|
MENU_LAYER_APP_ID, APP_ID_MUSIC};
|
|
|
|
AppInstallId desired_order[] = {APP_ID_MUSIC, APP_ID_SETTINGS, APP_ID_NOTIFICATIONS,
|
|
APP_ID_ALARMS, APP_ID_WATCHFACES, APP_ID_WORKOUT,
|
|
BG_COUNTER_APP_ID, MENU_LAYER_APP_ID};
|
|
|
|
uint8_t num_entries = ARRAY_LENGTH(written_order);
|
|
prv_write_order_to_file(written_order, num_entries);
|
|
|
|
app_install_mark_prioritized(APP_ID_MUSIC, true /* can expire */);
|
|
|
|
app_menu_data_source_init(&data_source, &(AppMenuDataSourceCallbacks) {
|
|
.changed = prv_menu_layer_reload_data,
|
|
.filter = app_filter_callback,
|
|
}, &menu_layer);
|
|
uint16_t num_apps = app_menu_data_source_get_count(&data_source);
|
|
|
|
for (uint16_t i = 0; i < num_apps; i++) {
|
|
AppMenuNode *node = app_menu_data_source_get_node_at_index(&data_source, i);
|
|
cl_assert_equal_i(node->install_id, desired_order[i]);
|
|
}
|
|
|
|
app_menu_data_source_deinit(&data_source);
|
|
}
|
|
|
|
void test_app_menu_data_source__all_floating_apps(void) {
|
|
// settings has to be at the beginning. The app_menu_data_source module enforces it
|
|
// This test will move the music app to the second position
|
|
AppInstallId written_order[] = {APP_ID_SETTINGS, APP_ID_NOTIFICATIONS, APP_ID_ALARMS,
|
|
APP_ID_WATCHFACES, APP_ID_WORKOUT, BG_COUNTER_APP_ID,
|
|
MENU_LAYER_APP_ID, APP_ID_MUSIC};
|
|
|
|
AppInstallId desired_order[] = {APP_ID_GOLF, APP_ID_WORKOUT, APP_ID_MUSIC,
|
|
APP_ID_SETTINGS, APP_ID_NOTIFICATIONS, APP_ID_ALARMS,
|
|
APP_ID_WATCHFACES, BG_COUNTER_APP_ID, MENU_LAYER_APP_ID};
|
|
|
|
uint8_t num_entries = ARRAY_LENGTH(written_order);
|
|
prv_write_order_to_file(written_order, num_entries);
|
|
|
|
app_install_mark_prioritized(APP_ID_MUSIC, true /* can expire */);
|
|
app_install_mark_prioritized(APP_ID_WORKOUT, false /* can expire */);
|
|
app_install_mark_prioritized(APP_ID_GOLF, true /* can expire */);
|
|
|
|
app_menu_data_source_init(&data_source, &(AppMenuDataSourceCallbacks) {
|
|
.changed = prv_menu_layer_reload_data,
|
|
.filter = app_filter_callback,
|
|
}, &menu_layer);
|
|
uint16_t num_apps = app_menu_data_source_get_count(&data_source);
|
|
|
|
for (uint16_t i = 0; i < num_apps; i++) {
|
|
AppMenuNode *node = app_menu_data_source_get_node_at_index(&data_source, i);
|
|
cl_assert_equal_i(node->install_id, desired_order[i]);
|
|
}
|
|
|
|
app_menu_data_source_deinit(&data_source);
|
|
}
|
|
|
|
void test_app_menu_data_source__complete_sorted_order(void) {
|
|
// Apps are sorted in the order of Quick Launch only, Override apps, Storage (smallest first),
|
|
// Record (smallest first), and finally Install ID (smallest first). Verify that this is true.
|
|
// This also tests that the Settings app (a special case) respects storage order if it exists
|
|
// in the storage order list.
|
|
AppInstallId storage_order[] = {APP_ID_NOTIFICATIONS, BG_COUNTER_APP_ID, APP_ID_SETTINGS};
|
|
|
|
AppInstallId desired_order[] = {
|
|
// Quick Launch only
|
|
APP_ID_QUIET_TIME_TOGGLE,
|
|
// Override apps
|
|
APP_ID_SPORTS,
|
|
APP_ID_GOLF,
|
|
// Storage (smallest first) defined by `storage_order`
|
|
APP_ID_NOTIFICATIONS,
|
|
BG_COUNTER_APP_ID,
|
|
APP_ID_SETTINGS,
|
|
// Record (smallest first) defined by
|
|
// `tests/overrides/fake_app_registry/shell/system_app_registry_list.auto.h`
|
|
APP_ID_TICTOC,
|
|
APP_ID_MUSIC,
|
|
APP_ID_ALARMS,
|
|
APP_ID_WATCHFACES,
|
|
APP_ID_WORKOUT,
|
|
// Install ID (smallest first)
|
|
MENU_LAYER_APP_ID,
|
|
BIG_TIME_APP_ID,
|
|
};
|
|
|
|
_Static_assert(MENU_LAYER_APP_ID < BIG_TIME_APP_ID,
|
|
"MENU_LAYER_APP_ID is unexpectedly >= BIG_TIME_APP_ID.");
|
|
|
|
const uint8_t num_entries = ARRAY_LENGTH(storage_order);
|
|
prv_write_order_to_file(storage_order, num_entries);
|
|
|
|
app_menu_data_source_init(&data_source, &(AppMenuDataSourceCallbacks) {
|
|
.changed = prv_menu_layer_reload_data,
|
|
.filter = everything_filter_callback,
|
|
}, &menu_layer);
|
|
const uint16_t num_apps = app_menu_data_source_get_count(&data_source);
|
|
|
|
for (uint16_t i = 0; i < num_apps; i++) {
|
|
AppMenuNode *node = app_menu_data_source_get_node_at_index(&data_source, i);
|
|
cl_assert_equal_i(node->install_id, desired_order[i]);
|
|
}
|
|
|
|
app_menu_data_source_deinit(&data_source);
|
|
}
|
|
|
|
void test_app_menu_data_source__settings_app_floats_to_top_if_absent_from_storage_order(void) {
|
|
AppInstallId storage_order[] = {APP_ID_NOTIFICATIONS, BG_COUNTER_APP_ID, APP_ID_MUSIC};
|
|
|
|
AppInstallId desired_order[] = {
|
|
// Settings floats above storage entries since it's absent in the storage order
|
|
APP_ID_SETTINGS,
|
|
// Storage (smallest first) defined by `storage_order`
|
|
APP_ID_NOTIFICATIONS,
|
|
BG_COUNTER_APP_ID,
|
|
APP_ID_MUSIC,
|
|
// Record (smallest first) defined by
|
|
// `tests/overrides/fake_app_registry/shell/system_app_registry_list.auto.h`
|
|
APP_ID_ALARMS,
|
|
APP_ID_WATCHFACES,
|
|
APP_ID_WORKOUT,
|
|
// Install ID (smallest first)
|
|
MENU_LAYER_APP_ID,
|
|
BIG_TIME_APP_ID,
|
|
};
|
|
|
|
_Static_assert(MENU_LAYER_APP_ID < BIG_TIME_APP_ID,
|
|
"MENU_LAYER_APP_ID is unexpectedly >= BIG_TIME_APP_ID.");
|
|
|
|
const uint8_t num_entries = ARRAY_LENGTH(storage_order);
|
|
prv_write_order_to_file(storage_order, num_entries);
|
|
|
|
app_menu_data_source_init(&data_source, &(AppMenuDataSourceCallbacks) {
|
|
.changed = prv_menu_layer_reload_data,
|
|
.filter = app_filter_callback,
|
|
}, &menu_layer);
|
|
const uint16_t num_apps = app_menu_data_source_get_count(&data_source);
|
|
|
|
for (uint16_t i = 0; i < num_apps; i++) {
|
|
AppMenuNode *node = app_menu_data_source_get_node_at_index(&data_source, i);
|
|
cl_assert_equal_i(node->install_id, desired_order[i]);
|
|
}
|
|
|
|
app_menu_data_source_deinit(&data_source);
|
|
}
|
|
|
|
int prv_app_node_comparator(void *app_node_ref, void *new_node_ref);
|
|
|
|
void test_app_menu_data_source__app_node_comparator_equality_cases(void) {
|
|
// Test handling of storage and record equality cases
|
|
AppMenuNode app_menu_nodes[] = {{
|
|
.install_id = APP_ID_ALARMS,
|
|
.storage_order = 0,
|
|
.record_order = 3,
|
|
}, {
|
|
.install_id = APP_ID_TICTOC,
|
|
.storage_order = 0,
|
|
.record_order = 3,
|
|
}, {
|
|
.install_id = APP_ID_NOTIFICATIONS,
|
|
.storage_order = 1,
|
|
.record_order = 0,
|
|
}, {
|
|
.install_id = APP_ID_SETTINGS,
|
|
.storage_order = 2,
|
|
.record_order = 1,
|
|
}, {
|
|
.install_id = APP_ID_WATCHFACES,
|
|
.storage_order = 0,
|
|
.record_order = 4,
|
|
}, {
|
|
.install_id = APP_ID_WORKOUT,
|
|
.storage_order = 0,
|
|
.record_order = 5,
|
|
}};
|
|
|
|
AppInstallId desired_order[] = {
|
|
APP_ID_NOTIFICATIONS,
|
|
APP_ID_SETTINGS,
|
|
APP_ID_TICTOC,
|
|
APP_ID_ALARMS,
|
|
APP_ID_WATCHFACES,
|
|
APP_ID_WORKOUT,
|
|
};
|
|
|
|
AppMenuNode *app_list = NULL;
|
|
const uint16_t num_apps = ARRAY_LENGTH(app_menu_nodes);
|
|
for (uint16_t i = 0; i < num_apps; i++) {
|
|
app_list = (AppMenuNode *)list_sorted_add(&app_list->node, &app_menu_nodes[i].node,
|
|
prv_app_node_comparator, true /* ascending */);
|
|
}
|
|
|
|
for (uint16_t i = 0; i < num_apps; i++) {
|
|
AppMenuNode *node = (AppMenuNode *)list_get_at(&app_list->node, i);
|
|
cl_assert_equal_i(node->install_id, desired_order[i]);
|
|
}
|
|
}
|