SlideShare ist ein Scribd-Unternehmen logo
1 von 93
Downloaden Sie, um offline zu lesen
@sarbogast @eloudsa#Devoxx #smartvoxx
Smartwatch Landscape
Sébastien Arbogast
Said Eloudrhiri
#Devoxx #smartvoxx @sarbogast @eloudsa
• Who owns a smartwatch?
• Who is an Android developer?
• Who is an iOS developer?
• Who is a Pebble developer?
• Who is a Rolex developer?
• Who has already written a smartwatch app?
• Who is a member of the Night’s Watch?
Survey
#Devoxx #smartvoxx @sarbogast @eloudsa
Sébastien Arbogast

@sarbogast
• Java developer for 10 years
• iOS developers for 5 years (developer of the first Devoxx schedule
app)
• Pebble developer for 2 years
• Owner of TikTok Lunatik with iPod Nano
• VP of engineering for Take Eat Easy
#Devoxx #smartvoxx @sarbogast @eloudsa
Said Eloudrhiri

@eloudsa
• Developer since 1992
• Agile Coach and trainer
• Devoxx4Kids helper (Sphero, MindStorms, CodeCombat)
• Side Projects: mobile development
• Husband and father of Nora, Rayane and Djenna
#Devoxx #smartvoxx @sarbogast @eloudsa
Disclaimer
We are not related to Google,Apple or Pebble.
We are just curious developers sharing our experience.
Materials used in this presentation remains the property of their
owners.
Any questions?
#Devoxx #smartvoxx @sarbogast @eloudsa
Why develop for smartwatches?
#Devoxx #smartvoxx @sarbogast @eloudsa
Glanceable
#Devoxx #smartvoxx @sarbogast @eloudsa
Sensors
#Devoxx #smartvoxx @sarbogast @eloudsa
Internet of Things
#Devoxx #smartvoxx @sarbogast @eloudsa
Notification-driven
#Devoxx #smartvoxx @sarbogast @eloudsa
Small screen
#Devoxx #smartvoxx @sarbogast @eloudsa
Interactions
#Devoxx #smartvoxx @sarbogast @eloudsa
Personal use
#Devoxx #smartvoxx @sarbogast @eloudsa
Landscape
Apple 

Watch
Android 

Wear
Pebble Tizen
#Devoxx #smartvoxx @sarbogast @eloudsa
IDE
#Devoxx #smartvoxx @sarbogast @eloudsa
XCode
#Devoxx #smartvoxx @sarbogast @eloudsa
Android Studio
#Devoxx #smartvoxx @sarbogast @eloudsa
Debugging with Emulator
USB
Bridge
adb -d forward tcp:5601 tcp:5601
#Devoxx #smartvoxx @sarbogast @eloudsa
Android Studio or Eclipse?
• Android Development Tools (ADT)
• Andmore - Eclipse Android Tooling (Incubation Project)
https://projects.eclipse.org/projects/tools.andmore
http://developer.android.com/tools/sdk/eclipse-adt.html
#Devoxx #smartvoxx @sarbogast @eloudsa
CloudPebble
#Devoxx #smartvoxx @sarbogast @eloudsa
Development cycle
#Devoxx #smartvoxx @sarbogast @eloudsa
Apple Watch
• Select the Watch App scheme
• Select your emulator configuration
• Run
• You can debug both emulators at the same time
#Devoxx #smartvoxx @sarbogast @eloudsa
Android
• Install Android Wear on your Phone
• Create Wear emulator
• Run Wear emulator
• Open ports to let emulator communicate with physical phone
• Pair the Phone and the Wear Emulator
• Deploy application on Wear and/or Mobile
#Devoxx #smartvoxx @sarbogast @eloudsa
Pebble
• Connect Pebble app with CloudPebble
• Enable Developer Connections
• Run in CloudPebble
#Devoxx #smartvoxx @sarbogast @eloudsa
Available Watches
#Devoxx #smartvoxx @sarbogast @eloudsa
Apple Watch
272x340312x390
#Devoxx #smartvoxx @sarbogast @eloudsa
Android Wear
#Devoxx #smartvoxx @sarbogast @eloudsa
Square Round Round Chin
Form factors
#Devoxx #smartvoxx @sarbogast @eloudsa
Pebble
Classic Steel Time Time Steel Time Round
144x168
#Devoxx #smartvoxx @sarbogast @eloudsa
Compatibility
• Android Wear:Android phones + iPhone (with some
limitations)
• Apple Watch: iPhones only
• Pebble:Android phones + iPhones (with SDKs to integrate
with apps on both platforms)
#Devoxx #smartvoxx @sarbogast @eloudsa
Inputs and Outputs
#Devoxx #smartvoxx @sarbogast @eloudsa
Apple Watch
• Gestures
• Force Touch
• Digital Crown
• Side Button
• Taptic Engine
• Microphone and speaker
• Accelerometer
• Heart rate monitor
• (NFC)
#Devoxx #smartvoxx @sarbogast @eloudsa
• Touch screen
• Shake moves
• Button
• Ambiant mode
• Microphone (Voice control)
• Heart rate monitor (PPG)
• Gyro,Accelerometer, Compass
• Barometer
• NFC
• GPS
Android Wear
#Devoxx #smartvoxx @sarbogast @eloudsa
Pebble
• Non-touch (color) e-ink screen
• 4 buttons
• Vibration
• Microphone
#Devoxx #smartvoxx @sarbogast @eloudsa
Design Principles
#Devoxx #smartvoxx @sarbogast @eloudsa
Human Interface Guidelines
• Lightweight interactions
• Holistic design
• Personal communication
#Devoxx #smartvoxx @sarbogast @eloudsa
Creative vision for Android Wear
• Suggest: Context Stream
• Demand: Cue Cards
• Glanceable
• Zero or Low interaction
Beam me up!
#Devoxx #smartvoxx @sarbogast @eloudsa
Guidelines and patterns
• Cards
• List options with Menus
• Execute actions with action bars
• Prompting User Action on the Phone
• Show Time and Data with the Status Bar
• Show Alerts and Get Decisions with Modal
Windows
• UsingVibrations and Haptic Feedback
• Handling Connection Problems
#Devoxx #smartvoxx @sarbogast @eloudsa
Different kinds of apps
#Devoxx #smartvoxx @sarbogast @eloudsa
Apple Watch
• Apps
• Notifications
• Glances
• Complications
#Devoxx #smartvoxx @sarbogast @eloudsa
Android Wear
• Full-screen apps
• Notifications
• Custom notifications
• Watch face
4
“If you don't have a Rolex by the time you
reach 50,
then you have clearly failed in your life.”
Jacques Séguéla
#Devoxx #smartvoxx @sarbogast @eloudsa
Pebble
• Apps
• Timeline integration
#Devoxx #smartvoxx @sarbogast @eloudsa
Languages
• Apple Watch: Swift or Objective-C
• Android Wear: Java (or Kotlin or Groovy or …)
• Pebble: C or Javascript (Pebble.js)
#Devoxx #smartvoxx @sarbogast @eloudsa
self.table.setNumberOfRows(self.schedules!.count, withRowType: "schedule")
for (index,schedule) in self.schedules!.enumerate() {
if let row = self.table.rowControllerAtIndex(index)
as? ScheduleRowController {
row.label.setText(
schedule.title!.stringByReplacingOccurrencesOfString(
NSLocalizedString("Schedule for ", comment:""),
withString: ""
)
)
}
}
Apple Watch
Demo
#Devoxx #smartvoxx @sarbogast @eloudsa
#Devoxx #smartvoxx @sarbogast @eloudsa
Layout: Round / Square
#Devoxx #smartvoxx @sarbogast @eloudsa
<?xml version="1.0" encoding="utf-8"?>

<android.support.wearable.view.WatchViewStub

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:id="@+id/watch_talk_stub"

android:layout_width="match_parent"

android:layout_height="match_parent"

app:rectLayout="@layout/talk_rect_fragment"

app:roundLayout="@layout/talk_round_fragment"

tools:context=".TalkActivity"

