SlideShare a Scribd company logo
1 of 69
Download to read offline
2015 Pebble Developer Retreat
Creating Pebble Apps for Aplite, Basalt, and Chalk
Kevin Conley, Firmware Engineer
Why Target Multiple Platforms?
Maximize Userbase
Pebble Time
Pebble Classic
Continuity
1. User installs your app on an older
platform
2. User upgrades to a new Pebble
3. User already has the most recent
version of your app in their locker :)
Developer Portal Icons
Developer Portal Icons
Agenda
• Runtime Platforms vs. SDK Versions
• Colors
• Display Shapes
• SDK Compatibility
Runtime Platforms vs.
SDK Versions
“Runtime Platform”
• Set of runtime attributes and capabilities
• Does NOT refer to a single watch hardware model
Aplite
2.x ✅
Pebble Classic Pebble Steel
OS Compatibility
• 2.x is legacy
• 3.x for Aplite coming soon!
Aplite Basalt
2.x ✅
3.0 ❌ ✅
Pebble Time Pebble Time Steel
OS Compatibility
Aplite Basalt Chalk
2.x ✅
3.0 ❌ ✅
3.6 ❌ ✅
Pebble Time Round
OS Compatibility
Aplite Basalt Chalk
CPU
24k

ARM Cortex M3
64k
ARM Cortex M4
Resolution
144x168px

(Rectangular)
180x180px
(Circular)
Color Black & White 64 Colors
SmartStrap ❌ ✅
Mic ❌ ✅
Hardware Features
Aplite, Basalt, and Chalk are runtime platforms, not SDK versions.
Aplite Basalt Chalk
2.x ✅
3.0 ❌ ✅
3.6 ❌ ✅
3.x ✅
Unified 3.x SDK later this year
OS Compatibility
runs on
2.x 3.x
Aplite Basalt
2.x Aplite ✅ ✅
3.x Basalt ❌ ✅
compiledagainst
2.x Aplite runs
on 3.x Basalt
SDK Compatibility
runs on
2.x 3.x
Aplite Aplite Basalt Chalk
2.x Aplite ✅ ✅ ✅ ❌
3.x
Aplite ❌ ✅ ❌ ❌
Basalt ❌ ❌ ✅ ❌
Chalk ❌ ❌ ❌ ✅
compiledagainst
3.x apps
are compiled
per platform
SDK Compatibility
Colors
Colors
• Aplite
•Black and white
• Basalt and Chalk
•64 colors
•Pebble color picker tool:
• https://developer.getpebble.com/more/color-picker
•Download color palettes for Photoshop, GIMP, ImageMagick
• https://developer.getpebble.com/guides/pebble-apps/display-
and-animations/intro-to-colors/#color-palettes
Open-Source Dithering Library
• Created by Mathew Reiss
• Display approximate colors beyond provided color palette
• https://github.com/mathewreiss/dithering
Aplite: shades of gray Basalt/Chalk: > 300 colors
#define COLOR_FALLBACK(_____, _____)
#define COLOR_FALLBACK(color_value, bw_value)
#define COLOR_FALLBACK(color_value, bw_value)
(deprecated)
Organize Code Using Color Macros
#define PBL_IF_COLOR_ELSE(if_true, if_false)
#define PBL_IF_BW_ELSE(if_true, if_false)
Returns if_true on watches that support color and if_false otherwise
Returns if_true on watches that only support black & white and if_false otherwise
Organize Code Using Color Defines
#define PBL_COLOR
#define PBL_BW
Defined on watches that support color and undefined otherwise
Defined on watches that only support black & white and undefined otherwise
Color-Specific Resources
"resources": {

"media": [

{

"type": "png",

"name": "MY_IMAGE",

"file": "images/image.png"

}

]

}

appinfo.json: resources/
images/
image~bw.png
image~color.png
image~bw.png image~color.png
WatchInfoColor
GColor text_foreground_color, text_background_color;
switch(watch_info_get_color()) {

case WATCH_INFO_COLOR_TIME_STEEL_GOLD:

// White on red theme
text_foreground_color = GColorWhite;
text_background_color = GColorRed;

break;

case WATCH_INFO_COLOR_TIME_ROUND_BLACK_20:

// White on black theme

text_foreground_color = GColorWhite;
text_background_color = GColorBlack;

break;

/* Other cases... */ 

}
text_layer_set_text_color(s_label_layer, text_foreground_color);

text_layer_set_background_color(s_label_layer, text_background_color);
• Customize your app’s UI using the color of the Pebble watch
Display Shapes
Display Shapes
• Round has 7% more
visible pixels than
rectangular
Rectangular
(144 x 168)
Round (visible)
Round (total)
(180 x 180)
(0, 0)
Calculate Position/Size as a Function of Other Layers
const Layer *window_layer = window_get_root_layer(window);
const GRect text_frame = GRect(0, 72, 144, 20);
const TextLayer *text_layer = text_layer_create(text_frame);
text_layer_set_text(text_layer, "Hello world!");
text_layer_set_text_alignment(text_layer, GTextAlignmentCenter);
layer_add_child(window_layer, text_layer_get_layer(text_layer));
Calculate Position/Size as a Function of Other Layers
const Layer *window_layer = window_get_root_layer(window);
const GRect text_frame = GRect(0, 72, 144, 20);
const TextLayer *text_layer = text_layer_create(text_frame);
text_layer_set_text(text_layer, "Hello world!");
text_layer_set_text_alignment(text_layer, GTextAlignmentCenter);
layer_add_child(window_layer, text_layer_get_layer(text_layer));
Calculate Position/Size as a Function of Other Layers
const Layer *window_layer = window_get_root_layer(window);
const GRect text_frame = GRect(0, 72, 144, 20);
const TextLayer *text_layer = text_layer_create(text_frame);
text_layer_set_text(text_layer, "Hello world!");
text_layer_set_text_alignment(text_layer, GTextAlignmentCenter);
layer_add_child(window_layer, text_layer_get_layer(text_layer));
Calculate Position/Size as a Function of Other Layers
const Layer *window_layer = window_get_root_layer(window);
const GRect window_bounds = layer_get_bounds(window_layer);
const int16_t text_height = 20;
const int16_t text_frame_y =
(window_bounds.size.h - text_height) / 2;
const GRect text_frame = (GRect) {
.origin = GPoint(0, text_frame_y),
.size = GSize(window_bounds.size.w, text_height)
};
const TextLayer *text_layer = text_layer_create(text_frame);
text_layer_set_text(text_layer, "Hello world!");
text_layer_set_text_alignment(text_layer, GTextAlignmentCenter);
layer_add_child(window_layer, text_layer_get_layer(text_layer));
void grect_align(GRect *rect, const GRect *inside_rect,
const GAlign alignment, const bool clip);
GAlignCenter
clip = false
rect
inside_rect
Align Rectangles Within Other Rectangles Using grect_align()
inside_rect
GAlignTop
clip = true
rect
typedef enum GAlign {

GAlignCenter,

GAlignTopLeft,

GAlignTopRight,

GAlignTop,

GAlignLeft,

GAlignBottom,

GAlignRight,

GAlignBottomRight,

GAlignBottomLeft

} GAlign; GAlignBottomRight
GAlignRight
GAlignTopRight
GAlignBottom
GAlignCenter
GAlignTop
GAlignBottomLeft
GAlignLeft
GAlignTopLeft
const GRect a = grect_inset(rect, GEdgeInsets(16)); // all sides
const GRect b = grect_inset(rect, GEdgeInsets(25, 16)); // top & bottom, right & left
const GRect c = grect_inset(rect, GEdgeInsets(25, 16, 10)); // top, right & left, bottom
const GRect d = grect_inset(rect, GEdgeInsets(25, -20, 10, 16)); // top, right, bottom, left
a b
c d
16px
16px
25px 25px 25px
25px
10px 10px
16px 16px 16px 16px16px 16px 16px 20px
Inset Rectangles Using grect_inset() and GEdgeInsets()
rect
GPoint grect_center_point(const GRect *rect);
result
Find the Center of Rectangles Using grect_center_point()
• Use PBL_IF_[ROUND | RECT]_ELSE() macros to choose
values or simple expressions based on the display shape
• Similar to PBL_IF_[COLOR | BW]_ELSE()
Organize Code Using Display Shape Macros/Defines
const uint16_t area = PBL_IF_ROUND_ELSE(PI * (width * width / 4),
(width * height));
• For multiple lines, choose code using PBL_[ROUND | RECT] defines
#if defined(PBL_ROUND)

