making apps for android wear luis de la rosa€¦ · currently targeting only watches several...

Post on 19-Aug-2020

0 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

MAKING APPS FOR ANDROID WEARLUIS DE LA ROSALEAD APP DEVELOPER

CAPITAL ONE

WEAR OVERVIEWCurrently targeting only watches

Several manufacturers and modelsBuilds upon your Android experience

WHAT IS NOT IN WEARwebkitprint

appwidgethardware.usb

WHAT IS ONLY IN WEARWearable UI Library

Wearable Data Layer

SETUP DEV FOR WEARAndroid Studio

SDK 20 4.4W KITKAT_WATCHPair with Emulator

adb -d forward tcp:5601 tcp:5601bluetooth

ANDROID WEAR PROJECTwear module

handheld modulesubclass Activity, not WatchActivity (fixed in Studio 0.8.1)

DESIGN + UXsmall screen: roughly 320x320

timeout -> homeStream of CardsSwipes and Taps

GLANCEABLE UI

PATTERNSCard

Action Button1D Picker2D Picker

Selection ListConfirmation

Exit

NOTIFICATIONS AND APPS

HANDHELD AND WEARABLE APPS

HELLO WEAR WORLD APP

SQUARE VS ROUNDWatchViewStub

rectLayout / roundLayoutBoxInsetLayout

app:layout_box="bottom" (or all, top|left, etc)

EMULATORRound

Workaround: Use Host GPU off to truly roundSquare

Can make custom 320x320HAXM + Intel image

VOICEvoice trigger

custom voice trigger with label attribute and launcher intent-filterspeech input

WEAR LIBRARIESInside of Google Play Services

com.google.android.gms.wearable17 Interfaces12 Classes

WEAR UI LIBRARYaka Wearable Support Library

android.support.wearable2 Classes in .activity

7 Interfaces and 19 Classes in .view

CARDSCardFragment

CardFrameCardScrollView

GRIDVIEWPAGERFragmentGridPagerAdapter

getBackground(row, column) - parallaxgetRowCount() / getColumnCount(row)

getFragment(row, column)getCurrentColumnForRow(row, currentColumn)

LISTS

LISTSWearableListView

.Item.ViewHolder

.Adapter.ClickListener

EXITINGswipeToDismiss

DeviceDefault theme<style name="AppTheme" parent="@android:style/Theme.DeviceDefault.Light"> <item name="android:windowSwipeToDismiss">false</item></style>

DismissOverlayView + GestureDetector for long press

ALLOWING USER TO CANCELDelayedConfirmationView

SHOWING CONFIRMATION ANIMATIONConfirmationActivity

UI EXAMPLES

WEARABLE DATA LAYER APIPurpose

GoogleApiClientData Items

AssetMessage

NodeWearableListenerService

DataListener / MessageListener / NodeListener

GOOGLEAPICLIENTbuild with Wearable.API

attach callbacks and listenersconnect

@Overridepublic void onCreate(Bundle b) { super.onCreate(b); mGoogleApiClient = new GoogleApiClient.Builder(this) .addApi(Wearable.API) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build();}

CONNECTING@Overrideprotected void onStart() { super.onStart(); mGoogleApiClient.connect();}

@Override //ConnectionCallbackspublic void onConnected(Bundle connectionHint) { Wearable.DataApi.addListener(mGoogleApiClient, this); Wearable.MessageApi.addListener(mGoogleApiClient, this); Wearable.NodeApi.addListener(mGoogleApiClient, this);}

DISCONNECTING@Overrideprotected void onStop() { Wearable.DataApi.removeListener(mGoogleApiClient, this); Wearable.MessageApi.removeListener(mGoogleApiClient, this); Wearable.NodeApi.removeListener(mGoogleApiClient, this); mGoogleApiClient.disconnect(); super.onStop();}

DECIDING WHICH TO USEReplicate data?

Less than 100KB, use Data*100KB or more, use Asset

Message-based

DATAITEM (SENDING SMALL ITEMS)Payload

Path