tools:deviceIds="wear">



</android.support.wearable.view.WatchViewStub>
Layout: Main
res/layout/talk_fragment.xml
#Devoxx #smartvoxx @sarbogast @eloudsa
<?xml version="1.0" encoding="utf-8"?>



<RelativeLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:paddingTop="15dp">



<TextView

android:id="@+id/title"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

Sub-layout: Square
res/layout/talk_rect_fragment.xml
#Devoxx #smartvoxx @sarbogast @eloudsa
<?xml version="1.0" encoding="utf-8"?>



<android.support.wearable.view.BoxInsetLayout 

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:padding="15dp">



<RelativeLayout

android:layout_width="match_parent"

android:layout_height="match_parent">



<TextView

android:id="@+id/title"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

Sub-layout: Round
res/layout/talk_round_fragment.xml
#Devoxx #smartvoxx @sarbogast @eloudsa
CloudPebble UI editor
#Devoxx #smartvoxx @sarbogast @eloudsa
static void main_window_load(Window *window) {

// Get information about the Window

Layer *window_layer = window_get_root_layer(window);

GRect bounds = layer_get_bounds(window_layer);



// Create the TextLayer with specific bounds

s_time_layer = text_layer_create(

GRect(0, PBL_IF_ROUND_ELSE(58, 52), bounds.size.w, 50));



// Improve the layout to be more like a watchface

text_layer_set_background_color(s_time_layer, GColorClear);

text_layer_set_text_color(s_time_layer, GColorBlack);

text_layer_set_text(s_time_layer, "00:00");

text_layer_set_font(s_time_layer, fonts_get_system_font(FONT_KEY_BITHAM_42_BOLD));

text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter);



// Add it as a child layer to the Window's root layer

layer_add_child(window_layer, text_layer_get_layer(s_time_layer));

}
Pebble
#Devoxx #smartvoxx @sarbogast @eloudsa
Internet connectivity
#Devoxx #smartvoxx @sarbogast @eloudsa
Apple Watch (NSURLSession)
Apple 

Watch
Apple
Watch app
Internet
#Devoxx #smartvoxx @sarbogast @eloudsa
func loadSchedulesForConference(conference:String, callback: ([Schedule]) -> (Void)) {
//Configure session and disable caching as it fails
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.requestCachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData
let session = NSURLSession(configuration: configuration)
//Call API
let schedulesURL = NSURL(string: "http://cfp.devoxx.be/api/conferences/(conference)/schedules/")!
let task = session.dataTaskWithURL(schedulesURL) { (data: NSData?, response:NSURLResponse?,
error:NSError?) -> Void in
//process data
}
task.resume()
}
Apple Watch
#Devoxx #smartvoxx @sarbogast @eloudsa
Internet connectivity
Fallback solution when Bluetooth not
available.
Unable to connect on remote servers.
#Devoxx #smartvoxx @sarbogast @eloudsa
/**

* Created by eloudsa on 30/10/15.

*/

public interface DevoxxApi {





@GET("/conferences/{conference}/schedules")

void getSchedules(@Path("conference") String conference, Callback<Schedules> callback);



@GET("/conferences/{conference}/schedules/{day}")

void getSchedule(@Path("conference") String conference, @Path("day") String day, Callback<SlotList> callback);



@GET("/conferences/{conference}/talks/{talkid}")

void getTalk(@Path("conference") String conference, @Path("talkid") String uuid, Callback<Talk> callback);



@GET("/conferences/{conference}/speakers/{uuid}")

void getSpeaker(@Path("conference") String conference, @Path("uuid") String uuid, Callback<Speaker> callback);



}

Android Wear: Endpoints
Retrofit REST API client from Square
#Devoxx #smartvoxx @sarbogast @eloudsa
@Override

public void onCreate() {

super.onCreate();



…

// prepare the REST build

mRestAdapter = new RestAdapter.Builder()

.setEndpoint(getResources().getString(R.string.devoxx_rest_api))

.build();



mMethods = mRestAdapter.create(DevoxxApi.class);

mConferenceName = getResources().getString(R.string.devoxx_conference);

}
Android Wear: Setup
#Devoxx #smartvoxx @sarbogast @eloudsa
// Retrieve schedules from Devoxx

private void retrieveSchedules() {

// retrieve the schedules list from the server

Callback callback = new Callback() {

@Override

public void success(Object o, Response response) {

// retrieve schedule from REST

Schedules scheduleList = (Schedules) o;

if (scheduleList == null) {

Log.d(TAG, "No schedules!");

return;

}



sendSchedules(scheduleList.getLinks());

}



@Override

public void failure(RetrofitError retrofitError) {

Log.d(TAG, retrofitError.getMessage());

}

};

mMethods.getSchedules(mConferenceName, callback);

}
Android Wear: Get Shedules
1
2
3
#Devoxx #smartvoxx @sarbogast @eloudsa
Pebble
Pebble app
Pebble App
JS module
Internet
AppMessage
XHR
#Devoxx #smartvoxx @sarbogast @eloudsa
static bool load_site_list() {

if(accessToken && sizeof(accessToken) > 0) {

DictionaryIterator *iter;

app_message_outbox_begin(&iter);

if (iter == NULL) {

APP_LOG(APP_LOG_LEVEL_DEBUG, "null iter");

return false;

}



Tuplet message_type_tuple = TupletInteger(MESSAGE_TYPE, LOAD_SITE_LIST);

dict_write_tuplet(iter, &message_type_tuple);

Tuplet access_token_tuple = TupletCString(ACCESS_TOKEN, accessToken);

dict_write_tuplet(iter, &access_token_tuple);

Tuplet refresh_token_tuple = TupletCString(REFRESH_TOKEN, refreshToken);

dict_write_tuplet(iter, &refresh_token_tuple);

dict_write_end(iter);



app_message_outbox_send();



return true;

} else {

return false;

}

}
Pebble to phone
#Devoxx #smartvoxx @sarbogast @eloudsa
function loadSiteList(accessToken, refreshToken) {

console.log("Loading site list for access token " + accessToken);

var response;

var req = new XMLHttpRequest();

// build the GET request

req.open('GET', "https://api.myfox.me:443/v2/client/site/items?access_token=" + accessToken, true);

req.onload = function(e) {

if (req.readyState == 4) {

// 200 - HTTP OK

if(req.status == 200) {

console.log(req.responseText);

response = JSON.parse(req.responseText);

var siteList;

if (response.status === 'OK') {

siteList = response.payload.items;



var msg = {};

msg.messageType = MessageType.SITE_LIST;

for(var i = 0; i < siteList.length; i++){

var site = siteList[i];

msg['' + site.siteId] = site.label;

}

console.log("Sending response back to Pebble: " + JSON.stringify(msg));

Pebble.sendAppMessage(msg);

} else {

console.log("Status not OK");

Pebble.sendAppMessage({messageType:MessageType.ERROR, errorMessage:"Could not load list of sites. Please try again later."});

}

} else if(req.status == 401 && refreshToken){

getNewAccessToken(refreshToken, loadSiteList);

} else {

console.log("Request returned error code " + req.status.toString());

Pebble.sendAppMessage({messageType:MessageType.ERROR});

}

}

};

req.send(null);

}
Phone to internet and back
#Devoxx #smartvoxx @sarbogast @eloudsa
Phone communication
#Devoxx #smartvoxx @sarbogast @eloudsa
Watch Connectivity
Apple 