const GPoint center_point = grect_center_point(&rect);

graphics_fill_circle(ctx, center_point, radius);

#else
const uint16_t corner_radius = 0;

graphics_fill_rect(ctx, rect, corner_radius, GCornerNone);

#endif
Organize Code Using Display Shape Macros/Defines
• For > 5 lines, break code into functions with _rect/_round suffixes
• If the functions share the same arguments, you can simplify
calling them by using the PBL_IF_[ROUND | RECT]_ELSE() macro
• Otherwise, use the PBL_[ROUND | RECT] defines:
Organize Code Using Display Shape Macros/Defines
PBL_IF_RECT_ELSE(function_rect, function_round)(arg1, arg2, ...);
#if defined(PBL_RECT)

function_rect(arg1);

#else

function_round(arg1, arg2);

#endif
• For > 2 display-specific functions, break into separate _rect/_round files
• Use wrapper file to choose appropriate implementation using display
shape defines/macros
• Alternatively, if the files share a common API:
• (also requires ifdef’ing out implementations)
Organize Code Using Display Shape Macros/Defines
// main.c
#if defined(PBL_RECT)

#include “file_rect.h"

#else

#include “file_round.h"

#endif
src/
file_rect.c
file_rect.h
file_round.c
file_round.h
file.c
file.h
main.c
Display-Specific Resources
"resources": {

"media": [

{

"type": "png",

"name": "MY_IMAGE",

"file": "images/image.png"

}

]

}

resources/
images/
image~rect.png
image~color~round.png
appinfo.json:
image~rect.png image~color~round.png
• Most-specific resource will be used
• Ambiguity will result in compiler error
Two-Pixel Margin on Round Displays
• Extend background colors to all outer
edges
• Avoid thin rings around the edge of the
display
• Manufacturing variations may result in
off-center appearance
• Instead, use thick rings or significantly
inset from the edge
Platform-Specific Designs
“Caltrain” by Katharine Berry: https://github.com/Katharine/pebble-caltrain/
Rectangular Round
UI Components
Status Bar
• For SDK 2.x, the status bar appears by default and insets the window from
the top unless you use:
window_set_fullscreen(window, true);
• For SDK 3.x, the status bar is a UI component you must create, configure,
and add to the layer hierarchy yourself:
static StatusBarLayer *s_status_bar;

s_status_bar = status_bar_layer_create();

status_bar_layer_set_separator_mode(s_status_bar,
StatusBarLayerSeparatorModeDotted);

status_bar_layer_set_colors(s_status_bar, GColorBlack, GColorWhite);

const Layer *status_bar_layer = status_bar_layer_get_layer(s_status_bar);

layer_add_child(window_root_layer, status_bar_layer);
Status Bar
Rectangular Round
Status Bar
s_status_bar = status_bar_layer_create();

GRect status_bar_rect = window_bounds;

status_bar_rect.size.h = STATUS_BAR_LAYER_HEIGHT;

layer_set_frame(
status_bar_layer_get_layer(s_status_bar),

status_bar_rect);



// top/bottom: statusbar, left/right: 0
const GEdgeInsets insets = GEdgeInsets(
STATUS_BAR_LAYER_HEIGHT, 0);
GRect menu_layer_rect = grect_inset(
window_bounds, insets);
Status Bar
ActionBar
Rectangular
Round
ActionBar
s_action_bar = action_bar_layer_create();

action_bar_layer_add_to_window(
s_action_bar, window);



// top: statusbar, right: actionbar, bottom/left:0
const GEdgeInsets insets = GEdgeInsets(

STATUS_BAR_LAYER_HEIGHT, ACTION_BAR_WIDTH, 0, 0);

GRect content_rect = grect_inset(
window_bounds, insets);
ActionBar
MenuLayer
Rectangular Round
MENU_CELL_ROUND_UNFOCUSED_SHORT_CELL_HEIGHT
MENU_CELL_ROUND_FOCUSED_TALL_CELL_HEIGHT

MENU_CELL_ROUND_UNFOCUSED_SHORT_CELL_HEIGHT
MENU_CELL_ROUND_UNFOCUSED_TALL_CELL_HEIGHT
MENU_CELL_ROUND_FOCUSED_SHORT_CELL_HEIGHT
MENU_CELL_ROUND_UNFOCUSED_TALL_CELL_HEIGHT
MENU_CELL_BASIC_CELL_HEIGHT
MENU_CELL_BASIC_CELL_HEIGHT
MENU_CELL_BASIC_CELL_HEIGHT
MenuLayer
// default on Chalk
menu_layer_set_center_focused(menu_layer, true);
static int16_t get_cell_height_callback(MenuLayer *menu_layer,
MenuIndex *cell_index,

void *callback_context) {

#if defined(PBL_ROUND)
// when center_focused, MenuLayer can handle cell heights
// that change based on the selection status
if (menu_layer_is_index_selected(menu_layer, cell_index)) {

return MENU_CELL_ROUND_FOCUSED_TALL_CELL_HEIGHT;

} else {

return MENU_CELL_ROUND_UNFOCUSED_SHORT_CELL_HEIGHT;

}
#else
return MENU_CELL_BASIC_CELL_HEIGHT;
#endif

}

