mirror of
https://github.com/google/pebble
synced 2026-10-17 00:34:11 +02:00
Import of the watch repository from Pebble
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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 "app_glance.h"
|
||||
|
||||
#include "applib/template_string.h"
|
||||
#include "apps/system_apps/launcher/default/launcher_app_glance_generic.h"
|
||||
#include "process_state/app_state/app_state.h"
|
||||
#include "resource/resource_ids.auto.h"
|
||||
#include "services/normal/blob_db/app_glance_db_private.h"
|
||||
#include "services/normal/timeline/attribute.h"
|
||||
#include "services/normal/timeline/timeline_resources.h"
|
||||
#include "syscall/syscall.h"
|
||||
#include "util/string.h"
|
||||
#include "util/uuid.h"
|
||||
|
||||
AppGlanceResult app_glance_add_slice(AppGlanceReloadSession *session, AppGlanceSlice slice) {
|
||||
#if !CAPABILITY_HAS_APP_GLANCES
|
||||
return APP_GLANCE_RESULT_INVALID_SESSION;
|
||||
#endif
|
||||
AppGlanceResult result = APP_GLANCE_RESULT_SUCCESS;
|
||||
|
||||
AppGlance *glance = app_state_get_glance();
|
||||
|
||||
// We use the glance set in the session as a crude way of validating the session
|
||||
// Bail out if the session is invalid
|
||||
if (!session || (glance != session->glance)) {
|
||||
result |= APP_GLANCE_RESULT_INVALID_SESSION;
|
||||
return result;
|
||||
}
|
||||
|
||||
// From here on to the end of the function we can accumulate multiple failures in `result`
|
||||
|
||||
// Check if this slice would put us over the max slices per glance
|
||||
if (glance->num_slices >= APP_GLANCE_DB_MAX_SLICES_PER_GLANCE) {
|
||||
result |= APP_GLANCE_RESULT_SLICE_CAPACITY_EXCEEDED;
|
||||
}
|
||||
|
||||
// Check if this slice's icon is a valid resource (but only if it's not the value that specifies
|
||||
// that the app's default icon should be used)
|
||||
if (slice.layout.icon != APP_GLANCE_SLICE_DEFAULT_ICON) {
|
||||
Uuid app_uuid;
|
||||
sys_get_app_uuid(&app_uuid);
|
||||
const TimelineResourceInfo timeline_resource_info = (TimelineResourceInfo) {
|
||||
.app_id = &app_uuid,
|
||||
.res_id = (TimelineResourceId)slice.layout.icon,
|
||||
};
|
||||
AppResourceInfo app_resource_info = (AppResourceInfo) {};
|
||||
sys_timeline_resources_get_id(&timeline_resource_info,
|
||||
LAUNCHER_APP_GLANCE_GENERIC_ICON_SIZE_TYPE, &app_resource_info);
|
||||
if (app_resource_info.res_id == RESOURCE_ID_INVALID) {
|
||||
result |= APP_GLANCE_RESULT_INVALID_ICON;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the template string is too long (if it's not NULL)
|
||||
// Plus one for the null terminator, then plus one more to become too long
|
||||
const size_t template_string_too_long_size = ATTRIBUTE_APP_GLANCE_SUBTITLE_MAX_LEN + 1 + 1;
|
||||
if (slice.layout.subtitle_template_string &&
|
||||
strnlen(slice.layout.subtitle_template_string,
|
||||
template_string_too_long_size) == template_string_too_long_size) {
|
||||
result |= APP_GLANCE_RESULT_TEMPLATE_STRING_TOO_LONG;
|
||||
}
|
||||
|
||||
// Check if the provided subtitle string is a valid template string, if it's present.
|
||||
const time_t current_time = sys_get_time();
|
||||
if (slice.layout.subtitle_template_string) {
|
||||
const TemplateStringVars template_string_vars = (TemplateStringVars) {
|
||||
.current_time = current_time,
|
||||
};
|
||||
TemplateStringError template_string_error = {0};
|
||||
if (!template_string_evaluate(slice.layout.subtitle_template_string, NULL, 0, NULL,
|
||||
&template_string_vars, &template_string_error)) {
|
||||
result |= APP_GLANCE_RESULT_INVALID_TEMPLATE_STRING;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the slice would expire in the past (if it's not APP_GLANCE_SLICE_NO_EXPIRATION)
|
||||
if ((slice.expiration_time != APP_GLANCE_SLICE_NO_EXPIRATION) &&
|
||||
slice.expiration_time <= current_time) {
|
||||
result |= APP_GLANCE_RESULT_EXPIRES_IN_THE_PAST;
|
||||
}
|
||||
|
||||
// If we haven't failed at this point, we're ready to add the slice to the glance!
|
||||
if (result == APP_GLANCE_RESULT_SUCCESS) {
|
||||
AppGlanceSliceInternal *slice_dest = &glance->slices[glance->num_slices];
|
||||
*slice_dest = (AppGlanceSliceInternal) {
|
||||
.expiration_time = slice.expiration_time,
|
||||
.type = AppGlanceSliceType_IconAndSubtitle,
|
||||
.icon_and_subtitle.icon_resource_id = slice.layout.icon,
|
||||
};
|
||||
// We already checked that the provided template string fits, so use strcpy instead of strncpy
|
||||
if (slice.layout.subtitle_template_string) {
|
||||
strcpy(slice_dest->icon_and_subtitle.template_string, slice.layout.subtitle_template_string);
|
||||
}
|
||||
glance->num_slices++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void app_glance_reload(AppGlanceReloadCallback callback, void *context) {
|
||||
#if !CAPABILITY_HAS_APP_GLANCES
|
||||
return;
|
||||
#endif
|
||||
|
||||
AppGlance *glance = app_state_get_glance();
|
||||
|
||||
Uuid current_app_uuid;
|
||||
sys_get_app_uuid(¤t_app_uuid);
|
||||
|
||||
// Zero out the glance
|
||||
app_glance_service_init_glance(glance);
|
||||
|
||||
if (callback) {
|
||||
// Create a "reload session" on the stack that wraps the glance, and then call the user callback
|
||||
AppGlanceReloadSession session = (AppGlanceReloadSession) {
|
||||
.glance = glance,
|
||||
};
|
||||
callback(&session, APP_GLANCE_DB_MAX_SLICES_PER_GLANCE, context);
|
||||
}
|
||||
|
||||
sys_app_glance_update(¤t_app_uuid, glance);
|
||||
}
|
||||
Reference in New Issue
Block a user