Watch
update application context
send message
transfer user info
transfer file
replace
live
queue
big data
#Devoxx #smartvoxx @sarbogast @eloudsa
if WCSession.isSupported() {
session = WCSession.defaultSession()
session?.delegate = self
session?.activateSession()
if let session = self.session where session.reachable {
session.sendMessage(["talkSlot" : talkSlotMessage as NSDictionary],
replyHandler: { (reply:[String : AnyObject]) -> Void in
},
errorHandler: { (error:NSError) -> Void in
print(error)
}
)
} else {
session?.transferUserInfo(["talkSlot" : talkSlotMessage as NSDictionary])
}
}
Watch Connectivity
#Devoxx #smartvoxx @sarbogast @eloudsa
Google API Client
Device
Google Play
Services
Your App
Google API Client
Google Play
services library
Message API
Data API
Node API
#Devoxx #smartvoxx @sarbogast @eloudsa
public class ScheduleActivity extends Activity {
// Google Play Services

private GoogleApiClient mApiClient;

…	
@Override

protected void onStart() {

super.onStart();



mApiClient = new GoogleApiClient.Builder(this)

.addApi(Wearable.API)

.addConnectionCallbacks(this)

.build();



mApiClient.connect();

}





@Override

protected void onStop() {

if ((mApiClient != null) && (mApiClient.isConnected())) {

Wearable.DataApi.removeListener(mApiClient, this);

mApiClient.disconnect();

}



super.onStop();

}
Google API Client
1
2
3
#Devoxx #smartvoxx @sarbogast @eloudsa
Connected nodes
Phone Watch
Node Node
Message API
WearableListenerService
onMessageReceived()
MessageApi
sendMessage()
#Devoxx #smartvoxx @sarbogast @eloudsa
public class ScheduleActivity extends Activity {
…	
private void sendMessage(final String path, final String message) {

new Thread(new Runnable() {

@Override

public void run() {

// broadcast the message to all connected devices

final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(mApiClient).await();

for (Node node : nodes.getNodes()) {

Wearable.MessageApi.sendMessage(mApiClient, node.getId(), path, message.getBytes()).await();

}

}

}).start();

}


Message API: Send Message
#Devoxx #smartvoxx @sarbogast @eloudsa
public class WearService extends WearableListenerService {
…	
@Override

public void onMessageReceived(MessageEvent messageEvent) {



// Processing the incoming message

String path = messageEvent.getPath();

String data = new String(messageEvent.getData());



if (path.equalsIgnoreCase(Constants.SCHEDULES_PATH)) {

retrieveSchedules();

return;

}
…
Message API: Message Received
#Devoxx #smartvoxx @sarbogast @eloudsa
Data Synchronisation
Phone Watch
Node Node
Data API.putDataItem()
Wearable.DataApi
onDataChanged()
DataApi.DataListener
#Devoxx #smartvoxx @sarbogast @eloudsa


// send Schedules to the watch

private void sendSchedules(List<Link> schedules) {

final PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(Constants.SCHEDULES_PATH);



ArrayList<DataMap> schedulesDataMap = new ArrayList<>();



// process each schedule

for (Link schedule : schedules) {



DataMap scheduleDataMap = new DataMap();



// process and push schedule's data

scheduleDataMap.putString("day", Utils.getLastPartUrl(schedule.getHref()));

scheduleDataMap.putString("title", schedule.getTitle());



schedulesDataMap.add(scheduleDataMap);

}



// store the list in the datamap to send it to the watch

putDataMapRequest.getDataMap().putDataMapArrayList(Constants.LIST_PATH, schedulesDataMap);



// send the schedules

if (mApiClient.isConnected()) {

Wearable.DataApi.putDataItem(mApiClient, putDataMapRequest.asPutDataRequest());

}

}

Data API: Send Data
1
2
3
4
#Devoxx #smartvoxx @sarbogast @eloudsa
@Override

public void onDataChanged(DataEventBuffer dataEventBuffer) {



for (DataEvent event : dataEventBuffer) {



// Check if list of schedules has changed

if (event.getType() == DataEvent.TYPE_CHANGED && event.getDataItem().getUri().getPath().startsWith(Constants.SCHEDULES_PATH)) {

// get the list of schedules from the incoming data event 

SchedulesListWrapper schedulesListWrapper = new SchedulesListWrapper();

final List<Schedule> schedulesList = schedulesListWrapper.getSchedulesList(event);



runOnUiThread(new Runnable() {

@Override

public void run() {

// hide the progress bar

findViewById(R.id.progressBar).setVisibility(View.GONE);



mListViewAdapter.refresh(schedulesList);

}

});



return;

}

}

}
1
2
3
4
Data API: Data changed
#Devoxx #smartvoxx @sarbogast @eloudsa
Caching
#Devoxx #smartvoxx @sarbogast @eloudsa
private func saveSchedulesFromData(data: NSData, inContext context: NSManagedObjectContext) {
context.performBlockAndWait { () -> Void in
if data.length > 0 {
do {
let schedulesDict = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
if let schedulesDict = schedulesDict as? NSDictionary, schedulesArray = schedulesDict["links"] as? NSArray {
guard let devoxx15 = self.getOrCreateDevoxx15(inContext: context) else { return }
var schedules = [Schedule]()
for scheduleDict in schedulesArray {
let scheduleDict = scheduleDict as? NSDictionary
let schedule = self.getOrCreateScheduleForHref(scheduleDict["href"] as! String, inContext: context)!
schedule.title = scheduleDict["title"] as? String
schedule.href = scheduleDict["href"] as? String
schedule.conference = devoxx15
self.saveContext(context)
schedules.append(schedule)
}
devoxx15.schedules = NSOrderedSet(array: schedules)
self.saveContext(context)
}
} catch let jsonError as NSError {
print(jsonError)
}
}
}
}
Core Data on Apple Watch
Demo
#Devoxx #smartvoxx @sarbogast @eloudsa
#Devoxx #smartvoxx @sarbogast @eloudsa
Wear
Data Item
(Cache)
.getInt()
DataMap
.getDataIetms()
DataApi
wear://path_to_data
1
2
Data caching
MessageApi
sendMessage()
3
4
Demo
#Devoxx #smartvoxx @sarbogast @eloudsa
#Devoxx #smartvoxx @sarbogast @eloudsa
App structure and distribution
#Devoxx #smartvoxx @sarbogast @eloudsa
Apple Watch
• Package the Apple Watch app with the iPhone app
• Release the iPhone app like any other
• Wait for review…
• Wait again…
• Wait some more…
#Devoxx #smartvoxx @sarbogast @eloudsa
Android Wear
#Devoxx #smartvoxx @sarbogast @eloudsa
Prepare the build
• Include permissions required by Wear into Phone (Manifest)
• Use same package name and version number (build.gradle)
#Devoxx #smartvoxx @sarbogast @eloudsa
Generate signed APK
#Devoxx #smartvoxx @sarbogast @eloudsa
Mobile APK embeds Wearable
Mobile App Module
Code
Resources
Wearable App
Wear App Module
Code
Resources
#Devoxx #smartvoxx @sarbogast @eloudsa
Publishing: Select Android Wear
#Devoxx #smartvoxx @sarbogast @eloudsa
Distribution
Companion App
Wearable App
Bluetooth
Companion
App
Play Services
Android Wear
Wearable App
Smartvoxx
#Devoxx #smartvoxx @sarbogast @eloudsa
Pebble
Pebble App
JS module
#Devoxx #smartvoxx @sarbogast @eloudsa
Smartvoxx
• smartvoxx.com
Demo
#Devoxx #smartvoxx @sarbogast @eloudsa
#Devoxx #smartvoxx @sarbogast @eloudsa
Summary
• Huge inequalities in terms of development platform ease-of-
use
• Apple obviously took time to add abstraction layers that make
development more expressive
• Short learning curve on Android Wear compared to Apple
Watch
• Tooling support not up-to-date on Android
• Documentation is not really finished for both platforms
• Not all apps make sense on smartwatches
#Devoxx #smartvoxx @sarbogast @eloudsa
Apps that work on smartwatches
• countdowns and timers
• status checks: what’s the temperature? what’s my next
session? what’s the score of the game?
• remote controls: switch off the light, change the music, open
my hotel room, pay for my shopping
• notification responders: invitation to a meeting -> what’s the
meeting about, somebody sent me a message -> what does it
say?
• data trackers: where am I? how many calories am I burning?
what’s my speed?)
#Devoxx #smartvoxx @sarbogast @eloudsa
Apps that don’t make sense
•  games of any kind
•  any long reading (news, books, etc.)
•  ecommerce
•  video or image viewing
•  anything that requires text input
#Devoxx #smartvoxx @sarbogast @eloudsa
One more thing …
#Devoxx #smartvoxx @sarbogast @eloudsa
Smartvoxx on Github
Available in Black … … and White
http://github.com/smartvoxx

Weitere ähnliche Inhalte

Andere mochten auch

Sergey Ilinsky Presentation Ample Sdk
Sergey Ilinsky Presentation Ample SdkSergey Ilinsky Presentation Ample Sdk
Sergey Ilinsky Presentation Ample SdkAjax Experience 2009
 
Continental Drift And Plate Tectonics Andie
Continental  Drift And  Plate  Tectonics  AndieContinental  Drift And  Plate  Tectonics  Andie
Continental Drift And Plate Tectonics Andiecharsh
 
Signage And Info Centres
Signage And Info CentresSignage And Info Centres
Signage And Info Centresrobyna
 
Leaders and followers ann grand - open university - easst 2014
Leaders and followers   ann grand - open university - easst 2014Leaders and followers   ann grand - open university - easst 2014
Leaders and followers ann grand - open university - easst 2014agrand
 
Creating a Successful Transmedia Project
Creating a Successful Transmedia ProjectCreating a Successful Transmedia Project
Creating a Successful Transmedia ProjectRobert Pratten
 
S4 tarea4 gania
S4 tarea4 ganiaS4 tarea4 gania
S4 tarea4 ganiakeyrin
 
web信息架构与社会化
web信息架构与社会化web信息架构与社会化
web信息架构与社会化tony
 
Participation for Interactive Narratives
Participation for Interactive NarrativesParticipation for Interactive Narratives
Participation for Interactive NarrativesRobert Pratten
 
20110726卑南族
20110726卑南族20110726卑南族
20110726卑南族Jolen Yao
 
Aprender haciendo
Aprender haciendoAprender haciendo
Aprender haciendorolando678
 
技术猪是什么猪
技术猪是什么猪技术猪是什么猪
技术猪是什么猪niceparadise
 
Daftar pembagian tugas presentasi kelompok kelas a b
Daftar pembagian tugas presentasi kelompok kelas a bDaftar pembagian tugas presentasi kelompok kelas a b
Daftar pembagian tugas presentasi kelompok kelas a bDasrieny Pratiwi
 
Network First Open Day presentation
Network First Open Day presentationNetwork First Open Day presentation
Network First Open Day presentationVictoria College
 
Scott Isaacs Presentationajaxexperience (Final)
Scott Isaacs Presentationajaxexperience (Final)Scott Isaacs Presentationajaxexperience (Final)
Scott Isaacs Presentationajaxexperience (Final)Ajax Experience 2009
 
innoveren_met_big_data_jr_helmus
innoveren_met_big_data_jr_helmusinnoveren_met_big_data_jr_helmus
innoveren_met_big_data_jr_helmusJurjen Helmus
 
lifePERX Benefit Brochure
lifePERX Benefit BrochurelifePERX Benefit Brochure
lifePERX Benefit BrochureweBranding
 

Andere mochten auch (20)

Sergey Ilinsky Presentation Ample Sdk
Sergey Ilinsky Presentation Ample SdkSergey Ilinsky Presentation Ample Sdk
Sergey Ilinsky Presentation Ample Sdk
 
Continental Drift And Plate Tectonics Andie
Continental  Drift And  Plate  Tectonics  AndieContinental  Drift And  Plate  Tectonics  Andie
Continental Drift And Plate Tectonics Andie
 
Signage And Info Centres
Signage And Info CentresSignage And Info Centres
Signage And Info Centres
 
Kurikulum 2013 SMA
Kurikulum 2013 SMAKurikulum 2013 SMA
Kurikulum 2013 SMA
 
Leaders and followers ann grand - open university - easst 2014
Leaders and followers   ann grand - open university - easst 2014Leaders and followers   ann grand - open university - easst 2014
Leaders and followers ann grand - open university - easst 2014
 
Creating a Successful Transmedia Project
Creating a Successful Transmedia ProjectCreating a Successful Transmedia Project
Creating a Successful Transmedia Project
 
S4 tarea4 gania
S4 tarea4 ganiaS4 tarea4 gania
S4 tarea4 gania
 
web信息架构与社会化
web信息架构与社会化web信息架构与社会化
web信息架构与社会化
 
Participation for Interactive Narratives
Participation for Interactive NarrativesParticipation for Interactive Narratives
Participation for Interactive Narratives
 
Saving money with MFDs
Saving money with MFDsSaving money with MFDs
Saving money with MFDs
 
20110726卑南族
20110726卑南族20110726卑南族
20110726卑南族
 
Aprender haciendo
Aprender haciendoAprender haciendo
Aprender haciendo
 
技术猪是什么猪
技术猪是什么猪技术猪是什么猪
技术猪是什么猪
 
Kurikulum 2013 SD
Kurikulum 2013 SD Kurikulum 2013 SD
Kurikulum 2013 SD
 
Daftar pembagian tugas presentasi kelompok kelas a b
Daftar pembagian tugas presentasi kelompok kelas a bDaftar pembagian tugas presentasi kelompok kelas a b
Daftar pembagian tugas presentasi kelompok kelas a b
 
Network First Open Day presentation
Network First Open Day presentationNetwork First Open Day presentation
Network First Open Day presentation
 
Gaza project
Gaza projectGaza project
Gaza project
 
Scott Isaacs Presentationajaxexperience (Final)
Scott Isaacs Presentationajaxexperience (Final)Scott Isaacs Presentationajaxexperience (Final)
Scott Isaacs Presentationajaxexperience (Final)
 
innoveren_met_big_data_jr_helmus
innoveren_met_big_data_jr_helmusinnoveren_met_big_data_jr_helmus
innoveren_met_big_data_jr_helmus
 
lifePERX Benefit Brochure
lifePERX Benefit BrochurelifePERX Benefit Brochure
lifePERX Benefit Brochure
 

Ähnlich wie Smartwatch Landscape

Serverless: when functions and GitOps collide
Serverless: when functions and GitOps collideServerless: when functions and GitOps collide
Serverless: when functions and GitOps collideEdward Wilde
 
How to Set Up Mobile Continuous Integration with Real Devices: CloudBees & SO...
How to Set Up Mobile Continuous Integration with Real Devices: CloudBees & SO...How to Set Up Mobile Continuous Integration with Real Devices: CloudBees & SO...
How to Set Up Mobile Continuous Integration with Real Devices: CloudBees & SO...SOASTA
 
Moving to a DevOps mode - easy, hard or just plain terrifying? - Daniel Bryan...
Moving to a DevOps mode - easy, hard or just plain terrifying? - Daniel Bryan...Moving to a DevOps mode - easy, hard or just plain terrifying? - Daniel Bryan...
Moving to a DevOps mode - easy, hard or just plain terrifying? - Daniel Bryan...JAXLondon2014
 
JAX London 2014 "Moving to DevOps Mode: easy, hard or just plain terrifying?"
JAX London 2014 "Moving to DevOps Mode: easy, hard or just plain terrifying?"JAX London 2014 "Moving to DevOps Mode: easy, hard or just plain terrifying?"
JAX London 2014 "Moving to DevOps Mode: easy, hard or just plain terrifying?"Daniel Bryant
 
Philly CocoaHeads 20160414 - Building Your App SDK With Swift
Philly CocoaHeads 20160414 - Building Your App SDK With SwiftPhilly CocoaHeads 20160414 - Building Your App SDK With Swift
Philly CocoaHeads 20160414 - Building Your App SDK With SwiftJordan Yaker
 
iOS apps in Swift
iOS apps in SwiftiOS apps in Swift
iOS apps in SwiftNuno Dias
 
Nebraska Trainer's Institute eLearning Presentaiotn
Nebraska Trainer's Institute eLearning PresentaiotnNebraska Trainer's Institute eLearning Presentaiotn
Nebraska Trainer's Institute eLearning Presentaiotneaselsolutions
 
iPhone Camp Birmingham (Bham) - Intro To iPhone Development
iPhone Camp Birmingham (Bham) - Intro To iPhone DevelopmentiPhone Camp Birmingham (Bham) - Intro To iPhone Development
iPhone Camp Birmingham (Bham) - Intro To iPhone Developmentandriajensen
 
SQL Server 2016 JSON
SQL Server 2016 JSONSQL Server 2016 JSON
SQL Server 2016 JSONDavide Mauri
 
Fast Track to Adobe Captivate
Fast Track to Adobe CaptivateFast Track to Adobe Captivate
Fast Track to Adobe Captivateeaselsolutions
 
Intro to DefectDojo at OWASP Switzerland
Intro to DefectDojo at OWASP SwitzerlandIntro to DefectDojo at OWASP Switzerland
Intro to DefectDojo at OWASP SwitzerlandMatt Tesauro
 
DF14: Drive Salesforce User Productivity with the Pebble SmartWatch
DF14: Drive Salesforce User Productivity with the Pebble SmartWatchDF14: Drive Salesforce User Productivity with the Pebble SmartWatch
DF14: Drive Salesforce User Productivity with the Pebble SmartWatchjayvinarora
 
Flare - tech-intro-for-paris-hackathon
Flare - tech-intro-for-paris-hackathonFlare - tech-intro-for-paris-hackathon
Flare - tech-intro-for-paris-hackathonCisco DevNet
 
Building Your App SDK with Swift
Building Your App SDK with SwiftBuilding Your App SDK with Swift
Building Your App SDK with SwiftJordan Yaker
 
MOE: Cross Platform Mobile Apps in Java
MOE: Cross Platform Mobile Apps in JavaMOE: Cross Platform Mobile Apps in Java
MOE: Cross Platform Mobile Apps in JavaGergely Kis
 
Fast deterministic screenshot tests for Android
Fast deterministic screenshot tests for AndroidFast deterministic screenshot tests for Android
Fast deterministic screenshot tests for AndroidArnold Noronha
 
Strategies for Mobile eLearning
Strategies for Mobile eLearningStrategies for Mobile eLearning
Strategies for Mobile eLearningeaselsolutions
 
DevoxxUK 2014 "Moving to a DevOps Mode: Easy, Hard, or Just Plain Terrifying?"
DevoxxUK 2014 "Moving to a DevOps Mode: Easy, Hard, or Just Plain Terrifying?"DevoxxUK 2014 "Moving to a DevOps Mode: Easy, Hard, or Just Plain Terrifying?"
DevoxxUK 2014 "Moving to a DevOps Mode: Easy, Hard, or Just Plain Terrifying?"Daniel Bryant
 
Continuous integration by Rémy Virin
Continuous integration by Rémy VirinContinuous integration by Rémy Virin
Continuous integration by Rémy VirinCocoaHeads France
 

Ähnlich wie Smartwatch Landscape (20)

Serverless: when functions and GitOps collide
Serverless: when functions and GitOps collideServerless: when functions and GitOps collide
Serverless: when functions and GitOps collide
 
How to Set Up Mobile Continuous Integration with Real Devices: CloudBees & SO...
How to Set Up Mobile Continuous Integration with Real Devices: CloudBees & SO...How to Set Up Mobile Continuous Integration with Real Devices: CloudBees & SO...
How to Set Up Mobile Continuous Integration with Real Devices: CloudBees & SO...
 
Moving to a DevOps mode - easy, hard or just plain terrifying? - Daniel Bryan...
Moving to a DevOps mode - easy, hard or just plain terrifying? - Daniel Bryan...Moving to a DevOps mode - easy, hard or just plain terrifying? - Daniel Bryan...
Moving to a DevOps mode - easy, hard or just plain terrifying? - Daniel Bryan...
 
JAX London 2014 "Moving to DevOps Mode: easy, hard or just plain terrifying?"
JAX London 2014 "Moving to DevOps Mode: easy, hard or just plain terrifying?"JAX London 2014 "Moving to DevOps Mode: easy, hard or just plain terrifying?"
JAX London 2014 "Moving to DevOps Mode: easy, hard or just plain terrifying?"
 
Philly CocoaHeads 20160414 - Building Your App SDK With Swift
Philly CocoaHeads 20160414 - Building Your App SDK With SwiftPhilly CocoaHeads 20160414 - Building Your App SDK With Swift
Philly CocoaHeads 20160414 - Building Your App SDK With Swift
 
iOS apps in Swift
iOS apps in SwiftiOS apps in Swift
iOS apps in Swift
 
Nebraska Trainer's Institute eLearning Presentaiotn
Nebraska Trainer's Institute eLearning PresentaiotnNebraska Trainer's Institute eLearning Presentaiotn
Nebraska Trainer's Institute eLearning Presentaiotn
 
iPhone Camp Birmingham (Bham) - Intro To iPhone Development
iPhone Camp Birmingham (Bham) - Intro To iPhone DevelopmentiPhone Camp Birmingham (Bham) - Intro To iPhone Development
iPhone Camp Birmingham (Bham) - Intro To iPhone Development
 
SQL Server 2016 JSON
SQL Server 2016 JSONSQL Server 2016 JSON
SQL Server 2016 JSON
 
Fast Track to Adobe Captivate
Fast Track to Adobe CaptivateFast Track to Adobe Captivate
Fast Track to Adobe Captivate
 
Intro to DefectDojo at OWASP Switzerland
Intro to DefectDojo at OWASP SwitzerlandIntro to DefectDojo at OWASP Switzerland
Intro to DefectDojo at OWASP Switzerland
 
DF14: Drive Salesforce User Productivity with the Pebble SmartWatch
DF14: Drive Salesforce User Productivity with the Pebble SmartWatchDF14: Drive Salesforce User Productivity with the Pebble SmartWatch
DF14: Drive Salesforce User Productivity with the Pebble SmartWatch
 
Flare - tech-intro-for-paris-hackathon
Flare - tech-intro-for-paris-hackathonFlare - tech-intro-for-paris-hackathon
Flare - tech-intro-for-paris-hackathon
 
Building Your App SDK with Swift
Building Your App SDK with SwiftBuilding Your App SDK with Swift
Building Your App SDK with Swift
 
Intro to iOS Development
Intro to iOS DevelopmentIntro to iOS Development
Intro to iOS Development
 
MOE: Cross Platform Mobile Apps in Java
MOE: Cross Platform Mobile Apps in JavaMOE: Cross Platform Mobile Apps in Java
MOE: Cross Platform Mobile Apps in Java
 
Fast deterministic screenshot tests for Android
Fast deterministic screenshot tests for AndroidFast deterministic screenshot tests for Android
Fast deterministic screenshot tests for Android
 
Strategies for Mobile eLearning
Strategies for Mobile eLearningStrategies for Mobile eLearning
Strategies for Mobile eLearning
 
DevoxxUK 2014 "Moving to a DevOps Mode: Easy, Hard, or Just Plain Terrifying?"
DevoxxUK 2014 "Moving to a DevOps Mode: Easy, Hard, or Just Plain Terrifying?"DevoxxUK 2014 "Moving to a DevOps Mode: Easy, Hard, or Just Plain Terrifying?"
DevoxxUK 2014 "Moving to a DevOps Mode: Easy, Hard, or Just Plain Terrifying?"
 
Continuous integration by Rémy Virin
Continuous integration by Rémy VirinContinuous integration by Rémy Virin
Continuous integration by Rémy Virin
 

Kürzlich hochgeladen

Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
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
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 
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
 

Kürzlich hochgeladen (20)

Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
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
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 
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
 

Smartwatch Landscape