MenuLayer
TextLayer
• To maximize content visible on round displays, enable text
flow and paging with an optional inset (for padding):
text_layer_enable_screen_text_flow_and_paging(s_text_layer, 8);
TextLayer
• Text flow on a round display without pagination looks weird…
WatchInfo
• Inspect what watch the app is running on
• Useful e.g. if you want to align visual elements with buttons
• Next to different screen coordinates for different watches
GRect layer_frame = GRectZero;

switch(watch_info_get_model()) {

case WATCH_INFO_MODEL_PEBBLE_STEEL:

layer_frame = GRect(0, 64, 144, 44);

break;

case WATCH_INFO_MODEL_PEBBLE_TIME:

layer_frame = GRect(0, 58, 144, 56);

break;

/* Other cases */

}
SDK Compatibility
Platform Defines
• Feature/capability defines, like PBL_COLOR, PBL_ROUND,
etc. should be used in favor of these
• Exception: CPU/memory-specific code
#define PBL_PLATFORM_APLITE
#define PBL_PLATFORM_BASALT
#define PBL_PLATFORM_CHALK
Platform Specific Resources
• Can also use ~aplite, ~basalt, and ~chalk suffixes
• But overall, in most cases it’s best to use ~rect, ~round, ~bw, ~color suffixes instead
"resources": {

"media": [

{

"type": "png",

"name": "MY_IMAGE",

"file": “images/image.png”,
"targetPlatforms": [
"basalt"
]

}

]

}

GPoint shim_gpoint_from_polar(GRect rect, int32_t angle) {

#if defined(PBL_SDK_2)
const GPoint center = GPoint(rect.origin.x + (rect.size.w / 2),
rect.origin.y + (rect.size.h / 2));
const int16_t radius = MIN(rect.size.w, rect.size.h) / 2;

return GPoint((sin_lookup(angle) * radius / TRIG_MAX_RATIO) + center.x,

(-cos_lookup(angle) * radius / TRIG_MAX_RATIO) + center.y);

#else

return gpoint_from_polar(rect, GOvalScaleModeFitCircle, angle);

#endif

}
Shims
• Newer SDK 3.x functions do not exist in SDK 2.x
• You can create shims for them using PBL_SDK_2/3 defines:
PebbleKit JS API Availability
• Some PebbleKit JS APIs don’t exist on Pebble Classic mobile apps,
• Check if they are available and fail gracefully if necessary
if (Pebble.getActiveWatchInfo) {
// API is available; use it!
var info = Pebble.getActiveWatchInfo();
console.log('Pebble model: ' + info.model);
} else {
// Gracefully handle unavailable API
}
Check Return Values
• APIs may return NULL if:
• Unsupported by platform
• Permissions not given
• Phone disconnected
• Check the return value before using it and fail gracefully if necessary
const DictationSession *session = dictation_session_create(0, callback,
callback_context);
if (session) {
/* Success! */
dictation_session_start(session);
} else {
/* DictationSession is unsupported, need to fail gracefully here! */
}
Marcel: Friday 1 pm
Starting with Chalk, you
need to compile with
PebbleKit iOS 3.0
Since PebbleOS 3.0, you
need to compile with
PebbleKit Android 3.0
AndroidiOS
Mobile App Compatibility
Running Multiple Emulators at Once
• pebble install --emulator=aplite && pebble install --emulator=basalt &&
pebble install —-emulator=chalk
Automating Taking Screenshots
• pebble screenshot --emulator=aplite && pebble screenshot --emulator=basalt
&& pebble screenshot —-emulator=chalk
Recap
• Runtime Platforms vs. SDK Versions
• Colors
• Display Shapes
• SDK Compatibility
Questions?

More Related Content

What's hot

PEARC17: Modernizing GooFit: A Case Study
PEARC17: Modernizing GooFit: A Case StudyPEARC17: Modernizing GooFit: A Case Study
PEARC17: Modernizing GooFit: A Case StudyHenry Schreiner
 
IRIS-HEP Retreat: Boost-Histogram Roadmap
IRIS-HEP Retreat: Boost-Histogram RoadmapIRIS-HEP Retreat: Boost-Histogram Roadmap
IRIS-HEP Retreat: Boost-Histogram RoadmapHenry Schreiner
 
Migrating from OpenGL to Vulkan
Migrating from OpenGL to VulkanMigrating from OpenGL to Vulkan
Migrating from OpenGL to VulkanMark Kilgard
 
Simple ETL in python 3.5+ with Bonobo - PyParis 2017
Simple ETL in python 3.5+ with Bonobo - PyParis 2017Simple ETL in python 3.5+ with Bonobo - PyParis 2017
Simple ETL in python 3.5+ with Bonobo - PyParis 2017Romain Dorgueil
 
The Power of Rails 2.3 Engines & Templates
The Power of Rails 2.3 Engines & TemplatesThe Power of Rails 2.3 Engines & Templates
The Power of Rails 2.3 Engines & TemplatesTse-Ching Ho
 
Anatomy of a Gradle plugin
Anatomy of a Gradle pluginAnatomy of a Gradle plugin
Anatomy of a Gradle pluginDmytro Zaitsev
 
Modern OpenGL Usage: Using Vertex Buffer Objects Well
Modern OpenGL Usage: Using Vertex Buffer Objects Well Modern OpenGL Usage: Using Vertex Buffer Objects Well
Modern OpenGL Usage: Using Vertex Buffer Objects Well Mark Kilgard
 
How data rules the world: Telemetry in Battlefield Heroes
How data rules the world: Telemetry in Battlefield HeroesHow data rules the world: Telemetry in Battlefield Heroes
How data rules the world: Telemetry in Battlefield HeroesElectronic Arts / DICE
 
Developing and Deploying Apps with the Postgres FDW
Developing and Deploying Apps with the Postgres FDWDeveloping and Deploying Apps with the Postgres FDW
Developing and Deploying Apps with the Postgres FDWJonathan Katz
 
Best Practices in Qt Quick/QML - Part 1 of 4
Best Practices in Qt Quick/QML - Part 1 of 4Best Practices in Qt Quick/QML - Part 1 of 4
Best Practices in Qt Quick/QML - Part 1 of 4ICS
 
OpenGL NVIDIA Command-List: Approaching Zero Driver Overhead
OpenGL NVIDIA Command-List: Approaching Zero Driver OverheadOpenGL NVIDIA Command-List: Approaching Zero Driver Overhead
OpenGL NVIDIA Command-List: Approaching Zero Driver OverheadTristan Lorach
 
Experiments in Sharing Java VM Technology with CRuby
Experiments in Sharing Java VM Technology with CRubyExperiments in Sharing Java VM Technology with CRuby
Experiments in Sharing Java VM Technology with CRubyMatthew Gaudet
 
Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)
Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)
Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)ngotogenome
 
OrientDB and Hazelcast
OrientDB and HazelcastOrientDB and Hazelcast
OrientDB and HazelcastLuca Garulli
 
CHEP 2018: A Python upgrade to the GooFit package for parallel fitting
CHEP 2018: A Python upgrade to the GooFit package for parallel fittingCHEP 2018: A Python upgrade to the GooFit package for parallel fitting
CHEP 2018: A Python upgrade to the GooFit package for parallel fittingHenry Schreiner
 
