Google I/O 2016: WatchFace 2.0 — Complications

Привіт, Хабр! Зовсім недавно пройшов Google I/O (якщо хто пропустив наш репортаж — вам сюди), де побачив світ новий API для відображення даних на циферблатах годинників. Назва його прийшло з годинної галузі: по-російськи їх традиційно звуть «Ускладнення», ну а по-англійськи —«Complications».



Якщо коротко — це механізм відображення якої-небудь додаткової інформації на годиннику, крім, власне часу: в реальних можуть бути всякі планети-зірки-календарі, ну а в нашому випадку — все, що прийде вам в голову. Сьогодні ми покажемо, на що здатний API Watch Face Complications і як з ним працювати.



Прим.: текст і огляд API підготував для вас лідер GDG Ростова-на-Дону Олександр Куліковський, далі весь текст від його імені. :)



Знайомимося з WatchFace 2.0
Привіт, я Олександр Куліковський, займаюся розробкою для Android з 2010 року. На даний момент працюю в компанії Sebbia на посаді Senior Android Engineer і очолюю GDG Ростова-на-Дону.

Приступаємо до роботи

Отже, щоб спробувати нові можливості Android Watch 2.0 нам знадобиться чистий проект. Створюємо його, вказуємо API N в якості мінімальної версії SDK (minSdk) для телефону і годинника.


Activity для телефону нам не потрібна, тому вибираємо шаблон «no Add activity». Для годинника ж візьмемо стандартний шаблон Watch Face. Дамо ім'я сервісу ComplicationWatchFaceService, стиль — аналоговий.



Після цього отримаємо стандартний проект.

Перед тим як продовжимо, нам необхідно переконатися в тому, що в gradle-файл, що описує модуль wear, в розділі залежностей wearable підключені не нижче версії 2.0.0:
compile 'com.google.android.support:wearable:2.0.0-alpha1'


Підключаємо «Ускладнення»

Додаємо complication до нашого watchface. В реальному додатку, користувач зможе вибирати джерела інформації для отримання complication-даних, нам же треба забезпечити отримання та відображення такого роду інформації.

Щоб почати отримувати complication-дані, ми вызваем метод setActiveComplications ComplicationWatchFaceService.Engine, і отримуємо список ідентифікаторів посадочних місць для відображення інформації:
// Unique IDs for each complication.
private static final int LEFT_DIAL_COMPLICATION = 0;
private static final int RIGHT_DIAL_COMPLICATION = 1;

// Left and right complication IDs as array for Complication API.
public static final int[] COMPLICATION_IDS = {LEFT_DIAL_COMPLICATION, RIGHT_DIAL_COMPLICATION};

....
public void onCreate(SurfaceHolder holder) {
...
setActiveComplications(COMPLICATION_IDS);
...
}

Дані для відображення приходять в методі onComplicationDataUpdate нашого ComplicationWatchFaceService.Engine.


Це важливо:

спецификации ми вільні відображати отримані дані як завгодно, але для кожного типу даних є набір обов'язкових полів для відображення. Більш детально про це можна подивитися в таблице.


Повертаємося до нашого прикладу. Метод onComplicationDataUpdate дав нам набір даних, які ми можемо відобразити. Так какотрисовка нашого watchface відбувається тільки в методі onDraw, то отримані дані треба попередньо кудись зберегти. Для цього створимо SparseArray<ComplicationData>, ініціалізуємо його в onCreate і будемо всі значення складати в нього в методі onComplicationDataUpdate:
@Override
public void onComplicationDataUpdate(int watchFaceComplicationId, ComplicationData data) {
super.onComplicationDataUpdate(watchFaceComplicationId, data);
mActiveComplicationDataSparseArray.put(watchFaceComplicationId, data);
invalidate();
}

Саме малювання на canvas'е нам не цікава — про це вже сто разів розповідали. А ось на що треба звернути увагу, так це на те, звідки, власне, взяти дані, які ми будемо показувати. У випадку з TYPE_SHORT_TEXT код буде виглядати наступним чином:

private void drawComplications(Canvas canvas, long currentTimeMillis) {
ComplicationData complicationData;

for (int i = 0; i < COMPLICATION_IDS.length; i++) {

complicationData = mActiveComplicationDataSparseArray.get(COMPLICATION_IDS[i]);

if ((complicationData != null)
&& (complicationData.isActive(currentTimeMillis))
&& (complicationData.getType() == ComplicationData.TYPE_SHORT_TEXT)) {

ComplicationText mainText = complicationData.getShortText();
ComplicationText subText = complicationData.getShortTitle();

CharSequence complicationMessage =
mainText.getText(getApplicationContext(), currentTimeMillis);

if (subText != null) {
complicationMessage = TextUtils.concat(
complicationMessage,
" ",
subText.getText(getApplicationContext(), currentTimeMillis));
}
........

Але тепер, якщо запустити проект, ми ніяких complications не побачимо. А все тому, що користувач не поставив джерела інформації для відображення. Тому що не міг — меню налаштувань-то ми йому не виділили… Виправимо це: створимо актівіті налаштувань і пропишемо її в маніфесті:

<service
....
<meta-data
android:name="com.google.android.wearable.watchface.wearableConfigurationAction" android:value="com.example.complicationwatchface.CONFIG_COMPLICATION_SIMPLE"/>
....
</service>
<activity
android:name=".ComplicationConfigActivity"
android:label="@string/complication_simple">
<intent-filter>
<action android:name="com.example.complicationwatchface.CONFIG_COMPLICATION_SIMPLE"/>
<category android:name="com.google.android.wearable.watchface.category.WEARABLE_CONFIGURATION"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>

В даній актівіті ми відобразимо список інформації про доступні посадочних місцях для complications, апо кліку на елемент будемо запускати стандартний екран вибору доступних джерел даних:

Integer tag = (Integer) viewHolder.itemView.getTag();
ComplicationItem complicationItem = mAdapter.getItem(tag);

startActivityForResult(ProviderChooserIntent.createProviderChooserIntent(
complicationItem.watchFace,
complicationItem.complicationId,
complicationItem.supportedTypes), PROVIDER_CHOOSER_REQUEST_CODE);


Якщо ви все зробили правильно, то в результаті в момент вибору у вас вийде приблизно така картина:



Перевіримо інтерфейс у справі: вибираємо для лівого complication відображення дати, а для правого — просто довільне число.

Тепер, як тільки з'являться нові дані в вибраних користувачем джерелах інформації, буде викликаний метод onCompliationDataUpdate, всі дані будуть збережені в SparseArray і при наступному виклику onDraw будуть відображені на екрані нашого циферблата.

Як бачите, робота з ускладненнями» максимально проста: десяток-інший рядків коду, і все працює. Справа за малим — оновити ваші проекти і додати підтримку нових можливостей. Удачі!
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.