  • 1. @sarbogast @eloudsa#Devoxx #smartvoxx Smartwatch Landscape Sébastien Arbogast Said Eloudrhiri
  • 2. #Devoxx #smartvoxx @sarbogast @eloudsa • Who owns a smartwatch? • Who is an Android developer? • Who is an iOS developer? • Who is a Pebble developer? • Who is a Rolex developer? • Who has already written a smartwatch app? • Who is a member of the Night’s Watch? Survey
  • 3. #Devoxx #smartvoxx @sarbogast @eloudsa Sébastien Arbogast
 @sarbogast • Java developer for 10 years • iOS developers for 5 years (developer of the first Devoxx schedule app) • Pebble developer for 2 years • Owner of TikTok Lunatik with iPod Nano • VP of engineering for Take Eat Easy
  • 4. #Devoxx #smartvoxx @sarbogast @eloudsa Said Eloudrhiri
 @eloudsa • Developer since 1992 • Agile Coach and trainer • Devoxx4Kids helper (Sphero, MindStorms, CodeCombat) • Side Projects: mobile development • Husband and father of Nora, Rayane and Djenna
  • 5. #Devoxx #smartvoxx @sarbogast @eloudsa Disclaimer We are not related to Google,Apple or Pebble. We are just curious developers sharing our experience. Materials used in this presentation remains the property of their owners. Any questions?
  • 6. #Devoxx #smartvoxx @sarbogast @eloudsa Why develop for smartwatches?
  • 7. #Devoxx #smartvoxx @sarbogast @eloudsa Glanceable
  • 8. #Devoxx #smartvoxx @sarbogast @eloudsa Sensors
  • 9. #Devoxx #smartvoxx @sarbogast @eloudsa Internet of Things
  • 10. #Devoxx #smartvoxx @sarbogast @eloudsa Notification-driven
  • 11. #Devoxx #smartvoxx @sarbogast @eloudsa Small screen
  • 12. #Devoxx #smartvoxx @sarbogast @eloudsa Interactions
  • 13. #Devoxx #smartvoxx @sarbogast @eloudsa Personal use
  • 14. #Devoxx #smartvoxx @sarbogast @eloudsa Landscape Apple 
 Watch Android 
 Wear Pebble Tizen
  • 17. #Devoxx #smartvoxx @sarbogast @eloudsa Android Studio
  • 18. #Devoxx #smartvoxx @sarbogast @eloudsa Debugging with Emulator USB Bridge adb -d forward tcp:5601 tcp:5601
  • 19. #Devoxx #smartvoxx @sarbogast @eloudsa Android Studio or Eclipse? • Android Development Tools (ADT) • Andmore - Eclipse Android Tooling (Incubation Project) https://projects.eclipse.org/projects/tools.andmore http://developer.android.com/tools/sdk/eclipse-adt.html
  • 20. #Devoxx #smartvoxx @sarbogast @eloudsa CloudPebble
  • 21. #Devoxx #smartvoxx @sarbogast @eloudsa Development cycle
  • 22. #Devoxx #smartvoxx @sarbogast @eloudsa Apple Watch • Select the Watch App scheme • Select your emulator configuration • Run • You can debug both emulators at the same time
  • 23. #Devoxx #smartvoxx @sarbogast @eloudsa Android • Install Android Wear on your Phone • Create Wear emulator • Run Wear emulator • Open ports to let emulator communicate with physical phone • Pair the Phone and the Wear Emulator • Deploy application on Wear and/or Mobile
  • 24. #Devoxx #smartvoxx @sarbogast @eloudsa Pebble • Connect Pebble app with CloudPebble • Enable Developer Connections • Run in CloudPebble
  • 25. #Devoxx #smartvoxx @sarbogast @eloudsa Available Watches
  • 26. #Devoxx #smartvoxx @sarbogast @eloudsa Apple Watch 272x340312x390
  • 27. #Devoxx #smartvoxx @sarbogast @eloudsa Android Wear
  • 28. #Devoxx #smartvoxx @sarbogast @eloudsa Square Round Round Chin Form factors
  • 29. #Devoxx #smartvoxx @sarbogast @eloudsa Pebble Classic Steel Time Time Steel Time Round 144x168
  • 30. #Devoxx #smartvoxx @sarbogast @eloudsa Compatibility • Android Wear:Android phones + iPhone (with some limitations) • Apple Watch: iPhones only • Pebble:Android phones + iPhones (with SDKs to integrate with apps on both platforms)
  • 31. #Devoxx #smartvoxx @sarbogast @eloudsa Inputs and Outputs
  • 32. #Devoxx #smartvoxx @sarbogast @eloudsa Apple Watch • Gestures • Force Touch • Digital Crown • Side Button • Taptic Engine • Microphone and speaker • Accelerometer • Heart rate monitor • (NFC)
  • 33. #Devoxx #smartvoxx @sarbogast @eloudsa • Touch screen • Shake moves • Button • Ambiant mode • Microphone (Voice control) • Heart rate monitor (PPG) • Gyro,Accelerometer, Compass • Barometer • NFC • GPS Android Wear
  • 34. #Devoxx #smartvoxx @sarbogast @eloudsa Pebble • Non-touch (color) e-ink screen • 4 buttons • Vibration • Microphone
  • 35. #Devoxx #smartvoxx @sarbogast @eloudsa Design Principles
  • 36. #Devoxx #smartvoxx @sarbogast @eloudsa Human Interface Guidelines • Lightweight interactions • Holistic design • Personal communication
  • 37. #Devoxx #smartvoxx @sarbogast @eloudsa Creative vision for Android Wear • Suggest: Context Stream • Demand: Cue Cards • Glanceable • Zero or Low interaction Beam me up!
  • 38. #Devoxx #smartvoxx @sarbogast @eloudsa Guidelines and patterns • Cards • List options with Menus • Execute actions with action bars • Prompting User Action on the Phone • Show Time and Data with the Status Bar • Show Alerts and Get Decisions with Modal Windows • UsingVibrations and Haptic Feedback • Handling Connection Problems
  • 39. #Devoxx #smartvoxx @sarbogast @eloudsa Different kinds of apps
  • 40. #Devoxx #smartvoxx @sarbogast @eloudsa Apple Watch • Apps • Notifications • Glances • Complications
  • 41. #Devoxx #smartvoxx @sarbogast @eloudsa Android Wear • Full-screen apps • Notifications • Custom notifications • Watch face 4 “If you don't have a Rolex by the time you reach 50, then you have clearly failed in your life.” Jacques Séguéla
  • 42. #Devoxx #smartvoxx @sarbogast @eloudsa Pebble • Apps • Timeline integration
  • 43. #Devoxx #smartvoxx @sarbogast @eloudsa Languages • Apple Watch: Swift or Objective-C • Android Wear: Java (or Kotlin or Groovy or …) • Pebble: C or Javascript (Pebble.js)
  • 44. #Devoxx #smartvoxx @sarbogast @eloudsa self.table.setNumberOfRows(self.schedules!.count, withRowType: "schedule") for (index,schedule) in self.schedules!.enumerate() { if let row = self.table.rowControllerAtIndex(index) as? ScheduleRowController { row.label.setText( schedule.title!.stringByReplacingOccurrencesOfString( NSLocalizedString("Schedule for ", comment:""), withString: "" ) ) } } Apple Watch
  • 46. #Devoxx #smartvoxx @sarbogast @eloudsa Layout: Round / Square
  • 47. #Devoxx #smartvoxx @sarbogast @eloudsa <?xml version="1.0" encoding="utf-8"?>
 <android.support.wearable.view.WatchViewStub
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/watch_talk_stub"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 app:rectLayout="@layout/talk_rect_fragment"
 app:roundLayout="@layout/talk_round_fragment"
 tools:context=".TalkActivity"
 tools:deviceIds="wear">
 