PG-4034, Using OpenGL and DirectX for Heterogeneous Compute, by Karl Hillesland
PG-4034, Using OpenGL and DirectX for Heterogeneous Compute, by Karl HilleslandPG-4034, Using OpenGL and DirectX for Heterogeneous Compute, by Karl Hillesland
PG-4034, Using OpenGL and DirectX for Heterogeneous Compute, by Karl HilleslandAMD Developer Central
 
Foreign Data Wrapper Enhancements
Foreign Data Wrapper EnhancementsForeign Data Wrapper Enhancements
Foreign Data Wrapper EnhancementsShigeru Hanada
 

What's hot (20)

PEARC17: Modernizing GooFit: A Case Study
PEARC17: Modernizing GooFit: A Case StudyPEARC17: Modernizing GooFit: A Case Study
PEARC17: Modernizing GooFit: A Case Study
 
IRIS-HEP Retreat: Boost-Histogram Roadmap
IRIS-HEP Retreat: Boost-Histogram RoadmapIRIS-HEP Retreat: Boost-Histogram Roadmap
IRIS-HEP Retreat: Boost-Histogram Roadmap
 
Migrating from OpenGL to Vulkan
Migrating from OpenGL to VulkanMigrating from OpenGL to Vulkan
Migrating from OpenGL to Vulkan
 
Simple ETL in python 3.5+ with Bonobo - PyParis 2017
Simple ETL in python 3.5+ with Bonobo - PyParis 2017Simple ETL in python 3.5+ with Bonobo - PyParis 2017
Simple ETL in python 3.5+ with Bonobo - PyParis 2017
 
The Power of Rails 2.3 Engines & Templates
The Power of Rails 2.3 Engines & TemplatesThe Power of Rails 2.3 Engines & Templates
The Power of Rails 2.3 Engines & Templates
 
Anatomy of a Gradle plugin
Anatomy of a Gradle pluginAnatomy of a Gradle plugin
Anatomy of a Gradle plugin
 
Scalding
ScaldingScalding
Scalding
 
PyHEP 2019: Python 3.8
PyHEP 2019: Python 3.8PyHEP 2019: Python 3.8
PyHEP 2019: Python 3.8
 
Modern OpenGL Usage: Using Vertex Buffer Objects Well
Modern OpenGL Usage: Using Vertex Buffer Objects Well Modern OpenGL Usage: Using Vertex Buffer Objects Well
Modern OpenGL Usage: Using Vertex Buffer Objects Well
 
How data rules the world: Telemetry in Battlefield Heroes
How data rules the world: Telemetry in Battlefield HeroesHow data rules the world: Telemetry in Battlefield Heroes
How data rules the world: Telemetry in Battlefield Heroes
 
Developing and Deploying Apps with the Postgres FDW
Developing and Deploying Apps with the Postgres FDWDeveloping and Deploying Apps with the Postgres FDW
Developing and Deploying Apps with the Postgres FDW
 
Ruby meets Go
Ruby meets GoRuby meets Go
Ruby meets Go
 
Best Practices in Qt Quick/QML - Part 1 of 4
Best Practices in Qt Quick/QML - Part 1 of 4Best Practices in Qt Quick/QML - Part 1 of 4
Best Practices in Qt Quick/QML - Part 1 of 4
 
OpenGL NVIDIA Command-List: Approaching Zero Driver Overhead
OpenGL NVIDIA Command-List: Approaching Zero Driver OverheadOpenGL NVIDIA Command-List: Approaching Zero Driver Overhead
OpenGL NVIDIA Command-List: Approaching Zero Driver Overhead
 
Experiments in Sharing Java VM Technology with CRuby
Experiments in Sharing Java VM Technology with CRubyExperiments in Sharing Java VM Technology with CRuby
Experiments in Sharing Java VM Technology with CRuby
 
Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)
Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)
Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)
 
OrientDB and Hazelcast
OrientDB and HazelcastOrientDB and Hazelcast
OrientDB and Hazelcast
 
CHEP 2018: A Python upgrade to the GooFit package for parallel fitting
CHEP 2018: A Python upgrade to the GooFit package for parallel fittingCHEP 2018: A Python upgrade to the GooFit package for parallel fitting
CHEP 2018: A Python upgrade to the GooFit package for parallel fitting
 
PG-4034, Using OpenGL and DirectX for Heterogeneous Compute, by Karl Hillesland
PG-4034, Using OpenGL and DirectX for Heterogeneous Compute, by Karl HilleslandPG-4034, Using OpenGL and DirectX for Heterogeneous Compute, by Karl Hillesland
PG-4034, Using OpenGL and DirectX for Heterogeneous Compute, by Karl Hillesland
 
Foreign Data Wrapper Enhancements
Foreign Data Wrapper EnhancementsForeign Data Wrapper Enhancements
Foreign Data Wrapper Enhancements
 

Similar to #PDR15 Creating Pebble Apps for Aplite, Basalt, and Chalk

.gradle 파일 정독해보기
.gradle 파일 정독해보기.gradle 파일 정독해보기
.gradle 파일 정독해보기경주 전
 
Android_Bootcamp_PPT_GDSC_ITS_Engineering
Android_Bootcamp_PPT_GDSC_ITS_EngineeringAndroid_Bootcamp_PPT_GDSC_ITS_Engineering
Android_Bootcamp_PPT_GDSC_ITS_EngineeringShivanshSeth6
 
Software Development Automation With Scripting Languages
Software Development Automation With Scripting LanguagesSoftware Development Automation With Scripting Languages
Software Development Automation With Scripting LanguagesIonela
 
"Xapi-lang For declarative code generation" By James Nelson
"Xapi-lang For declarative code generation" By James Nelson"Xapi-lang For declarative code generation" By James Nelson
"Xapi-lang For declarative code generation" By James NelsonGWTcon
 
Reproducible Computational Research in R
Reproducible Computational Research in RReproducible Computational Research in R
Reproducible Computational Research in RSamuel Bosch
 
SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra
SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra  SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra
SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra Sencha
 
Css3 and gwt in perfect harmony
Css3 and gwt in perfect harmonyCss3 and gwt in perfect harmony
Css3 and gwt in perfect harmonyjdramaix
 
Css3 and gwt in perfect harmony
Css3 and gwt in perfect harmonyCss3 and gwt in perfect harmony
Css3 and gwt in perfect harmonyArcbees
 
Cocoa Heads Tricity - Design Patterns
Cocoa Heads Tricity - Design PatternsCocoa Heads Tricity - Design Patterns
Cocoa Heads Tricity - Design PatternsMaciej Burda
 
Rspec and Capybara Intro Tutorial at RailsConf 2013
Rspec and Capybara Intro Tutorial at RailsConf 2013Rspec and Capybara Intro Tutorial at RailsConf 2013
Rspec and Capybara Intro Tutorial at RailsConf 2013Brian Sam-Bodden
 
