gdg georgetown devfest 2014 presentation: android wear: a developer's perspective

74
Android Wear: A Developer’s Perspective Marc Lester Tan Mobility Innovation Center, APJ w: marctan.com t: @mharkus +MarcLesterTan

Upload: mharkus

Post on 02-Jul-2015

1.456 views

Category:

Software


0 download

DESCRIPTION

These are the slides that I've used for my Android Wear presentation in GDG GeorgeTown Malaysia's first ever Devfest and GDays. November 15, 2014

TRANSCRIPT

Page 1: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Android Wear: A Developer’s

Perspective

Marc Lester TanMobility Innovation Center, APJ

w: marctan.comt: @mharkus+MarcLesterTan

Page 2: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Agenda• Introduction to Android Wear• Notifications• Wearable Apps • Watch Faces• Demo

Page 3: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective
Page 4: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective
Page 5: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective
Page 6: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective
Page 7: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective
Page 8: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Notifications

Page 9: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Simple NotificationPendingIntent pendingIntent = createIntent();

NotificationCompat.Builder builder = new NotificationCompat.Builder(this).setContentTitle(“Message from Weng”).setContentText(“Don’t forget to try Penang Laksa!”)

.setSmallIcon(R.drawable.ic_launcher)

.setContentIntent(pendingIntent);

notificationMgr = NotificationManagerCompat.from(this);

notificationMgr.notify(0, builder.build());

Page 10: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective
Page 11: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective
Page 12: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

NO WORK

REQUIRED

Page 13: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

RepliesPagesStacks

Page 14: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Stacked

Notifications

Page 15: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Stacked Notificationsbuilder1 = createNotification(“Don’t forget to try Penang Laksa!”);