 </android.support.wearable.view.WatchViewStub> Layout: Main res/layout/talk_fragment.xml
  • 48. #Devoxx #smartvoxx @sarbogast @eloudsa <?xml version="1.0" encoding="utf-8"?>
 
 <RelativeLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:paddingTop="15dp">
 
 <TextView
 android:id="@+id/title"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 Sub-layout: Square res/layout/talk_rect_fragment.xml
  • 49. #Devoxx #smartvoxx @sarbogast @eloudsa <?xml version="1.0" encoding="utf-8"?>
 
 <android.support.wearable.view.BoxInsetLayout 
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:padding="15dp">
 
 <RelativeLayout
 android:layout_width="match_parent"
 android:layout_height="match_parent">
 
 <TextView
 android:id="@+id/title"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 Sub-layout: Round res/layout/talk_round_fragment.xml
  • 50. #Devoxx #smartvoxx @sarbogast @eloudsa CloudPebble UI editor
  • 51. #Devoxx #smartvoxx @sarbogast @eloudsa static void main_window_load(Window *window) {
 // Get information about the Window
 Layer *window_layer = window_get_root_layer(window);
 GRect bounds = layer_get_bounds(window_layer);
 
 // Create the TextLayer with specific bounds
 s_time_layer = text_layer_create(
 GRect(0, PBL_IF_ROUND_ELSE(58, 52), bounds.size.w, 50));
 