Tutorial: Implementing your first Postgres extension | PGConf EU 2019 | Burak...
Tutorial: Implementing your first Postgres extension | PGConf EU 2019 | Burak...Tutorial: Implementing your first Postgres extension | PGConf EU 2019 | Burak...
Tutorial: Implementing your first Postgres extension | PGConf EU 2019 | Burak...Citus Data
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial EnAnkur Dongre
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial EnAnkur Dongre
 
(1) c sharp introduction_basics_dot_net
(1) c sharp introduction_basics_dot_net(1) c sharp introduction_basics_dot_net
(1) c sharp introduction_basics_dot_netNico Ludwig
 
Go Faster With Native Compilation
Go Faster With Native CompilationGo Faster With Native Compilation
Go Faster With Native CompilationPGConf APAC
 
Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2Rajeev Rastogi (KRR)
 
Smoothing Your Java with DSLs
Smoothing Your Java with DSLsSmoothing Your Java with DSLs
Smoothing Your Java with DSLsintelliyole
 
Kerberizing Spark: Spark Summit East talk by Abel Rincon and Jorge Lopez-Malla
Kerberizing Spark: Spark Summit East talk by Abel Rincon and Jorge Lopez-MallaKerberizing Spark: Spark Summit East talk by Abel Rincon and Jorge Lopez-Malla
Kerberizing Spark: Spark Summit East talk by Abel Rincon and Jorge Lopez-MallaSpark Summit
 

Similar to #PDR15 Creating Pebble Apps for Aplite, Basalt, and Chalk (20)

.gradle 파일 정독해보기
.gradle 파일 정독해보기.gradle 파일 정독해보기
.gradle 파일 정독해보기
 
Android_Bootcamp_PPT_GDSC_ITS_Engineering
Android_Bootcamp_PPT_GDSC_ITS_EngineeringAndroid_Bootcamp_PPT_GDSC_ITS_Engineering
Android_Bootcamp_PPT_GDSC_ITS_Engineering
 
Software Development Automation With Scripting Languages
Software Development Automation With Scripting LanguagesSoftware Development Automation With Scripting Languages
Software Development Automation With Scripting Languages
 
"Xapi-lang For declarative code generation" By James Nelson
"Xapi-lang For declarative code generation" By James Nelson"Xapi-lang For declarative code generation" By James Nelson
"Xapi-lang For declarative code generation" By James Nelson
 
Reproducible Computational Research in R
Reproducible Computational Research in RReproducible Computational Research in R
Reproducible Computational Research in R
 
SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra
SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra  SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra
SenchaCon 2016: Learn the Top 10 Best ES2015 Features - Lee Boonstra
 
a3.pdf
a3.pdfa3.pdf
a3.pdf
 
Css3 and gwt in perfect harmony
Css3 and gwt in perfect harmonyCss3 and gwt in perfect harmony
Css3 and gwt in perfect harmony
 
Css3 and gwt in perfect harmony
Css3 and gwt in perfect harmonyCss3 and gwt in perfect harmony
Css3 and gwt in perfect harmony
 
Cocoa Heads Tricity - Design Patterns
Cocoa Heads Tricity - Design PatternsCocoa Heads Tricity - Design Patterns
Cocoa Heads Tricity - Design Patterns
 
Go Faster With Native Compilation
Go Faster With Native CompilationGo Faster With Native Compilation
Go Faster With Native Compilation
 
Rspec and Capybara Intro Tutorial at RailsConf 2013
Rspec and Capybara Intro Tutorial at RailsConf 2013Rspec and Capybara Intro Tutorial at RailsConf 2013
Rspec and Capybara Intro Tutorial at RailsConf 2013
 
Tutorial: Implementing your first Postgres extension | PGConf EU 2019 | Burak...
Tutorial: Implementing your first Postgres extension | PGConf EU 2019 | Burak...Tutorial: Implementing your first Postgres extension | PGConf EU 2019 | Burak...
Tutorial: Implementing your first Postgres extension | PGConf EU 2019 | Burak...
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial En
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial En
 
(1) c sharp introduction_basics_dot_net
(1) c sharp introduction_basics_dot_net(1) c sharp introduction_basics_dot_net
(1) c sharp introduction_basics_dot_net
 
Go Faster With Native Compilation
Go Faster With Native CompilationGo Faster With Native Compilation
Go Faster With Native Compilation
 
Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2
 
Smoothing Your Java with DSLs
Smoothing Your Java with DSLsSmoothing Your Java with DSLs
Smoothing Your Java with DSLs
 
Kerberizing Spark: Spark Summit East talk by Abel Rincon and Jorge Lopez-Malla
Kerberizing Spark: Spark Summit East talk by Abel Rincon and Jorge Lopez-MallaKerberizing Spark: Spark Summit East talk by Abel Rincon and Jorge Lopez-Malla
Kerberizing Spark: Spark Summit East talk by Abel Rincon and Jorge Lopez-Malla
 

More from Pebble Technology

#PDR15 - Awesome Appstore Assets
#PDR15 - Awesome Appstore Assets#PDR15 - Awesome Appstore Assets
#PDR15 - Awesome Appstore AssetsPebble Technology
 
#PDR15 - Smartstrap Workshop
#PDR15 - Smartstrap Workshop#PDR15 - Smartstrap Workshop
#PDR15 - Smartstrap WorkshopPebble Technology
 
#PDR15 - Data Analytics and Pebble
#PDR15 - Data Analytics and Pebble#PDR15 - Data Analytics and Pebble
#PDR15 - Data Analytics and PebblePebble Technology
 
#PDR15 - Best Use Cases For Timeline
#PDR15 - Best Use Cases For Timeline#PDR15 - Best Use Cases For Timeline
#PDR15 - Best Use Cases For TimelinePebble Technology
 
#PDR15 - Developing for Round
#PDR15 - Developing for Round#PDR15 - Developing for Round
#PDR15 - Developing for RoundPebble Technology
 
#PDR15 - Designing for Pebble
#PDR15 - Designing for Pebble#PDR15 - Designing for Pebble
#PDR15 - Designing for PebblePebble Technology
 
Overlay & Libraries | Pebble Meetup Oct. 2014
Overlay & Libraries | Pebble Meetup Oct. 2014Overlay & Libraries | Pebble Meetup Oct. 2014
Overlay & Libraries | Pebble Meetup Oct. 2014Pebble Technology
 
Connecting Pebble to the World
Connecting Pebble to the WorldConnecting Pebble to the World
Connecting Pebble to the WorldPebble Technology
 
Guest Presentation - Strap | Pebble Developer Retreat 2014
Guest Presentation - Strap | Pebble Developer Retreat 2014Guest Presentation - Strap | Pebble Developer Retreat 2014
Guest Presentation - Strap | Pebble Developer Retreat 2014Pebble Technology
 
Battery Life | Pebble Developer Retreat 2014
Battery Life | Pebble Developer Retreat 2014Battery Life | Pebble Developer Retreat 2014
Battery Life | Pebble Developer Retreat 2014Pebble Technology
 
Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014
Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014
Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014Pebble Technology
 