builder1.setGroup("MESSAGES_GROUP_KEY”);

builder2 = createNotification(“Also their Char Koay Teow!”);

builder2.setGroup("MESSAGES_GROUP_KEY”);

summary = createNotification(“2 Messages from Weng”);

summary.setGroup(”MESSAGES_GROUP_KEY”);

summary.setGroupSummary(true);

notificationMgr.notify(0, builder1.build());

notificationMgr.notify(1, builder2.build());

notificationMgr.notify(2, summary.build());

Page 16: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective
Page 17: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Pages

Page 18: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

PagesNotificationCompat.BigPictureStyle style = new

NotificationCompat.BigPictureStyle();

style.setBigContentTitle(”Penang Laksa");

pageNotif = NotificationCompat.Builder(this)

.setStyle(style)

.setContentText("Mouth Watering!")

.extend(new NotificationCompat.WearableExtender()

.setBackground(penangLaksaBitmap)

.build();

Page 19: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Pagesbuilder1 = createNotification(“Don’t forget to try Penang Laksa!”);

wearableExtender =

new NotificationCompat.WearableExtender()

.setHintHideIcon(true)

.setBackground(mainbgBitmap)

.addPage(pageNotif);

builder1.extend(wearableExtender);

notificationMgr.notify(0, builder1.build());

Page 20: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective
Page 21: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Replies

Page 22: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Replies• RemoteInput remoteInput = new

RemoteInput.Builder("extra_voice_reply”)

.setLabel("What do you think?")

.setChoices(new String[]{

"Awesome",

"Shiok!",

"Nom nom nom!"

})

.build();

Page 23: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

RepliesAction action = new Action.Builder(replyIcon,"Reply”,

replyPendingIntent)

.addRemoteInput(remoteInput)

.build();

builder1 = createNotification(“Don’t forget to try Penang Laksa!”);

builder1.extend(wearableExtender.addAction(action));

notificationMgr.notify(0, builder1.build());

Page 24: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective
Page 25: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Receiving Voice InputBundle remoteInput = RemoteInput.getResultsFromIntent(getIntent());

if (remoteInput != null) {

reply = remoteInput.getCharSequence("extra_voice_reply”);

}

Page 26: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Wearable Apps

Page 27: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Wearable Apps

• Run directly on the device

• Access to sensors and GPU

• Greatly differ in design and usability

• Limited functionality

Page 28: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Wearable vs Handheld Apps

• System enforces timeout period

• Relatively small in size and functionality

• Users don’t download apps directly to wearable

• Don’t support the following APIs• android.webkit

• android.print

• android.app.backup

• android.appwidget• android.hardware.usb

Page 29: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Creating Wearable

Apps

Page 30: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Creating Wearable Apps

Page 31: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Creating Wearable Apps

Page 32: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Creating Wearable Apps

Page 33: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Creating Wearable Apps

Page 34: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Creating Wearable Apps

Page 35: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Creating Wearable Apps

Page 36: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Creating Wearable Apps

Page 37: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Data Exchange Custom UI Voice Actions

Page 38: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective
Page 39: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Node

Data

Message

Data Exchange

Page 40: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Create a GoogleApiClientGoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)

.addConnectionCallbacks(new ConnectionCallbacks() {

public void onConnected(Bundle connectionHint) {

// Now you can use the data layer API

}

...

})

.addOnConnectionFailedListener(new OnConnectionFailedListener() {

public void onConnectionFailed(ConnectionResult result) {

}

})

// Request access only to the Wearable API

.addApi(Wearable.API)

.build();

mGoogleApiClient.connect();

Page 41: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Check for connected nodesnodes = Wearable.NodeApi

.getConnectedNodes(mGoogleApiClient)

.await();

nodeList = nodes.getNodes();

if (nodeList.size() > 0) {

connectedNode = nodeList.get(0);

}

Page 42: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Send a messageresult = Wearable.MessageApi

.sendMessage(mGoogleApiClient, parentNode.getId(), "/start/MainActivity/",

message.getBytes());

result.setResultCallback(new

ResultCallback<MessageApi.SendMessageResult>() {

public void onResult(MessageApi.SendMessageResult

sendMessageResult) {

if (!sendMessageResult.getStatus().isSuccess()) {

// handle error

}

}

});

Page 43: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Receive a message@Override

public void onMessageReceived(MessageEvent messageEvent) {

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

}

Page 44: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Send a datamap = PutDataMapRequest.create("/image");

map.getDataMap().putAsset("image”,assetFromBitmap);

PutDataRequest request = map.asPutDataRequest();

pendingResult = Wearable.DataApi

.putDataItem(mGoogleApiClient,request);

Page 45: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Receive a data@Override

public void onDataChanged(DataEventBuffer dataEvents) {

for (DataEvent event : dataEvents) {

if (event.getType() == DataEvent.TYPE_CHANGED &&

event.getDataItem()

.getUri().getPath()

.equals("/image")) {

dataMapItem = DataMapItem

.fromDataItem(event.getDataItem());

profileAsset = dataMapItem.getDataMap()

.getAsset("image");

}

}

}

Page 46: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

public class MyWearListener extends WearableListenerService {

@Override

public void onMessageReceived(MessageEvent messageEvent) {

}

@Override

public void onDataChanged(DataEventBuffer dataEvents) {

}

@Override

public void onPeerConnected(Node peer) {

}

@Override

public void onPeerDisconnected(Node peer) {

}

}

Page 47: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

<service android:name=”.MyWearListener" >

<intent-filter>

<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />

</intent-filter>

</service>

Intent Filter

Page 48: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Custom

Layouts

Page 49: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective
Page 50: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

● BoxInsetLayout

● Card Fragment

● CircledImageView

● ConfirmationActivity

● DismissOverlayView

● DelayedConfirmationView

● GridViewPager

● GridPagerAdapter

● FragmentGridPagerAdapter

● WatchViewStub

Page 51: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

WatchViewStub

<?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

app:rectLayout="@layout/rect_activity_main"

app:roundLayout="@layout/round_activity_main"tools:context=".Main"

tools:deviceIds="wear" android:padding="12dp">

</android.support.wearable.view.WatchViewStub>

Page 52: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

BoxInsetLayout

Page 53: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

DelayedConfirmationView & ConfirmationActivity

Page 54: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

CardFragment

Page 55: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Voice Actions

Page 56: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective
Page 57: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

<activity android:name="MyNoteActivity">

<intent-filter>

<action android:name="android.intent.action.SEND" />

<category

android:name="com.google.android.voicesearch.SELF_NOTE" />

</intent-filter>

</activity>

System Provided Action

Page 58: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

● Call a car/taxi

● Take a note

● Set alarm

● Set timer

● Start/Stop a bike ride

● Start/Stop a run

● Start/Stop a workout

● Show heart rate

● Show step count

Page 59: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

<activity android:name="StartRunActivity"

android:label="MyRunningApp">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category

android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

App Provided Voice Action

Page 60: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

private void displaySpeechRecognizer() {

Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);

intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,

RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);

startActivityForResult(intent, SPEECH_REQUEST_CODE);

}

Speech Recognizer

Page 61: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Watch Faces

Page 62: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective
Page 63: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

UNOFFICIAL

Page 64: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Create a Wear Watch Face

• Same steps as creating a wearable app

• Uses Executors for per-second updates

• Uses Intent.ACTION_TIME_TICK for per-minute updates

• Use DisplayManager for screen events

• HACK!

Page 65: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Create a Wear Watch Face

Page 66: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

<activity

android:name="com.marctan.hellowatchface.MainActivity"

android:label="@string/app_name"

android:allowEmbedded="true">

<meta-data

android:name="com.google.android.clockwork.home.preview"

android:resource="@drawable/ic_launcher" />

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category

android:name="com.google.android.clockwork.home.category.HOME_BACKGROUND" />

</intent-filter>

. . .

</activity>

Modify AndroidManifest.xml

Page 67: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

public void onDisplayAdded(int i) {

}

public void onDisplayRemoved(int i) {

}

public void onDisplayChanged(int displayId) {

switch(displayManager.getDisplay(displayId).getState()){

case Display.STATE_OFF:

case Display.STATE_DOZING:

updateEveryMinute();

break;

default:

updateEverySecond();

break;

}

}

DisplayListener Events

Page 68: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

private void updateEverySecond() {

. . .

scheduledFuture = scheduleTaskExecutor.scheduleAtFixedRate(new

Runnable() {

public void run() {

updateClockView();

}

}, 0, 1, TimeUnit.SECONDS);

}

Per-second updates

Page 69: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

private void updateEveryMinute() {

if (scheduledFuture != null) {

scheduledFuture.cancel(true);

}

ClockManager.getInstance().setAmbientMode(true);

}

Per-minute updates

Page 70: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Hello Wear Watch Face

Page 71: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Demo

Page 72: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Thank You

Source Codegithub.com/mharkus/DevfestGeorgeTown2014

Android Wear Dev Documentationdeveloper.android.com/wear/index.html

My Blogmarctan.com

Page 73: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Android Wear: A Developer’s

Perspective

Page 74: GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspective

Android Wear: A Developer’s

Perspective