Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction to Android Wear - A Glimpse Into the Future

Introduction to Android Wear - A Glimpse Into the Future

The recent unveiling of Android Wear introduced a brand new set of challenges and opportunities for application designers and developers. Indeed, wearable computing requires designers to think in a radically different manner while offering tremendous new ways to improve people lives. This session acts as a complete overview of the new Android Wear ecosystem and explains how developers can push their existing apps to the wearable level from both a designer and a developer perspective.

Cyril Mottier

November 14, 2014
Tweet

More Decks by Cyril Mottier

Other Decks in Programming

Transcript

  1. Android Wear 101
    A glimpse into the future

    View full-size slide

  2. TWITTER
    @cyrilmottier
    !
    WEBSITE
    cyrilmottier.com

    View full-size slide

  3. Introducing
    Android Wear paradigms

    View full-size slide

  4. Real life
    Get
    phone
    Use
    phone

    View full-size slide

  5. Micro interactions
    Reducing interactions to their minimum

    View full-size slide

  6. wearable
    paradigms
    handheld
    paradigms

    View full-size slide

  7. Think different
    …or at least differently ?

    View full-size slide

  8. Android Wear
    UX main principles

    View full-size slide

  9. 3 main principles
    Contextual

    View full-size slide

  10. 3 main principles
    Contextual | Glanceable

    View full-size slide

  11. 3 main principles
    Contextual | Glanceable Low interaction
    |

    View full-size slide

  12. Contextual
    The right info
    at the right time

    View full-size slide

  13. Context helpers
    Sensors
    Activity
    Time
    Location
    Devices
    Identity
    Calendar

    View full-size slide

  14. Glanceable
    The essential info
    in a blink of an eye

    View full-size slide

  15. Low interaction
    Design for big gestures

    View full-size slide

  16. Low interaction
    Design for big gestures

    View full-size slide

  17. Favour non
    error-prone input
    fullscreen tap/swipe
    voice actions

    View full-size slide

  18. Simplified Activity
    lifecycle
    Device goes to sleep → Activity destroyed

    View full-size slide

  19. Think your app as a row of
    cards in a grid

    View full-size slide

  20. Understanding the
    Android Wear ecosystem

    View full-size slide

  21. 1 device - 1 OS

    View full-size slide

  22. 1 device - 1 OS
    No shared code
    No shared resources

    View full-size slide

  23. Different code base
    Different applications
    1 device - 1 OS

    View full-size slide

  24. Google
    Play Services

    View full-size slide

  25. No Play Store
    on Android Wear

    View full-size slide

  26. Imbricated APKs
    for distribution
    An APK in an APK…

    View full-size slide

  27. Play Store
    Wearable

    View full-size slide

  28. Play Store
    Wearable

    View full-size slide

  29. Play Store
    Wearable

    View full-size slide

  30. Developing for
    Android Wear devices

    View full-size slide

  31. 2 possibilities
    Notifications Custom app
    |

    View full-size slide

  32. If your app already uses notifications,
    you have nothing to do

    View full-size slide

  33. If your app already uses notifications,
    you have nothing to do
    almost

    View full-size slide

  34. final Intent detailsIntent = DetailsActivity.

    newIntent(this, travelId);

    final PendingIntent detailPendingIntent = PendingIntent.

    getActivity(this, 0, detailsIntent, 0);


    final NotificationCompat.Builder builder = new NotificationCompat.Builder(this).

    setSmallIcon(R.drawable.ic_status_capitaine).

    setContentTitle(travelTitle).

    setContentIntent(detailPendingIntent);


    final Notification notif = new NotificationCompat.BigTextStyle(builder).

    bigText(travelDescription).

    build();


    NotificationManagerCompat.from(this).notify(NOTIFICATION_ID, notif);

    View full-size slide

  35. Wearable specific notifications
    WearableExtender to the rescue

    View full-size slide

  36. final Bitmap background = 

    BitmapFactory.decodeResource(

    getResources(), R.drawable.paris);


    builder.extend(new NotificationCompat.

    WearableExtender().setBackground(background));

    View full-size slide

  37. Stacks
    setGroup()
    setSortKey()
    setGroupSummary()

    View full-size slide

  38. Pages
    addPage(Notification)

    View full-size slide

  39. Pages
    addPage(Notification)

    View full-size slide

  40. Voice input
    RemoteInput

    View full-size slide

  41. There are some case where
    notifications are not enough

    View full-size slide

  42. Wearable apps are
    fundamentally the same as
    apps built for other devices

    View full-size slide

  43. android.webkit
    android.print
    android.app.backup
    android.appwidget
    android.hardware.usb
    Unsupported APIs

    View full-size slide

  44. NodeApi
    Learn about local &
    connected nodes
    MessageApi
    Send messages on
    a “fire & forget” basis
    DataApi
    Sync data between
    nodes on the network

    View full-size slide

  45. Handheld - ReminderService.java
    final Notification notification = new NotificationCompat.Builder(context).

    // ...
    setLocalOnly(true).

    // ...

    build();

    View full-size slide

  46. if (mGoogleApiClient == null) {

    mGoogleApiClient = new GoogleApiClient.Builder(this).

    addApi(Wearable.API).

    addOnConnectionFailedListener(mOnConnectionFailedListener).

    addConnectionCallbacks(mConnectionCallbacks).

    build();

    }

    mGoogleApiClient.connect();


    private final GoogleApiClient.OnConnectionFailedListener mOnConnectionFailedListener

    = new GoogleApiClient.OnConnectionFailedListener() {

    @Override

    public void onConnectionFailed(ConnectionResult connectionResult) { /* ... */ }

    };


    private final GoogleApiClient.ConnectionCallbacks mConnectionCallbacks = 

    new GoogleApiClient.ConnectionCallbacks() {

    @Override

    public void onConnected(Bundle bundle) { /* TODO */ }


    @Override

    public void onConnectionSuspended(int i) { /* ... */ }

    };
    Handheld - ReminderService.java

    View full-size slide

  47. Handheld - ReminderService.java
    @Override

    public void onConnected(Bundle bundle) {


    final PutDataMapRequest request = PutDataMapRequest.

    create("/show-reminder/travel");

    final DataMap map = request.getDataMap();


    map.putString("departureStation", departureStation);

    map.putString("arrivalStation", arrivalStation);

    map.putString("barcodeData", barcodeData);
    // ...


    Wearable.DataApi.putDataItem(mGoogleApiClient, request.asPutDataRequest()).

    setResultCallback(new ResultCallback() {

    @Override

    public void onResult(DataApi.DataItemResult dataItemResult) {

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

    // Deal with errors

    }

    }

    });

    }

    View full-size slide

  48. Wearable - ReminderReceiverService.java
    public class ReminderReceiverService extends WearableListenerService {


    @Override

    public void onDataChanged(DataEventBuffer dataEvents) {

    super.onDataChanged(dataEvents);

    for (DataEvent dataEvent : dataEvents) {

    final Uri uri = dataEvent.getDataItem().getUri();

    final DataMap dataMap = DataMapItem.
    fromDataItem(dataEvent.getDataItem()).getDataMap();

    switch (dataEvent.getType()) {

    case DataEvent.TYPE_CHANGED:

    onDataEventChanged(uri, dataMap);

    break;


    case DataEvent.TYPE_DELETED:

    onDataEventDeleted(uri, dataMap);

    break;

    }

    }

    }


    protected void onDataEventChanged(Uri uri, DataMap dataMap) { /* TODO */ }

    protected void onDataEventDeleted(Uri uri, DataMap dataMap) { /* TODO */ }

    }

    View full-size slide

  49. Wearable - ReminderReceiverService.java
    @Override

    protected void onDataEventChanged(Uri uri, DataMap dataMap) {

    final List segments = uri.getPathSegments();

    if (segments != null && segments.size() > 1 && "show-reminder".equals(segments.get(0))) {

    final String notificationId = segments.get(1);


    final String departureStation = dataMap.getString("departureStation");

    final String arrivalStation = dataMap.getString("arrivalStation");

    final String barcodeData = dataMap.getString("barcodeData");

    // ...


    final Notification notification = new NotificationCompat.Builder(this).

    setLocalOnly(true).

    // ...

    build();


    mNotificationManager.notify(notificationId, NOTIFICATION_ID, notification);

    }

    }

    View full-size slide

  50. Wearable - ReminderReceiverService.java
    @Override

    protected void onDataEventDeleted(Uri uri, DataMap dataMap) {

    final List segments = uri.getPathSegments();

    if (segments != null && segments.size() > 1 && "show-reminder".equals(segments.get(0))) {

    final String notificationId = segments.get(1);

    mNotificationManager.cancel(notificationId, REMINDER_NOTIFICATION_ID);

    }

    }

    View full-size slide

  51. android {

    // ...

    }


    dependencies {
    // ...

    wearApp project(':wearable')

    }
    Packaging wearable apps
    a simple Gradle dependency

    View full-size slide

  52. Design from scratch
    Do not create a small version of your handheld
    app. Start a completely new design process

    View full-size slide

  53. Think “cards” first
    Always think about the notification cards
    pattern first. The wear app pattern is a fallback

    View full-size slide

  54. Keep simplicity in mind
    Your wearables apps should be as rudimentary
    as interactions with these devices are

    View full-size slide

  55. Thank you!
    @cyrilmottier
    cyrilmottier.com

    View full-size slide

  56. Fonts
    Source Sans Pro
    Menlo
    Resources
    Dressed for Iceland • Cécile Bernard
    Moelwynion, Eryri, Cymru • Marc Poppleton

    View full-size slide