Android Wear 리뷰

디자이너와 개발자 모두를 위한 리뷰

marojun
marojun’s Android

--

해당 포스트는 디벨로퍼 프리뷰https://medium.com/p/5ee24c941aec를 기준으로 작성하였습니다. ☺

Android Wear는 기계가 아닌 패션이다

Android Wear SDK에 대한 글이 올라오자마자 UI 가이드라인이 포함된 디벨로퍼 프리뷰를 살펴보았다. 부디 이 글이 디자이너와 개발자 모두에게 도움이 되었으면 한다.

손목 시계의 인터페이스를 디자인 한다는 것은 무엇이라 생각하는가? 단순히 착용 가능한 모바일 인터페이스라고 생각하면 안된다. 이것은 UI, UX 디자이너들에게는 지금까지와는 완전히 새로운 차원

바로 패션이기 때문이다!

앞으로 우리가 이것을 뭐라고 부르게 될지는 모르겠지만 Android Wear SDK가 나왔으니 디자이너들은 왜 사람들이 손목 시계를 차는지에 대해 고민할때다.

컬러 ? 사이즈? 모양? 굵기? 남자용 혹은 여자용? 보석 장식? 착용시간? (낮 혹은 밤)

Fossil Group, Inc. ($FOSL) 이나 Motorola의 군더더기 없는 Moto 360 시계 등 글로벌 패션 파트너들이 구글 안드로이드 플랫폼 개발을 지원하는 만큼, 앞으로 인터페이스 디자인에 있어 패션이 하나의 중요한 요소가 될 것을 반드시 인지해야한다.

Android Wear Overview

Android Wear를 살펴보면 직사각형과 원형 2가지를 제공하고 있지만 개인적으로 손목시계라는 것을 생각해보면 원형의 인터페이스가 더 나을 것으로 생각된다.

휴대용 시계와 손목 시계는 수백년 전부터 시작해 많은 사람들에 의해 대대로 내려왔다. 아래 Motorola’s Moto360은 그 정신을 이어 손목 시계의 가치를 가장 잘 반영한 것 같다.

http://youtu.be/dnerqDWwVgg

Android Ware: Information that moves you

http://youtu.be/QrqZl2QIz0c

Android Wear is smart.

Android Wear의 명제는 사람들이 손목시계에서 주로 사용하는 두개의 주된 기능을 토대로 디자인하는 것이다.

1. Suggest — The Context Stream

Simple Navigation: Vertical Swipe to browse cards of content categories; Horizontal Swipe to dive into the cards.

유저가 무엇을 필요로하고 원하는지를 아는 것은 인터페이스 디자인에 있어 매우 중요하다. 이러한 점을 고려했을때 서비스에 Google Now를 접목시킬 방안을 고민해야 하며, 디바이스의 센서와 API를 통합함으로서 유저가 몇분 뒤 무엇이 필요로 할지 예측하여 실행 가능한 이벤트 플로우를 만들도록 하는데 이것을 “컨텍스트 스트림” 이라고 한다.

컨텍스트 스트림 네비게이션 — 인터페이스를 사용하는 방법은 꽤 쉽다. 유저들은 특정 시간이나 위치를 통해 제공된 카드 리스트를 위 아래로 스와이핑하여 살펴볼 수 있다.

분당에 사는 유저가 어느 더운 여름 날 집으로 가고 있다고 생각해보자, 카드는 집에 도착하기 10분 전에 알아서 “외출중” 에서 “냉방”으로(집의 온도를 낮추기 위해) 보여질 것이다.

위의 예시처럼 API는 유저들의 생활을 개선하도록 예측 할 수 있는 애플리케이션을 디자인 할 수 있게 해준다. 시간은 유저가 평소에 집에 도착하는 특정 시간을 알려주고, GPS는 유저가 어디에 있는지, 집으로 가고 있는중인지를 확인해주고, 날씨 데이터는 얼마나 더운지를 알려주며, 교통 데이터는 집에 도착할 때 까지 얼마나 걸리는 지를 알려준다. 이러한 조건을 통해 시계에 해당 Card가 제공되는 것이다.

2. Demand: The Cue Card

The cue card is opened by saying, “Okay Google” or by tapping on the “g” icon on the home screen.

