/* * 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. */ #pragma once #include "modal_manager_private.h" #include "applib/graphics/graphics.h" #include "applib/ui/click_internal.h" #include "applib/ui/window.h" #include "applib/ui/window_stack_animation.h" #include "applib/ui/window_stack_private.h" #include "kernel/events.h" struct ModalContext; typedef struct ModalContext ModalContext; typedef bool (*ModalContextFilterCallback)(ModalContext *context, void *data); //! This defines the priorities for the various modals. The order in which they are //! defined is specified by the interruption policy and determine who is able to interrupt //! whom. If a modal has a higher priority than another modal, it is able to interrupt //! that modal. Before adding anything to here, consider how it would affect the interrupt //! policy. //! Interruption Policy: //! https://docs.google.com/presentation/d/1xIjOR9kh4jcBYonzRstdtFQW0ZNMoFZZwYOUMN2JHNI typedef enum ModalPriority { //! Invalid priority for a modal. ModalPriorityInvalid = -1, //! Min priority, all modals are below or equal to this priority. ModalPriorityMin = 0, //! Discreet mode for watchface overlay information such as Timeline Peek. //! This priority should be used for modals that meant to display above the watchface without //! completely obstructing the watchface. For this reason, Discreet modal windows do not have //! compositor transitions because partial obstruction requires notifying the app of the //! unobstructed regions which only the modal window is able to derive. ModalPriorityDiscreet = ModalPriorityMin, //! Priority for generic one-off windows such as the battery charging window. //! This priority should be used for any modals that don't necessarily care how //! they are shown, just that they are shown. ModalPriorityGeneric, //! Priority used for displaying the phone ui after a phone call has been answered. //! Note: Notifications should always be able to subvert this. ModalPriorityPhone, //! Priority used for displaying notifications. ModalPriorityNotification, //! Priority used for displaying alerts. Alerts are important, but shouldn't //! impact the user of the watch. ModalPriorityAlert, //! Priority used for displaying the voice screen for recording. Ensure this one is //! always kept second to last. ModalPriorityVoice, //! Priority for displaying time-sensitive/critical windows which provide information //! on things that may affect the user's watch experience. However, these should never //! prevent an alarm from displaying. ModalPriorityCritical, //! Priority used for displaying wake up events such as alarms. ModalPriorityAlarm, //! Max priority, all modals are below this priority ModalPriorityMax, NumModalPriorities = ModalPriorityMax, } ModalPriority; typedef enum ModalProperty { ModalProperty_None = 0, //! Whether there exists a modal in a modal stack on screen. ModalProperty_Exists = (1 << 0), //! Whether there exists a modal in a modal stack on screen that uses compositor transitions. ModalProperty_CompositorTransitions = (1 << 1), //! Whether there exists a modal that requested to render. ModalProperty_RenderRequested = (1 << 2), //! Whether all modal stacks are transparent. Having no modal is treated as transparent. ModalProperty_Transparent = (1 << 3), //! Whether all modal stacks pass input through. Having no modal is treated as unfocused. ModalProperty_Unfocused = (1 << 4), //! The default properties equivalent to there being no modal windows. ModalPropertyDefault = (ModalProperty_Transparent | ModalProperty_Unfocused), } ModalProperty; //! Initializes the modal window state. This should be called before any //! Modal applications attempt to push windows. void modal_manager_init(void); //! Sets whether modal windows are enabled. //! @param enabled Boolean indicating whether enabled or disabled //! Note that this is usable before modal_manager_init is called and modal_manager_init will not //! reset this state. void modal_manager_set_min_priority(ModalPriority priority); //! Gets whether modal windows are enabled. // @returns boolean indicating if modals are enabled bool modal_manager_get_enabled(void); //! Returns the ClickManager for the modal windows. //! @returns pointer to a \ref ClickManager ClickManager *modal_manager_get_click_manager(void); //! Returns the first \ref WindowStack to pass the given filter callback. //! Iterates down from the highest priority to the lowest priority. //! @param filter_cb The \ref ModalContextFilterCallback //! @param context Context to pass to the callback //! @returns pointer to a \ref WindowStack WindowStack *modal_manager_find_window_stack(ModalContextFilterCallback filter_cb, void *ctx); //! Returns the stack with the given window priority. //! If the passed priority is invalid, raises an assertion. //! @param priority The \ref ModalPriority of the desired \ref WindowStack //! @returns pointer to a \ref WindowStack WindowStack *modal_manager_get_window_stack(ModalPriority priority); //! Returns the \ref Window of the current visible stack if there is one, //! otherwise NULL. //! @returns Pointer to a \ref Window Window *modal_manager_get_top_window(void); //! Handles a button press event for the Modal Window. Raises an //! assertion if the event is not a click event. //! @param event The \ref PebbleEvent to handle. void modal_manager_handle_button_event(PebbleEvent *event); //! Pops all windows from all modal stacks. void modal_manager_pop_all(void); //! Pops all windows from modal stacks with priorities less than the given priority //! @param the max priority stack to pop all windows from void modal_manager_pop_all_below_priority(ModalPriority priority); //! Called from the kernel event loop between events to handle any changes that have been made //! to the modal window stacks. void modal_manager_event_loop_upkeep(void); //! Enumerates through the modal stacks and returns the flattened properties of all stacks //! combined. For example, if all modals are transparent, the Transparent property will be //! returned. Flattened meaning the entire stack is considered in aggregate. For example, if any //! one modal is opaque, the Transparent property won't be returned. ModalProperty modal_manager_get_properties(void); //! Renders the highest priority top opaque window and all windows with higher priority. //! @param ctx The \ref GContext in which to render. //! @return Modal properties such as whether the modals are transparent or unfocusable void modal_manager_render(GContext *ctx); //! Determines whether the given modal window is visible. Use window_manager_is_window_visible if //! both app windows and modal windows need to be considered. //! @param window The modal window to determine whether it is visible. //! @return true if the modal window is visible, false otherwise bool modal_manager_is_window_visible(Window *window); //! Determines whether the given modal window is focused. Use window_manager_is_window_focused if //! both app windows and modal windows need to be considered. //! @param window The modal window to determine whether it is focused. //! @return true if the modal window is focused, false otherwise bool modal_manager_is_window_focused(Window *window); //! Wrapper to call \ref window_stack_push() with the appropriate stack for //! the given \ref ModalPriority //! @param window The window to push onto the stack //! @param priority The priority of the window stack to push to //! @param animated `True` for animated, otherwise `False` void modal_window_push(Window *window, ModalPriority priority, bool animated); //! Reset the modal manager state. Useful for unit testing. void modal_manager_reset(void);