Advanced Techniques: Size | Pebble Developer Retreat 2014
Advanced Techniques: Size | Pebble Developer Retreat 2014Advanced Techniques: Size | Pebble Developer Retreat 2014
Advanced Techniques: Size | Pebble Developer Retreat 2014Pebble Technology
 
Advanced Techniques: Graphics | Pebble Developer Retreat 2014
Advanced Techniques: Graphics | Pebble Developer Retreat 2014Advanced Techniques: Graphics | Pebble Developer Retreat 2014
Advanced Techniques: Graphics | Pebble Developer Retreat 2014Pebble Technology
 

More from Pebble Technology (19)

#PDR15 - Awesome Appstore Assets
#PDR15 - Awesome Appstore Assets#PDR15 - Awesome Appstore Assets
#PDR15 - Awesome Appstore Assets
 
#PDR15 - Smartstrap Workshop
#PDR15 - Smartstrap Workshop#PDR15 - Smartstrap Workshop
#PDR15 - Smartstrap Workshop
 
#PDR15 - Data Analytics and Pebble
#PDR15 - Data Analytics and Pebble#PDR15 - Data Analytics and Pebble
#PDR15 - Data Analytics and Pebble
 
#PDR15 - Best Use Cases For Timeline
#PDR15 - Best Use Cases For Timeline#PDR15 - Best Use Cases For Timeline
#PDR15 - Best Use Cases For Timeline
 
#PDR15 - PebbleKit iOS 3.0
#PDR15 - PebbleKit iOS 3.0#PDR15 - PebbleKit iOS 3.0
#PDR15 - PebbleKit iOS 3.0
 
#PDR15 - Voice API
#PDR15 - Voice API#PDR15 - Voice API
#PDR15 - Voice API
 
#PDR15 - Developing for Round
#PDR15 - Developing for Round#PDR15 - Developing for Round
#PDR15 - Developing for Round
 
#PDR15 - Designing for Pebble
#PDR15 - Designing for Pebble#PDR15 - Designing for Pebble
#PDR15 - Designing for Pebble
 
#PDR15 Kick-Off
#PDR15 Kick-Off#PDR15 Kick-Off
#PDR15 Kick-Off
 
Pebble Slate Workshop
Pebble Slate WorkshopPebble Slate Workshop
Pebble Slate Workshop
 
Overlay & Libraries | Pebble Meetup Oct. 2014
Overlay & Libraries | Pebble Meetup Oct. 2014Overlay & Libraries | Pebble Meetup Oct. 2014
Overlay & Libraries | Pebble Meetup Oct. 2014
 
Connecting Pebble to the World
Connecting Pebble to the WorldConnecting Pebble to the World
Connecting Pebble to the World
 
Guest Presentation - Strap | Pebble Developer Retreat 2014
Guest Presentation - Strap | Pebble Developer Retreat 2014Guest Presentation - Strap | Pebble Developer Retreat 2014
Guest Presentation - Strap | Pebble Developer Retreat 2014
 
Battery Life | Pebble Developer Retreat 2014
Battery Life | Pebble Developer Retreat 2014Battery Life | Pebble Developer Retreat 2014
Battery Life | Pebble Developer Retreat 2014
 
Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014
Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014
Thomas Sarlandie Kickoff Talk | Pebble Developer Retreat 2014
 
Advanced Techniques: Size | Pebble Developer Retreat 2014
Advanced Techniques: Size | Pebble Developer Retreat 2014Advanced Techniques: Size | Pebble Developer Retreat 2014
Advanced Techniques: Size | Pebble Developer Retreat 2014
 
Advanced Techniques: Graphics | Pebble Developer Retreat 2014
Advanced Techniques: Graphics | Pebble Developer Retreat 2014Advanced Techniques: Graphics | Pebble Developer Retreat 2014
Advanced Techniques: Graphics | Pebble Developer Retreat 2014
 
Pebble wearables devcon
Pebble wearables devconPebble wearables devcon
Pebble wearables devcon
 
Announcing Pebble SDK 2.0
Announcing Pebble SDK 2.0Announcing Pebble SDK 2.0
Announcing Pebble SDK 2.0
 

Recently uploaded

Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
Bluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdfBluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdfngoud9212
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Neo4j
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsAndrey Dotsenko
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraDeakin University
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024BookNet Canada
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 

Recently uploaded (20)

Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
Bluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdfBluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdf
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024
 
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptxVulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning era
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 