컨텍스트 스트림을 사용할 수 없을 때는 유저가 스스로 실행 가능한 큐 카드 리스트를 브라우징 함으로써 바로 이벤트를 생성할 수 있다.

단순히 “Okay Google” 이라고 얘기하거나 홈스크린의 “g” 버튼을 누름으로써 이벤트를 생성할 수 있는 리스트가 나타난다. 이 리스트도 역시 음성이나 터치로 실행 할 수 있다.

Preview

여기서부터 Android Wear에 대해서 디자이너와 개발자들이 주목해야 내용을 소개한다.

Android Wear의 UI 가이드라인에 대해 더 배우고 싶다면 아래 내용을 통해 네비게이션, 스타일, 보이스 인터렉션에 대해 알아보자.

Design Principles of Android Wear

가이드라인에서의 디자인 원칙들은 매우 명확하다.

Android Wear experiences are:

  • 컨텍스트를 이해하며 스마트하다. Wear에서의 동작은 완전히 새로운 레벨의 이해력을 요구한다. 유저가 인지하여 실행하기보다는 상황이나 상태 그리고 시간에 맞는 정보를 제공한다.
  • 빨리 한눈에 읽힌다. 사용자가 늘 집중해서 Wear를 보고있지 않기때문에 최소의 동작으로 최대의 정보를 제공할 수 있도록 최적화 되어야 한다.
  • 최소한의 인터렉션. 작은 크기로써의 강점을 살려, Wear 는 심플한 인터렉션에 집중한다. 따라서, 유저가 정말로 필요할때에만 입력을 요구한다. 대부분의 입력은 터치 스와이핑이나 음성 명령으로 사용 가능하며, 복잡한 입력은 없다.
  • 유용함. Wear 는 훌륭한 개인 비서다. 유저와 취향을 알며 꼭 필요할 때에만 정보를 제공하고, 언제든 준비되어 있다.

Notifications and Actions

모든 알림들은 콘텍스트 스트림의 카드 형태로 나타나며, 이것은 주로 “Okay Google, Reply” 라는 음성 명령이나 가로 스와이핑을 통해 실행된다.

Notifications

메지시가 알림으로 도착했을때 내용이 너무 많아 한 화면에 표현이 안될 수 있다. 이 경우 Wear는 자동으로 메시지의 일부분만 보여준다. 이 후 사용자가 메시지의 하단을 누르면 나머지 부분이 보여진다.

알림에는 우선순위가 있다. 이는 해당 알림이 사용자에게 꼭 필요한 것인가에 따라 알림의 우선순위가 정해진다. 진동을 통한 알림은 사용자가 바로 인지해야하거나 어떤 해야하는 우선순위가 높은 알림에만 동작하도록 해야한다. 이외의 경우에는 (예를 들어 교통 시간표 업데이트, 현재까지의 걸음 수, 소셜 컨텐츠가 업데이트 된 경우) 조용히 스트림에만 추가되도록 해야할 것이다.

Wear의 알림 대부분은 Android Design guidelines for notifications 을 기반으로 이루어지므로 참조하도록 하자.

Notification of a text message followed by the reply action.

알림 카드 디자인은 다음과 같은 요소로 이루어진다.

  • 백그라운드 이미지 — HDPI 이미지는 알림 메시지 뒤에 깔리고, 최소 사이즈는 320x320 pixels 이다. 또한 Google Map 이미지나, 주소록에 저장되어 있는 프로필 이미지, 또는 단색의 백그라운드를 띄울 수 있다. 여기서 백그라운드는 좌우로 스와이핑되기 때문에 가로방향으로 되어있는 이미지를 사용하는 것을 추천한다.
  • 애플리케이션 아이콘 — 어떤 서비스의 알림인지를 나타내며 알림 카드의 우측 상단에 위치한다. 애플리케이션 아이콘은 노출되지 않도록 설정할 수도 있다.
Big View example, where the user may scroll extended text content.
  • 타이틀과 메시지- 인터페이스의 중요한 부분이며 짧고, 명확하다. 기본적으로 적용되는 “big view” 스타일을 통해 메시지가 길 경우메시지의 하단을 터치하여 확장해 볼 수 있다. 메시지를 확장하기 전에는 기본적으로 3줄만 보인다.

