mirror of
https://github.com/google/pebble.git
synced 2025-11-28 18:22:24 -05:00
Import the pebble dev site into devsite/
This commit is contained in:
332
devsite/source/_guides/events-and-services/events.md
Normal file
332
devsite/source/_guides/events-and-services/events.md
Normal file
@@ -0,0 +1,332 @@
|
||||
---
|
||||
# Copyright 2025 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.
|
||||
|
||||
title: Event Services
|
||||
description: |
|
||||
How to use the various asynchronous event services to power app features.
|
||||
guide_group: events-and-services
|
||||
order: 5
|
||||
related_docs:
|
||||
- TickTimerService
|
||||
- ConnectionService
|
||||
- AccelerometerService
|
||||
- BatteryStateService
|
||||
- HealthService
|
||||
- AppFocusService
|
||||
- CompassService
|
||||
---
|
||||
|
||||
All Pebble apps are executed in three phases, which are summarized below:
|
||||
|
||||
* Initialization - all code from the beginning of `main()` is run to set up all
|
||||
the components of the app.
|
||||
|
||||
* Event Loop - the app waits for and responds to any event services it has
|
||||
subscribed to.
|
||||
|
||||
* Deinitialization - when the app is exiting (i.e.: the user has pressed Back
|
||||
from the last ``Window`` in the stack) ``app_event_loop()`` returns, and all
|
||||
deinitialization code is run before the app exits.
|
||||
|
||||
Once ``app_event_loop()`` is called, execution of `main()` pauses and all
|
||||
further activities are performed when events from various ``Event Service``
|
||||
types occur. This continues until the app is exiting, and is typically handled
|
||||
in the following pattern:
|
||||
|
||||
```c
|
||||
static void init() {
|
||||
// Initialization code here
|
||||
}
|
||||
|
||||
static void deinit() {
|
||||
// Deinitialization code here
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
init();
|
||||
app_event_loop();
|
||||
deinit();
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Types of Events
|
||||
|
||||
There are multiple types of events an app can receive from various event
|
||||
services. These are described in the table below, along with their handler
|
||||
signature and a brief description of what they do:
|
||||
|
||||
| Event Service | Handler(s) | Description |
|
||||
|---------------|------------|-------------|
|
||||
| ``TickTimerService`` | ``TickHandler`` | Most useful for watchfaces. Allows apps to be notified when a second, minute, hour, day, month or year ticks by. |
|
||||
| ``ConnectionService`` | ``ConnectionHandler`` | Allows apps to know when the Bluetooth connection with the phone connects and disconnects. |
|
||||
| ``AccelerometerService`` | ``AccelDataHandler``<br/>``AccelTapHandler`` | Allows apps to receive raw data or tap events from the onboard accelerometer. |
|
||||
| ``BatteryStateService`` | ``BatteryStateHandler`` | Allows apps to read the state of the battery, as well as whether the watch is plugged in and charging. |
|
||||
| ``HealthService`` | ``HealthEventHandler`` | Allows apps to be notified to changes in various ``HealthMetric`` values as the user performs physical activities. |
|
||||
| ``AppFocusService`` | ``AppFocusHandler`` | Allows apps to know when they are obscured by another window, such as when a notification modal appears. |
|
||||
| ``CompassService`` | ``CompassHeadingHandler`` | Allows apps to read a compass heading, including calibration status of the sensor. |
|
||||
|
||||
In addition, many other APIs also operate through the use of various callbacks
|
||||
including ``MenuLayer``, ``AppMessage``, ``Timer``, and ``Wakeup``, but these
|
||||
are not considered to be 'event services' in the same sense.
|
||||
|
||||
|
||||
## Using Event Services
|
||||
|
||||
The event services described in this guide are all used in the same manner - the
|
||||
app subscribes an implementation of one or more handlers, and is notified by the
|
||||
system when an event of that type occurs. In addition, most also include a
|
||||
'peek' style API to read a single data item or status value on demand. This can
|
||||
be useful to determine the initial service state when a watchapp starts. Apps
|
||||
can subscribe to as many of these services as they require, and can also
|
||||
unsubscribe at any time to stop receiving events.
|
||||
|
||||
Each event service is briefly discussed below with multiple snippets - handler
|
||||
implementation example, subscribing to the service, and any 'peek' API.
|
||||
|
||||
|
||||
### Tick Timer Service
|
||||
|
||||
The ``TickTimerService`` allows an app to be notified when different units of
|
||||
time change. This is decided based upon the ``TimeUnits`` value specified when a
|
||||
subscription is added.
|
||||
|
||||
The [`struct tm`](http://www.cplusplus.com/reference/ctime/tm/) pointer provided
|
||||
in the handler is a standard C object that contains many data fields describing
|
||||
the current time. This can be used with
|
||||
[`strftime()`](http://www.cplusplus.com/reference/ctime/strftime/) to obtain a
|
||||
human-readable string.
|
||||
|
||||
```c
|
||||
static void tick_handler(struct tm *tick_time, TimeUnits changed) {
|
||||
static char s_buffer[8];
|
||||
|
||||
// Read time into a string buffer
|
||||
strftime(s_buffer, sizeof(s_buffer), "%H:%M", tick_time);
|
||||
|
||||
APP_LOG(APP_LOG_LEVEL_INFO, "Time is now %s", s_buffer);
|
||||
}
|
||||
```
|
||||
|
||||
```c
|
||||
// Get updates when the current minute changes
|
||||
tick_timer_service_subscribe(MINUTE_UNIT, tick_handler);
|
||||
```
|
||||
|
||||
> The ``TickTimerService`` has no 'peek' API, but a similar effect can be
|
||||
> achieved using the ``time()`` and ``localtime()`` APIs.
|
||||
|
||||
|
||||
### Connection Service
|
||||
|
||||
The ``ConnectionService`` uses a handler for each of two connection types:
|
||||
|
||||
* `pebble_app_connection_handler` - the connection to the Pebble app on the
|
||||
phone, analogous with the bluetooth connection state.
|
||||
|
||||
* `pebblekit_connection_handler` - the connection to an iOS companion app, if
|
||||
applicable. Will never occur on Android.
|
||||
|
||||
Either one is optional, but at least one must be specified for a valid
|
||||
subscription.
|
||||
|
||||
```c
|
||||
static void app_connection_handler(bool connected) {
|
||||
APP_LOG(APP_LOG_LEVEL_INFO, "Pebble app %sconnected", connected ? "" : "dis");
|
||||
}
|
||||
|
||||
static void kit_connection_handler(bool connected) {
|
||||
APP_LOG(APP_LOG_LEVEL_INFO, "PebbleKit %sconnected", connected ? "" : "dis");
|
||||
}
|
||||
```
|
||||
|
||||
```c
|
||||
connection_service_subscribe((ConnectionHandlers) {
|
||||
.pebble_app_connection_handler = app_connection_handler,
|
||||
.pebblekit_connection_handler = kit_connection_handler
|
||||
});
|
||||
```
|
||||
|
||||
```c
|
||||
// Peek at either the Pebble app or PebbleKit connections
|
||||
bool app_connection = connection_service_peek_pebble_app_connection();
|
||||
bool kit_connection = connection_service_peek_pebblekit_connection();
|
||||
```
|
||||
|
||||
|
||||
### Accelerometer Service
|
||||
|
||||
The ``AccelerometerService`` can be used in two modes - tap events and raw data
|
||||
events. ``AccelTapHandler`` and ``AccelDataHandler`` are used for each of these
|
||||
respective use cases. See the
|
||||
{% guide_link events-and-services/accelerometer %} guide for more
|
||||
information.
|
||||
|
||||
**Data Events**
|
||||
|
||||
```c
|
||||
static void accel_data_handler(AccelData *data, uint32_t num_samples) {
|
||||
APP_LOG(APP_LOG_LEVEL_INFO, "Got %d new samples", (int)num_samples);
|
||||
}
|
||||
```
|
||||
|
||||
```c
|
||||
const int num_samples = 10;
|
||||
|
||||
// Subscribe to data events
|
||||
accel_data_service_subscribe(num_samples, accel_data_handler);
|
||||
```
|
||||
|
||||
```c
|
||||
// Peek at the last reading
|
||||
AccelData data;
|
||||
accel_service_peek(&data);
|
||||
```
|
||||
|
||||
**Tap Events**
|
||||
|
||||
```c
|
||||
static void accel_tap_handler(AccelAxisType axis, int32_t direction) {
|
||||
APP_LOG(APP_LOG_LEVEL_INFO, "Tap event received");
|
||||
}
|
||||
```
|
||||
|
||||
```c
|
||||
// Subscribe to tap events
|
||||
accel_tap_service_subscribe(accel_tap_handler);
|
||||
```
|
||||
|
||||
|
||||
### Battery State Service
|
||||
|
||||
The ``BatteryStateService`` allows apps to examine the state of the battery, and
|
||||
whether or not is is plugged in and charging.
|
||||
|
||||
```c
|
||||
static void battery_state_handler(BatteryChargeState charge) {
|
||||
// Report the current charge percentage
|
||||
APP_LOG(APP_LOG_LEVEL_INFO, "Battery charge is %d%%",
|
||||
(int)charge.charge_percent);
|
||||
}
|
||||
```
|
||||
|
||||
```c
|
||||
// Get battery state updates
|
||||
battery_state_service_subscribe(battery_state_handler);
|
||||
```
|
||||
|
||||
```c
|
||||
// Peek at the current battery state
|
||||
BatteryChargeState state = battery_state_service_peek();
|
||||
```
|
||||
|
||||
|
||||
### Health Service
|
||||
|
||||
The ``HealthService`` uses the ``HealthEventHandler`` to notify a subscribed app
|
||||
when new data pertaining to a ``HealthMetric`` is available. See the
|
||||
{% guide_link events-and-services/health %} guide for more information.
|
||||
|
||||
```c
|
||||
static void health_handler(HealthEventType event, void *context) {
|
||||
if(event == HealthEventMovementUpdate) {
|
||||
APP_LOG(APP_LOG_LEVEL_INFO, "New health movement event");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```c
|
||||
// Subscribe to health-related events
|
||||
health_service_events_subscribe(health_handler, NULL);
|
||||
```
|
||||
|
||||
|
||||
### App Focus Service
|
||||
|
||||
The ``AppFocusService`` operates in two modes - basic and complete.
|
||||
|
||||
**Basic Subscription**
|
||||
|
||||
A basic subscription involves only one handler which will be fired when the app
|
||||
is moved in or out of focus, and any animated transition has completed.
|
||||
|
||||
```c
|
||||
static void focus_handler(bool in_focus) {
|
||||
APP_LOG(APP_LOG_LEVEL_INFO, "App is %s in focus", in_focus ? "now" : "not");
|
||||
}
|
||||
```
|
||||
|
||||
```c
|
||||
// Add a basic subscription
|
||||
app_focus_service_subscribe(focus_handler);
|
||||
```
|
||||
|
||||
**Complete Subscription**
|
||||
|
||||
A complete subscription will notify the app with more detail about changes in
|
||||
focus using two handlers in an ``AppFocusHandlers`` object:
|
||||
|
||||
* `.will_focus` - represents a change in focus that is *about* to occur, such as
|
||||
the start of a transition animation to or from a modal window. `will_focus`
|
||||
will be `true` if the app will be in focus at the end of the transition.
|
||||
|
||||
* `.did_focus` - represents the end of a transition. `did_focus` will be `true`
|
||||
if the app is now completely in focus and the animation has finished.
|
||||
|
||||
```c
|
||||
void will_focus_handler(bool will_focus) {
|
||||
APP_LOG(APP_LOG_LEVEL_INFO, "Will %s focus", will_focus ? "gain" : "lose");
|
||||
}
|
||||
|
||||
void did_focus_handler(bool did_focus) {
|
||||
APP_LOG(APP_LOG_LEVEL_INFO, "%s focus", did_focus ? "Gained" : "Lost");
|
||||
}
|
||||
```
|
||||
|
||||
```c
|
||||
// Subscribe to both types of events
|
||||
app_focus_service_subscribe_handlers((AppFocusHandlers) {
|
||||
.will_focus = will_focus_handler,
|
||||
.did_focus = did_focus_handler
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
### Compass Service
|
||||
|
||||
The ``CompassService`` provides access to regular updates about the watch's
|
||||
magnetic compass heading, if it is calibrated. See the
|
||||
{% guide_link events-and-services/compass %} guide for more information.
|
||||
|
||||
```c
|
||||
static void compass_heading_handler(CompassHeadingData heading_data) {
|
||||
// Is the compass calibrated?
|
||||
if(heading_data.compass_status == CompassStatusCalibrated) {
|
||||
APP_LOG(APP_LOG_LEVEL_INFO, "Calibrated! Heading is %ld",
|
||||
TRIGANGLE_TO_DEG(heading_data.magnetic_heading));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```c
|
||||
// Subscribe to compass heading updates
|
||||
compass_service_subscribe(compass_heading_handler);
|
||||
```
|
||||
|
||||
```c
|
||||
// Peek the compass heading data
|
||||
CompassHeadingData data;
|
||||
compass_service_peek(&data);
|
||||
```
|
||||
Reference in New Issue
Block a user