#PDR15 Creating Pebble Apps for Aplite, Basalt, and Chalk

  • 1. 2015 Pebble Developer Retreat Creating Pebble Apps for Aplite, Basalt, and Chalk Kevin Conley, Firmware Engineer
  • 2. Why Target Multiple Platforms?
  • 4. Continuity 1. User installs your app on an older platform 2. User upgrades to a new Pebble 3. User already has the most recent version of your app in their locker :)
  • 7. Agenda • Runtime Platforms vs. SDK Versions • Colors • Display Shapes • SDK Compatibility
  • 9. “Runtime Platform” • Set of runtime attributes and capabilities • Does NOT refer to a single watch hardware model
  • 10. Aplite 2.x ✅ Pebble Classic Pebble Steel OS Compatibility • 2.x is legacy • 3.x for Aplite coming soon!
  • 11. Aplite Basalt 2.x ✅ 3.0 ❌ ✅ Pebble Time Pebble Time Steel OS Compatibility
  • 12. Aplite Basalt Chalk 2.x ✅ 3.0 ❌ ✅ 3.6 ❌ ✅ Pebble Time Round OS Compatibility
  • 13. Aplite Basalt Chalk CPU 24k
 ARM Cortex M3 64k ARM Cortex M4 Resolution 144x168px
 (Rectangular) 180x180px (Circular) Color Black & White 64 Colors SmartStrap ❌ ✅ Mic ❌ ✅ Hardware Features
  • 14. Aplite, Basalt, and Chalk are runtime platforms, not SDK versions.
  • 15. Aplite Basalt Chalk 2.x ✅ 3.0 ❌ ✅ 3.6 ❌ ✅ 3.x ✅ Unified 3.x SDK later this year OS Compatibility
  • 16. runs on 2.x 3.x Aplite Basalt 2.x Aplite ✅ ✅ 3.x Basalt ❌ ✅ compiledagainst 2.x Aplite runs on 3.x Basalt SDK Compatibility
  • 17. runs on 2.x 3.x Aplite Aplite Basalt Chalk 2.x Aplite ✅ ✅ ✅ ❌ 3.x Aplite ❌ ✅ ❌ ❌ Basalt ❌ ❌ ✅ ❌ Chalk ❌ ❌ ❌ ✅ compiledagainst 3.x apps are compiled per platform SDK Compatibility
  • 19. Colors • Aplite •Black and white • Basalt and Chalk •64 colors •Pebble color picker tool: • https://developer.getpebble.com/more/color-picker •Download color palettes for Photoshop, GIMP, ImageMagick • https://developer.getpebble.com/guides/pebble-apps/display- and-animations/intro-to-colors/#color-palettes
  • 20. Open-Source Dithering Library • Created by Mathew Reiss • Display approximate colors beyond provided color palette • https://github.com/mathewreiss/dithering Aplite: shades of gray Basalt/Chalk: > 300 colors
  • 24. Organize Code Using Color Macros #define PBL_IF_COLOR_ELSE(if_true, if_false) #define PBL_IF_BW_ELSE(if_true, if_false) Returns if_true on watches that support color and if_false otherwise Returns if_true on watches that only support black & white and if_false otherwise
  • 25. Organize Code Using Color Defines #define PBL_COLOR #define PBL_BW Defined on watches that support color and undefined otherwise Defined on watches that only support black & white and undefined otherwise
  • 26. Color-Specific Resources "resources": {
 "media": [
 {
 "type": "png",
 "name": "MY_IMAGE",
 "file": "images/image.png"
 }
 ]
 }
 appinfo.json: resources/ images/ image~bw.png image~color.png image~bw.png image~color.png
  • 27. WatchInfoColor GColor text_foreground_color, text_background_color; switch(watch_info_get_color()) {
 case WATCH_INFO_COLOR_TIME_STEEL_GOLD:
 // White on red theme text_foreground_color = GColorWhite; text_background_color = GColorRed;
 break;
 case WATCH_INFO_COLOR_TIME_ROUND_BLACK_20:
 // White on black theme
 text_foreground_color = GColorWhite; text_background_color = GColorBlack;
 break;
 /* Other cases... */ 
 } text_layer_set_text_color(s_label_layer, text_foreground_color);
 text_layer_set_background_color(s_label_layer, text_background_color); • Customize your app’s UI using the color of the Pebble watch
  • 29. Display Shapes • Round has 7% more visible pixels than rectangular Rectangular (144 x 168) Round (visible) Round (total) (180 x 180) (0, 0)
  • 30. Calculate Position/Size as a Function of Other Layers const Layer *window_layer = window_get_root_layer(window); const GRect text_frame = GRect(0, 72, 144, 20); const TextLayer *text_layer = text_layer_create(text_frame); text_layer_set_text(text_layer, "Hello world!"); text_layer_set_text_alignment(text_layer, GTextAlignmentCenter); layer_add_child(window_layer, text_layer_get_layer(text_layer));
  • 31. Calculate Position/Size as a Function of Other Layers const Layer *window_layer = window_get_root_layer(window); const GRect text_frame = GRect(0, 72, 144, 20); const TextLayer *text_layer = text_layer_create(text_frame); text_layer_set_text(text_layer, "Hello world!"); text_layer_set_text_alignment(text_layer, GTextAlignmentCenter); layer_add_child(window_layer, text_layer_get_layer(text_layer));
  • 32. Calculate Position/Size as a Function of Other Layers const Layer *window_layer = window_get_root_layer(window); const GRect text_frame = GRect(0, 72, 144, 20); const TextLayer *text_layer = text_layer_create(text_frame); text_layer_set_text(text_layer, "Hello world!"); text_layer_set_text_alignment(text_layer, GTextAlignmentCenter); layer_add_child(window_layer, text_layer_get_layer(text_layer));
  • 33. Calculate Position/Size as a Function of Other Layers const Layer *window_layer = window_get_root_layer(window); const GRect window_bounds = layer_get_bounds(window_layer); const int16_t text_height = 20; const int16_t text_frame_y = (window_bounds.size.h - text_height) / 2; const GRect text_frame = (GRect) { .origin = GPoint(0, text_frame_y), .size = GSize(window_bounds.size.w, text_height) }; const TextLayer *text_layer = text_layer_create(text_frame); text_layer_set_text(text_layer, "Hello world!"); text_layer_set_text_alignment(text_layer, GTextAlignmentCenter); layer_add_child(window_layer, text_layer_get_layer(text_layer));
  • 34. void grect_align(GRect *rect, const GRect *inside_rect, const GAlign alignment, const bool clip); GAlignCenter clip = false rect inside_rect Align Rectangles Within Other Rectangles Using grect_align() inside_rect GAlignTop clip = true rect
  • 35. typedef enum GAlign {
 GAlignCenter,
 GAlignTopLeft,
 GAlignTopRight,
 GAlignTop,
 GAlignLeft,
 GAlignBottom,
 GAlignRight,
 GAlignBottomRight,
 GAlignBottomLeft
 } GAlign; GAlignBottomRight GAlignRight GAlignTopRight GAlignBottom GAlignCenter GAlignTop GAlignBottomLeft GAlignLeft GAlignTopLeft
  • 36. const GRect a = grect_inset(rect, GEdgeInsets(16)); // all sides const GRect b = grect_inset(rect, GEdgeInsets(25, 16)); // top & bottom, right & left const GRect c = grect_inset(rect, GEdgeInsets(25, 16, 10)); // top, right & left, bottom const GRect d = grect_inset(rect, GEdgeInsets(25, -20, 10, 16)); // top, right, bottom, left a b c d 16px 16px 25px 25px 25px 25px 10px 10px 16px 16px 16px 16px16px 16px 16px 20px Inset Rectangles Using grect_inset() and GEdgeInsets()
  • 37. rect GPoint grect_center_point(const GRect *rect); result Find the Center of Rectangles Using grect_center_point()
  • 38. • Use PBL_IF_[ROUND | RECT]_ELSE() macros to choose values or simple expressions based on the display shape • Similar to PBL_IF_[COLOR | BW]_ELSE() Organize Code Using Display Shape Macros/Defines const uint16_t area = PBL_IF_ROUND_ELSE(PI * (width * width / 4), (width * height));
  • 39. • For multiple lines, choose code using PBL_[ROUND | RECT] defines #if defined(PBL_ROUND)
 const GPoint center_point = grect_center_point(&rect);
 graphics_fill_circle(ctx, center_point, radius);
 #else const uint16_t corner_radius = 0;
 graphics_fill_rect(ctx, rect, corner_radius, GCornerNone);
 #endif Organize Code Using Display Shape Macros/Defines
  • 40. • For > 5 lines, break code into functions with _rect/_round suffixes • If the functions share the same arguments, you can simplify calling them by using the PBL_IF_[ROUND | RECT]_ELSE() macro • Otherwise, use the PBL_[ROUND | RECT] defines: Organize Code Using Display Shape Macros/Defines PBL_IF_RECT_ELSE(function_rect, function_round)(arg1, arg2, ...); #if defined(PBL_RECT)
 function_rect(arg1);
 #else
 function_round(arg1, arg2);
 #endif
  • 41. • For > 2 display-specific functions, break into separate _rect/_round files • Use wrapper file to choose appropriate implementation using display shape defines/macros • Alternatively, if the files share a common API: • (also requires ifdef’ing out implementations) Organize Code Using Display Shape Macros/Defines // main.c #if defined(PBL_RECT)
 #include “file_rect.h"
 #else
 #include “file_round.h"
 #endif src/ file_rect.c file_rect.h file_round.c file_round.h file.c file.h main.c
  • 42. Display-Specific Resources "resources": {
 "media": [
 {
 "type": "png",
 "name": "MY_IMAGE",
 "file": "images/image.png"
 }
 ]
 }
 resources/ images/ image~rect.png image~color~round.png appinfo.json: image~rect.png image~color~round.png • Most-specific resource will be used • Ambiguity will result in compiler error
  • 43. Two-Pixel Margin on Round Displays • Extend background colors to all outer edges • Avoid thin rings around the edge of the display • Manufacturing variations may result in off-center appearance • Instead, use thick rings or significantly inset from the edge
  • 44. Platform-Specific Designs “Caltrain” by Katharine Berry: https://github.com/Katharine/pebble-caltrain/ Rectangular Round
  • 46. Status Bar • For SDK 2.x, the status bar appears by default and insets the window from the top unless you use: window_set_fullscreen(window, true); • For SDK 3.x, the status bar is a UI component you must create, configure, and add to the layer hierarchy yourself: static StatusBarLayer *s_status_bar;
 s_status_bar = status_bar_layer_create();
 status_bar_layer_set_separator_mode(s_status_bar, StatusBarLayerSeparatorModeDotted);
 status_bar_layer_set_colors(s_status_bar, GColorBlack, GColorWhite);
 const Layer *status_bar_layer = status_bar_layer_get_layer(s_status_bar);
 layer_add_child(window_root_layer, status_bar_layer);
  • 49. s_status_bar = status_bar_layer_create();
 GRect status_bar_rect = window_bounds;
 status_bar_rect.size.h = STATUS_BAR_LAYER_HEIGHT;
 layer_set_frame( status_bar_layer_get_layer(s_status_bar),
 status_bar_rect);
 
 // top/bottom: statusbar, left/right: 0 const GEdgeInsets insets = GEdgeInsets( STATUS_BAR_LAYER_HEIGHT, 0); GRect menu_layer_rect = grect_inset( window_bounds, insets); Status Bar
  • 52. s_action_bar = action_bar_layer_create();
 action_bar_layer_add_to_window( s_action_bar, window);
 
 // top: statusbar, right: actionbar, bottom/left:0 const GEdgeInsets insets = GEdgeInsets(
 STATUS_BAR_LAYER_HEIGHT, ACTION_BAR_WIDTH, 0, 0);
 GRect content_rect = grect_inset( window_bounds, insets); ActionBar
  • 55. // default on Chalk menu_layer_set_center_focused(menu_layer, true); static int16_t get_cell_height_callback(MenuLayer *menu_layer, MenuIndex *cell_index,
 void *callback_context) {
 #if defined(PBL_ROUND) // when center_focused, MenuLayer can handle cell heights // that change based on the selection status if (menu_layer_is_index_selected(menu_layer, cell_index)) {
 return MENU_CELL_ROUND_FOCUSED_TALL_CELL_HEIGHT;
 } else {
 return MENU_CELL_ROUND_UNFOCUSED_SHORT_CELL_HEIGHT;
 } #else return MENU_CELL_BASIC_CELL_HEIGHT; #endif
 }
 MenuLayer
  • 56. TextLayer • To maximize content visible on round displays, enable text flow and paging with an optional inset (for padding): text_layer_enable_screen_text_flow_and_paging(s_text_layer, 8);
  • 57. TextLayer • Text flow on a round display without pagination looks weird…
  • 58. WatchInfo • Inspect what watch the app is running on • Useful e.g. if you want to align visual elements with buttons • Next to different screen coordinates for different watches GRect layer_frame = GRectZero;
 switch(watch_info_get_model()) {
 case WATCH_INFO_MODEL_PEBBLE_STEEL:
 layer_frame = GRect(0, 64, 144, 44);
 break;
 case WATCH_INFO_MODEL_PEBBLE_TIME:
 layer_frame = GRect(0, 58, 144, 56);
 break;
 /* Other cases */
 }
  • 60. Platform Defines • Feature/capability defines, like PBL_COLOR, PBL_ROUND, etc. should be used in favor of these • Exception: CPU/memory-specific code #define PBL_PLATFORM_APLITE #define PBL_PLATFORM_BASALT #define PBL_PLATFORM_CHALK
  • 61. Platform Specific Resources • Can also use ~aplite, ~basalt, and ~chalk suffixes • But overall, in most cases it’s best to use ~rect, ~round, ~bw, ~color suffixes instead "resources": {
 "media": [
 {
 "type": "png",
 "name": "MY_IMAGE",
 "file": “images/image.png”, "targetPlatforms": [ "basalt" ]
 }
 ]
 }

  • 62. GPoint shim_gpoint_from_polar(GRect rect, int32_t angle) {
 #if defined(PBL_SDK_2) const GPoint center = GPoint(rect.origin.x + (rect.size.w / 2), rect.origin.y + (rect.size.h / 2)); const int16_t radius = MIN(rect.size.w, rect.size.h) / 2;
 return GPoint((sin_lookup(angle) * radius / TRIG_MAX_RATIO) + center.x,
 (-cos_lookup(angle) * radius / TRIG_MAX_RATIO) + center.y);
 #else
 return gpoint_from_polar(rect, GOvalScaleModeFitCircle, angle);
 #endif
 } Shims • Newer SDK 3.x functions do not exist in SDK 2.x • You can create shims for them using PBL_SDK_2/3 defines:
  • 63. PebbleKit JS API Availability • Some PebbleKit JS APIs don’t exist on Pebble Classic mobile apps, • Check if they are available and fail gracefully if necessary if (Pebble.getActiveWatchInfo) { // API is available; use it! var info = Pebble.getActiveWatchInfo(); console.log('Pebble model: ' + info.model); } else { // Gracefully handle unavailable API }
  • 64. Check Return Values • APIs may return NULL if: • Unsupported by platform • Permissions not given • Phone disconnected • Check the return value before using it and fail gracefully if necessary const DictationSession *session = dictation_session_create(0, callback, callback_context); if (session) { /* Success! */ dictation_session_start(session); } else { /* DictationSession is unsupported, need to fail gracefully here! */ }
  • 65. Marcel: Friday 1 pm Starting with Chalk, you need to compile with PebbleKit iOS 3.0 Since PebbleOS 3.0, you need to compile with PebbleKit Android 3.0 AndroidiOS Mobile App Compatibility
  • 66. Running Multiple Emulators at Once • pebble install --emulator=aplite && pebble install --emulator=basalt && pebble install —-emulator=chalk
  • 67. Automating Taking Screenshots • pebble screenshot --emulator=aplite && pebble screenshot --emulator=basalt && pebble screenshot —-emulator=chalk
  • 68. Recap • Runtime Platforms vs. SDK Versions • Colors • Display Shapes • SDK Compatibility