해당 화면을 구성하는 코드를 살펴 보자.

BigTextStyle bigStyle = new NotificationCompat.BigTextStyle();
bigStyle.bigText(eventDescription);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_event) // 어플리케이션 아이콘
.setLargeIcon(BitmapFractory.decodeResource( // 백그라운드 이미지
getResources(), R.drawable.notif_background))
.setContentTitle(eventTitle) // 타이틀
.setContentText(eventLocation) // 본문내용
.setContentIntent(viewPendingIntent)
.addAction(R.drawable.ic_map, // 액션에 대한 아이콘, 텍스트 및 액션 정의
getString(R.string.map), mapPendingIntent)
.setStyle(bigStyle); // 빅 스타일로 설정

이외에도 다양한 종류의 알림들이 존재한다.

basic : 일반적인 알림.

inbox : 라인별로 문자를 설정 할 수 있는 알림. (최대 5줄 표현)

NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle();// 라인별 노출될 텍스트를 정의한다.
style.addLine(context.getString(R.string.inbox_style_example_line1));
style.addLine(context.getString(R.string.inbox_style_example_line2));
style.addLine(context.getString(R.string.inbox_style_example_line3));
style.setBigContentTitle(context.getString(R.string.inbox_style_example_title));
style.setSummaryText(context.getString(R.string.inbox_style_example_summary_text));
WearableNotifications.Builder builder = buildBasicNotification(context, options);
builder.getCompatBuilder().setStyle(style);

Big picture : 큰 사진이 첨부되었을 경우 사용하는 알림.

 NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
style.bigPicture(BitmapFactory.decodeResource(context.getResources(),
R.drawable.example_big_picture));
style.setBigContentTitle(context.getString(R.string.big_picture_style_example_title));
style.setSummaryText(context.getString(
R.string.big_picture_style_example_summary_text));
WearableNotifications.Builder builder = buildBasicNotification(context, options);
builder.getCompatBuilder().setStyle(style);
return new Notification[]{builder.build()};

Big text : 텍스트가 많을 경우 사용하는 알림.

NotificationCompat.BigTextStyle style = new NotificationCompat.BigTextStyle();
style.bigText(context.getString(R.string.big_text_example_big_text));
style.setBigContentTitle(context.getString(R.string.big_text_example_title));
style.setSummaryText(context.getString(R.string.big_text_example_summary_text));
WearableNotifications.Builder builder = buildBasicNotification(context, options);
builder.getCompatBuilder().setStyle(style);
return new Notification[]{builder.build()};

Big action : 별도의 액션페이지가 아니라 본문 자체를 클릭하면 이벤트가 발생하도록 하는 알림.

 WearableNotifications.Builder builder = buildBasicNotification(context, options) .setBigActionIcon(R.mipmap.ic_app_notification_studio, context.getString(R.string.icon_subtext)) .setHintHideIcon(true); builder.getCompatBuilder().setContentIntent(NotificationUtil.getExamplePendingIntent(context, R.string.content_intent_clicked));

Multiple page : 여러 페이지를 노출해주는 알림.

Notification secondPage = new NotificationCompat.Builder(context).setContentTitle(context.getString(R.string.second_page_content_title)).setContentTitle(context.getString(R.string.second_page_content_title)).setContentText(context.getString(R.string.second_page_content_text)).build(); Notification notification = buildBasicNotification(context, options).addPage(secondPage).build();

Notification bundle : 액션 페이지 클릭시 어떤 이벤트가 발생할지를 정의하는 알림. (Big action은 메인 페이지 자체에서 이벤트가 발생한다.)

참고로 현재 프리뷰 버전은 한글을 지원하지 않는지 글자 표현이 제대로 안되는 문제가 있다.

  • 액션 버튼 — 이메일 답변 등, 텍스트를 써야하는 액션이 있다면 음성 명령을 통해 답변 할 수 있다. 또한, 유저들이 미리 설정 된 텍스트로 답변을 선택할 수도 있다.