 // Improve the layout to be more like a watchface
 text_layer_set_background_color(s_time_layer, GColorClear);
 text_layer_set_text_color(s_time_layer, GColorBlack);
 text_layer_set_text(s_time_layer, "00:00");
 text_layer_set_font(s_time_layer, fonts_get_system_font(FONT_KEY_BITHAM_42_BOLD));
 text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter);
 
 // Add it as a child layer to the Window's root layer
 layer_add_child(window_layer, text_layer_get_layer(s_time_layer));
 } Pebble
  • 52. #Devoxx #smartvoxx @sarbogast @eloudsa Internet connectivity
  • 53. #Devoxx #smartvoxx @sarbogast @eloudsa Apple Watch (NSURLSession) Apple 
 Watch Apple Watch app Internet
  • 54. #Devoxx #smartvoxx @sarbogast @eloudsa func loadSchedulesForConference(conference:String, callback: ([Schedule]) -> (Void)) { //Configure session and disable caching as it fails let configuration = NSURLSessionConfiguration.defaultSessionConfiguration() configuration.requestCachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData let session = NSURLSession(configuration: configuration) //Call API let schedulesURL = NSURL(string: "http://cfp.devoxx.be/api/conferences/(conference)/schedules/")! let task = session.dataTaskWithURL(schedulesURL) { (data: NSData?, response:NSURLResponse?, error:NSError?) -> Void in //process data } task.resume() } Apple Watch
  • 55. #Devoxx #smartvoxx @sarbogast @eloudsa Internet connectivity Fallback solution when Bluetooth not available. Unable to connect on remote servers.
  • 56. #Devoxx #smartvoxx @sarbogast @eloudsa /**
 * Created by eloudsa on 30/10/15.
 */
 public interface DevoxxApi {
 
 
 @GET("/conferences/{conference}/schedules")
 void getSchedules(@Path("conference") String conference, Callback<Schedules> callback);
 