DATAMAP (SENDING SMALL ITEMS #2)Like a Bundle

public void syncCount() { PutDataMapRequest dataMap = PutDataMapRequest.create("/count"); dataMap.getDataMap().putInt(COUNT_KEY, count++); PutDataRequest request = dataMap.asPutDataRequest(); PendingResult<DataApi.DataItemResult> pendingResult = Wearable.DataApi .putDataItem(mGoogleApiClient, request);}

ASSET (SENDING LARGE BINARY DATA)createFrom*

PutDataRequest.putAsset()PutDataMapRequest.getDataMap().putAsset()

Asset.createFromBytes(byteStream.toByteArray());

private void sendPhoto(Asset asset) { PutDataMapRequest dataMap = PutDataMapRequest.create(IMAGE_PATH); dataMap.getDataMap().putAsset(IMAGE_KEY, asset); dataMap.getDataMap().putLong("time", new Date().getTime()); PutDataRequest request = dataMap.asPutDataRequest(); Wearable.DataApi.putDataItem(mGoogleApiClient, request) .setResultCallback(new ResultCallback<DataItemResult>() { @Override public void onResult(DataItemResult dataItemResult) { LOGD(TAG, "Sending image was successful: " + dataItemResult.getStatus() } });

}

MESSAGEWearable.MessageApi.sendMessage()

private void sendStartActivityMessage(String node) { Wearable.MessageApi.sendMessage( mGoogleApiClient, node, START_ACTIVITY_PATH, new byte[0]).setResultCallback( new ResultCallback<SendMessageResult>() { @Override public void onResult(SendMessageResult sendMessageResult) { if (!sendMessageResult.getStatus().isSuccess()) { Log.e(TAG, "Failed to send message with status code: " + sendMessageResult.getStatus().getStatusCode()); } } } );}

PENDINGRESULTasync

setResultCallback();

syncawait();

WEARABLELISTENERSERVICEcreate in both wearable and handheld apps

<service android:name=".YourListenerService"> <intent-filter> <action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> </intent-filter></service>

Binder.clearCallingIdentity() / restoreCallingIdentity()

LISTENING FOR DATAMAPSonDataChanged()

@Overridepublic void onDataChanged(DataEventBuffer dataEvents) { LOGD(TAG, "onDataChanged: " + dataEvents); final List<DataEvent> events = FreezableUtils.freezeIterable(dataEvents); dataEvents.release(); // Loop through the events for (DataEvent event : events) { Uri uri = event.getDataItem().getUri(); String path = uri.getPath(); // Find the path we're interested in and work with that event if (COUNT_PATH.equals(path)) { } }}

LISTENING FOR MESSAGESonMessageReceived()

public void onMessageReceived(final MessageEvent messageEvent) { LOGD(TAG, "onMessageReceived() A message from watch was received:" + messageEvent .getRequestId() + " " + messageEvent.getPath());}

LISTENING FOR PEERSonPeerConnected() / onPeerDisconnected()

@Overridepublic void onPeerConnected(Node peer) { LOGD(TAG, "onPeerConnected: " + peer);}

@Overridepublic void onPeerDisconnected(Node peer) { LOGD(TAG, "onPeerDisconnected: " + peer);}

LISTENING IN AN ACTIVITYDataApi.DataListener

MessageApi.MessageListenerNodeApi.NodeListener

GoogleApiClient build / connect / addListener / removeListener/ disconnect

onDataChanged() / onMessageReceived() /onPeerConnected() / onPeerDisconnected()

FREEZABLEInterface for data objects that support being frozen into

immutable representations..freeze();

FreezableUtils.freezeIterable();

DATA LAYER EXAMPLES

PACKAGING WEAR APP

PROGUARDWearableListView

NEXT STEPSStack Overflow - use android-wear tag

SDK ExamplesSet up Emulators (and maybe buy a Watch)

Send feedbackStop by our booth

THANKS!Luis de la Rosa

twitter.com/@louielouiegoogle.com/+luisdelarosa

luisdelarosa.com/wear

top related