User can dictate a reply or select one of the pre-defined text replies.
// 액션버튼 클릭 시 전달받은 위치를 기준으로 브라우저의 구글맵에 나타나도록 하는 코드Intent mapIntent = new Intent(Intent.ACTION_VIEW);
Uri geoUri = Uri.parse(“geo:0,0?q=” + Uri.encode(location));
mapIntent.setData(geoUri);
PendingIntent mapPendingIntent =
PendingIntent.getActivity(this, 0, mapIntent, 0);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_event)
.setContentTitle(eventTitle)
.setContentText(eventLocation)
.setContentIntent(viewPendingIntent)
.addAction(R.drawable.ic_map,// 액션버튼 아이콘
getString(R.string.map), mapPendingIntent); // 액션버튼 텍스트와 동작 정의
  • 페이지 — 아니면 “Secondary Pages(두번째 페이지)”라고 칭해야 할까? — 페이지는 스트림의 메인 카드 우측에서 나타나는 추가적 카드를 말한다. (메인에서 오른쪽으로 스와이프 하면 나타난다. 아래 인디케이터를 통해 페이지가 더 있음을 확인할 수 있다.) 만약 주요 메시지가 길다면, 한 페이지에 너무 많은 정보를 노출해 가독성을 희생시키진 말자. 대신, 새로운 페이지를 추가하여 추가적인 정보를 제공 하도록한다.
Actionable Workflow using a card with a glance of the note followed by the additional content using Page, then the action.
// 메인 알림을 정의한다.
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.new_message)
.setContentTitle(“Page 1")
.setContentText(“Short message”)
.setContentIntent(viewPendingIntent);
// 두번째 페이지를 BigTextStyle로 지정한다.
BigTextStyle secondPageStyle = new NotificationCompat.BigTextStyle();
secondPageStyle.setBigContentTitle(“Page 2")
.bigText(“A lot of text…”);
// 두번째 알림을 정의한다.바로 위에서 지정한 스타일을 setStyle()을 통해 반영한다.
Notification secondPageNotification =
new NotificationCompat.Builder(this)
.setStyle(secondPageStyle)
.build();
// addPage 메서드를 통해 위에서 정의한 2번째 페이지가 노출되도록 한다.
Notification twoPageNotification =
new WearableNotifications.Builder(notificationBuilder)
.addPage(secondPageNotification)
.build();
  • 알림 스택 — 알림 스택은 화면을 복잡하게 하지 않고 여러개의 아이콘을 그룹화 할 수 있는 방법이다. 만약 애플리케이션에서 여러개의 알림이 존재할 경우, 스택으로 합치는 방안을 고려하자.
Notification Stacks or “bundles” collapsed followed by an expanded view.
// 그룹을 통해 스택화 시킬 수 있다.final static String GROUP_KEY_EMAILS = “group_key_emails”;NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
.setContentTitle(“New mail from “ + sender)
.setContentText(subject)
.setSmallIcon(R.drawable.new_mail);
Notification notif = new WearableNotifications.Builder(builder)
.setGroup(GROUP_KEY_EMAILS)
.build();
  • 음성 답변 — 음성 답변은 주로 손을 사용하지 않고 짧은 메시지를 작성할 때 메시지 애플리케이션에 의해 쓰인다. 최대 다섯 개의 추천 답변을 제공할 수 있고, 아니면 다양한 상황에 적합한 답변들을 저장해 둘 수 있다.
You should attempt to cover a range of simple, neutral replies in your choices. Longer voice replies may be automatically truncated in the Voice reply UI.
// 답변들을 string-array형태로 미리 지정해놓고 setChoices()를 통해 사용할 수 있다.<?xml version=”1.0" encoding=”utf-8"?>
<resources>
<string-array name=”reply_choices”>
<item>Yes</item>
<item>No</item>
<item>Maybe</item>
</string-array>
</resources>
String replyLabel = getResources().getString(R.string.reply_label);
String[] replyChoices = getResources().getStringArray(R.array.reply_choices);
RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
.setLabel(replyLabel)
.setChoices(replyChoices)
.build();

Keep the discussion on going

디자이너와 개발자들을 위해 휴먼 인터페이스에 한 획을 그을 Android Wear를 리뷰하는 내내 흥미진진했다. 이 글이 부디 여러분에게 영감을 줄 수 있으면 한다.

--

--

marojun
marojun’s Android

전슬마로. KTH, SK Planet, NCSOFT 에서 iOS와 Android를 개발하고 있다. — 안드로이드 개발 그룹 https://www.facebook.com/groups/junsle/