 @GET("/conferences/{conference}/schedules/{day}")
 void getSchedule(@Path("conference") String conference, @Path("day") String day, Callback<SlotList> callback);
 
 @GET("/conferences/{conference}/talks/{talkid}")
 void getTalk(@Path("conference") String conference, @Path("talkid") String uuid, Callback<Talk> callback);
 
 @GET("/conferences/{conference}/speakers/{uuid}")
 void getSpeaker(@Path("conference") String conference, @Path("uuid") String uuid, Callback<Speaker> callback);
 
 }
 Android Wear: Endpoints Retrofit REST API client from Square
  • 57. #Devoxx #smartvoxx @sarbogast @eloudsa @Override
 public void onCreate() {
 super.onCreate();
 
 …
 // prepare the REST build
 mRestAdapter = new RestAdapter.Builder()
 .setEndpoint(getResources().getString(R.string.devoxx_rest_api))
 .build();
 
 mMethods = mRestAdapter.create(DevoxxApi.class);
 mConferenceName = getResources().getString(R.string.devoxx_conference);
 } Android Wear: Setup
  • 58. #Devoxx #smartvoxx @sarbogast @eloudsa // Retrieve schedules from Devoxx
 private void retrieveSchedules() {
 // retrieve the schedules list from the server
 Callback callback = new Callback() {
 @Override
 public void success(Object o, Response response) {
 // retrieve schedule from REST
 Schedules scheduleList = (Schedules) o;
 if (scheduleList == null) {
 Log.d(TAG, "No schedules!");
 return;
 }
 
 sendSchedules(scheduleList.getLinks());
 }
 
 @Override
 public void failure(RetrofitError retrofitError) {
 Log.d(TAG, retrofitError.getMessage());
 }
 };
 mMethods.getSchedules(mConferenceName, callback);
 } Android Wear: Get Shedules 1 2 3
  • 59. #Devoxx #smartvoxx @sarbogast @eloudsa Pebble Pebble app Pebble App JS module Internet AppMessage XHR
  • 60. #Devoxx #smartvoxx @sarbogast @eloudsa static bool load_site_list() {
 if(accessToken && sizeof(accessToken) > 0) {
 DictionaryIterator *iter;
 app_message_outbox_begin(&iter);
 if (iter == NULL) {
 APP_LOG(APP_LOG_LEVEL_DEBUG, "null iter");
 return false;
 }
 
 Tuplet message_type_tuple = TupletInteger(MESSAGE_TYPE, LOAD_SITE_LIST);
 dict_write_tuplet(iter, &message_type_tuple);
 Tuplet access_token_tuple = TupletCString(ACCESS_TOKEN, accessToken);
 dict_write_tuplet(iter, &access_token_tuple);
 Tuplet refresh_token_tuple = TupletCString(REFRESH_TOKEN, refreshToken);
 dict_write_tuplet(iter, &refresh_token_tuple);
 dict_write_end(iter);
 
 app_message_outbox_send();
 
 return true;
 } else {
 return false;
 }
 } Pebble to phone
  • 61. #Devoxx #smartvoxx @sarbogast @eloudsa function loadSiteList(accessToken, refreshToken) {
 console.log("Loading site list for access token " + accessToken);
 var response;
 var req = new XMLHttpRequest();
 // build the GET request
 req.open('GET', "https://api.myfox.me:443/v2/client/site/items?access_token=" + accessToken, true);
 req.onload = function(e) {
 if (req.readyState == 4) {
 // 200 - HTTP OK
 if(req.status == 200) {
 console.log(req.responseText);
 response = JSON.parse(req.responseText);
 var siteList;
 if (response.status === 'OK') {
 siteList = response.payload.items;
 
 var msg = {};
 msg.messageType = MessageType.SITE_LIST;
 for(var i = 0; i < siteList.length; i++){
 var site = siteList[i];
 msg['' + site.siteId] = site.label;
 }
 console.log("Sending response back to Pebble: " + JSON.stringify(msg));
 Pebble.sendAppMessage(msg);
 } else {
 console.log("Status not OK");
 Pebble.sendAppMessage({messageType:MessageType.ERROR, errorMessage:"Could not load list of sites. Please try again later."});
 }
 } else if(req.status == 401 && refreshToken){
 getNewAccessToken(refreshToken, loadSiteList);
 } else {
 console.log("Request returned error code " + req.status.toString());
 Pebble.sendAppMessage({messageType:MessageType.ERROR});
 }
 }
 };
 req.send(null);
 } Phone to internet and back
  • 62. #Devoxx #smartvoxx @sarbogast @eloudsa Phone communication
  • 63. #Devoxx #smartvoxx @sarbogast @eloudsa Watch Connectivity Apple 
 Watch update application context send message transfer user info transfer file replace live queue big data
  • 64. #Devoxx #smartvoxx @sarbogast @eloudsa if WCSession.isSupported() { session = WCSession.defaultSession() session?.delegate = self session?.activateSession() if let session = self.session where session.reachable { session.sendMessage(["talkSlot" : talkSlotMessage as NSDictionary], replyHandler: { (reply:[String : AnyObject]) -> Void in }, errorHandler: { (error:NSError) -> Void in print(error) } ) } else { session?.transferUserInfo(["talkSlot" : talkSlotMessage as NSDictionary]) } } Watch Connectivity
  • 65. #Devoxx #smartvoxx @sarbogast @eloudsa Google API Client Device Google Play Services Your App Google API Client Google Play services library Message API Data API Node API
  • 66. #Devoxx #smartvoxx @sarbogast @eloudsa public class ScheduleActivity extends Activity { // Google Play Services
 private GoogleApiClient mApiClient;
 … @Override
 protected void onStart() {
 super.onStart();
 
 mApiClient = new GoogleApiClient.Builder(this)
 .addApi(Wearable.API)
 .addConnectionCallbacks(this)
 .build();
 
 mApiClient.connect();
 }
 
 
 @Override
 protected void onStop() {
 if ((mApiClient != null) && (mApiClient.isConnected())) {
 Wearable.DataApi.removeListener(mApiClient, this);
 mApiClient.disconnect();
 }
 
 super.onStop();
 } Google API Client 1 2 3
  • 67. #Devoxx #smartvoxx @sarbogast @eloudsa Connected nodes Phone Watch Node Node Message API WearableListenerService onMessageReceived() MessageApi sendMessage()
  • 68. #Devoxx #smartvoxx @sarbogast @eloudsa public class ScheduleActivity extends Activity { … private void sendMessage(final String path, final String message) {
 new Thread(new Runnable() {
 @Override
 public void run() {
 // broadcast the message to all connected devices
 final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(mApiClient).await();
 for (Node node : nodes.getNodes()) {
 Wearable.MessageApi.sendMessage(mApiClient, node.getId(), path, message.getBytes()).await();
 }
 }
 }).start();
 } 
 Message API: Send Message
  • 69. #Devoxx #smartvoxx @sarbogast @eloudsa public class WearService extends WearableListenerService { … @Override
 public void onMessageReceived(MessageEvent messageEvent) {
 
 // Processing the incoming message
 String path = messageEvent.getPath();
 String data = new String(messageEvent.getData());
 
 if (path.equalsIgnoreCase(Constants.SCHEDULES_PATH)) {
 retrieveSchedules();
 return;
 } … Message API: Message Received
  • 70. #Devoxx #smartvoxx @sarbogast @eloudsa Data Synchronisation Phone Watch Node Node Data API.putDataItem() Wearable.DataApi onDataChanged() DataApi.DataListener
  • 71. #Devoxx #smartvoxx @sarbogast @eloudsa 
 // send Schedules to the watch
 private void sendSchedules(List<Link> schedules) {
 final PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(Constants.SCHEDULES_PATH);
 
 ArrayList<DataMap> schedulesDataMap = new ArrayList<>();
 
 // process each schedule
 for (Link schedule : schedules) {
 
 DataMap scheduleDataMap = new DataMap();
 
 // process and push schedule's data
 scheduleDataMap.putString("day", Utils.getLastPartUrl(schedule.getHref()));
 scheduleDataMap.putString("title", schedule.getTitle());
 
 schedulesDataMap.add(scheduleDataMap);
 }
 
 // store the list in the datamap to send it to the watch
 putDataMapRequest.getDataMap().putDataMapArrayList(Constants.LIST_PATH, schedulesDataMap);
 
 // send the schedules
 if (mApiClient.isConnected()) {
 Wearable.DataApi.putDataItem(mApiClient, putDataMapRequest.asPutDataRequest());
 }
 }
 Data API: Send Data 1 2 3 4
  • 72. #Devoxx #smartvoxx @sarbogast @eloudsa @Override
 public void onDataChanged(DataEventBuffer dataEventBuffer) {
 
 for (DataEvent event : dataEventBuffer) {
 
 // Check if list of schedules has changed
 if (event.getType() == DataEvent.TYPE_CHANGED && event.getDataItem().getUri().getPath().startsWith(Constants.SCHEDULES_PATH)) {
 // get the list of schedules from the incoming data event 
 SchedulesListWrapper schedulesListWrapper = new SchedulesListWrapper();
 final List<Schedule> schedulesList = schedulesListWrapper.getSchedulesList(event);
 
 runOnUiThread(new Runnable() {
 @Override
 public void run() {
 // hide the progress bar
 findViewById(R.id.progressBar).setVisibility(View.GONE);
 
 mListViewAdapter.refresh(schedulesList);
 }
 });
 
 return;
 }
 }
 } 1 2 3 4 Data API: Data changed
  • 73. #Devoxx #smartvoxx @sarbogast @eloudsa Caching
  • 74. #Devoxx #smartvoxx @sarbogast @eloudsa private func saveSchedulesFromData(data: NSData, inContext context: NSManagedObjectContext) { context.performBlockAndWait { () -> Void in if data.length > 0 { do { let schedulesDict = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) if let schedulesDict = schedulesDict as? NSDictionary, schedulesArray = schedulesDict["links"] as? NSArray { guard let devoxx15 = self.getOrCreateDevoxx15(inContext: context) else { return } var schedules = [Schedule]() for scheduleDict in schedulesArray { let scheduleDict = scheduleDict as? NSDictionary let schedule = self.getOrCreateScheduleForHref(scheduleDict["href"] as! String, inContext: context)! schedule.title = scheduleDict["title"] as? String schedule.href = scheduleDict["href"] as? String schedule.conference = devoxx15 self.saveContext(context) schedules.append(schedule) } devoxx15.schedules = NSOrderedSet(array: schedules) self.saveContext(context) } } catch let jsonError as NSError { print(jsonError) } } } } Core Data on Apple Watch
  • 76. #Devoxx #smartvoxx @sarbogast @eloudsa Wear Data Item (Cache) .getInt() DataMap .getDataIetms() DataApi wear://path_to_data 1 2 Data caching MessageApi sendMessage() 3 4
  • 78. #Devoxx #smartvoxx @sarbogast @eloudsa App structure and distribution
  • 79. #Devoxx #smartvoxx @sarbogast @eloudsa Apple Watch • Package the Apple Watch app with the iPhone app • Release the iPhone app like any other • Wait for review… • Wait again… • Wait some more…
  • 80. #Devoxx #smartvoxx @sarbogast @eloudsa Android Wear
  • 81. #Devoxx #smartvoxx @sarbogast @eloudsa Prepare the build • Include permissions required by Wear into Phone (Manifest) • Use same package name and version number (build.gradle)
  • 82. #Devoxx #smartvoxx @sarbogast @eloudsa Generate signed APK
  • 83. #Devoxx #smartvoxx @sarbogast @eloudsa Mobile APK embeds Wearable Mobile App Module Code Resources Wearable App Wear App Module Code Resources
  • 84. #Devoxx #smartvoxx @sarbogast @eloudsa Publishing: Select Android Wear
  • 85. #Devoxx #smartvoxx @sarbogast @eloudsa Distribution Companion App Wearable App Bluetooth Companion App Play Services Android Wear Wearable App Smartvoxx
  • 86. #Devoxx #smartvoxx @sarbogast @eloudsa Pebble Pebble App JS module
  • 87. #Devoxx #smartvoxx @sarbogast @eloudsa Smartvoxx • smartvoxx.com
  • 89. #Devoxx #smartvoxx @sarbogast @eloudsa Summary • Huge inequalities in terms of development platform ease-of- use • Apple obviously took time to add abstraction layers that make development more expressive • Short learning curve on Android Wear compared to Apple Watch • Tooling support not up-to-date on Android • Documentation is not really finished for both platforms • Not all apps make sense on smartwatches
  • 90. #Devoxx #smartvoxx @sarbogast @eloudsa Apps that work on smartwatches • countdowns and timers • status checks: what’s the temperature? what’s my next session? what’s the score of the game? • remote controls: switch off the light, change the music, open my hotel room, pay for my shopping • notification responders: invitation to a meeting -> what’s the meeting about, somebody sent me a message -> what does it say? • data trackers: where am I? how many calories am I burning? what’s my speed?)
  • 91. #Devoxx #smartvoxx @sarbogast @eloudsa Apps that don’t make sense •  games of any kind •  any long reading (news, books, etc.) •  ecommerce •  video or image viewing •  anything that requires text input
  • 92. #Devoxx #smartvoxx @sarbogast @eloudsa One more thing …
  • 93. #Devoxx #smartvoxx @sarbogast @eloudsa Smartvoxx on Github Available in Black … … and White http://github.com/smartvoxx