Думаю, всем кто интересуется Google Glass известно, что представляет собой программная “начинка” этого гаджета. Да, это Android 4 с адаптированным launcher-ом. Да, в “очках” вполне можно запускать обычные android-приложения, установив их туда через adb. Известно вам наверняка и про Mirror API, который до недавнего времени считался единственным способом официально предоставить свой сервис пользователю Google Glass. Ниже я немного расскажу о использовании этого инструмента. Но главное, о чём хотелось бы рассказать — как писать под Google Glass полноценные android-приложения, используя пока ещё не официальный Glass Development Kit.
Итак, для начала, сделаем себе Google Glass
Если вы не попали в число избранных обладателей революционного гаджета, не отчаивайтесь. Почти настоящий Google Glass вы сможете сделать из своего android-смартфона или планшета, установив на него launcher и несколько сопутствующих apk отсюда. Вы получите полноценный интерфейс с timeline-карточками, нормально работающее распознавание голосовых команд, bluetooth, кое-как работающую камеру (удалось нормально запустить только на Nexus 7) звук и Hangouts в придачу. С навигацией как-то не сложилось, но возможно у вас получится лучше. При первом запуске launcher запросит доступ к вашему аккаунту как обычное приложение. Даём ему права и становимся почти настоящим Glass Explorer-ом. По крайней мере вы сможете себе отправлять timeline-карточки через Mirror API.
Почему Goggle даёт Mirror API только владельцам Google Glass?
Что сделает нормальный программист, получив доступ к новому инструменту? Конечно же, начнёт писать код. Затем — тестировать. А когда багов вроде бы не останется — опубликует так или иначе своё детище. Это нормально везде, только не в Google Glass. На этой платформе пользователь не переключает внимание между реальным и виртуальным миром. Google Glass в этом смысле — уникальный инструмент. Не пользующийся “очками” программист скорее всего не сможет сделать своё приложение достаточно ненавязчивым и одновременно функциональным, особенно поначалу. Пользовательский опыт Glass Explorer-а в полной мере гайдлайнами не заменяется. Вероятно для того чтобы оградить пока ещё крошечное сообщество “носителей” Google Glass от тонны неприятных и навязчивых приложений Google и “прячет” Mirror API.
Но, допустим, доступ у вас есть. Что мы можем делать с его помощью?
Публикуем и подписываемся без гарантии сроков доставки
Основная парадигма интерфейса Google Glass — это Timeline. Справа от “домашнего” экрана с часами и голосовым вводом — бесконечная лента карточек уходящих в прошлое. Все приложения, использующие Mirror API публикуют туда свои карточки в хронологическом порядке и могут подписываться на события, которые с этими карточками происходят.
События пользователь генерирует с помощью элементов меню, привязанных к карточке. Карточка может содержать как предопределённые элементы меню, например “Delete” или “Share” а также определённые приложением. Карточка может содержать вложенные карточки. Схема организации таких “пакетов” достаточно примитивна и не позволяет делать многоуровневые конструкции. Мы назначаем серии карточек один и тот же bundleId а той карточке, что должна быть “обложкой” устанавливаем isBundleCover=true. При этом меню “обложки” становится недоступным. Использовать его снова пользователь сможет только если удалит все вложенные карточки.
Карточки могут располагаться и слева от “домашнего” экрана. Это “закреплённые” карточки. Вы можете попытаться добавить такую карточку через Mirror API, установив свойство isPinned=true но у вас, скорее всего, ничего не выйдет. Mirror API всё равно свалит вашу карточку в общую ленту. Впрочем, решение есть: добавляем в опции меню с action TOGGLE_PINNED и пользователь сам, если сочтёт нужным, закрепит вашу карточку. Обновление карточки уже не будет влиять на её состояние — она так и останется закреплённой пока вы или пользователь не удалите её или пользователь не сделает ей UnPin той же опцией в меню.
Это, понятно, не всё, что вы можете делать с помощью Mirror API. Вы можете добавить пользователю “контакт” вашего приложения, давая тем самым возможность ему шарить вам фото или видео. Карточки могут включать вложения. Есть куча особенностей в формировании внешнего вида этих самых карточек. Оставлю тут только ссылки на пару полезных ресурсов, где всё это вы можете попробовать. APIs Explorer даст вам возможность тренироваться в общении с Mirror API, а playground позволит “подизайнить” карточки.
Важно же данном случае другое: вы НИКАК не сможете сделать с помощью Mirror API интерактивное приложение. Пользователь может что-то сделать в вашем “интерфейсе” но вы не можете быть уверены в том, когда это событие вам доставит Google. Вы можете что-то показать пользователю. Но вы никак не сможете предвидеть, когда пользователь получит ваше “послание”. Большинство великолепных идей приложений просто принципиально не реализуемы с помощью Mirror API. Это надо понимать. И с этим надо смириться.
Как же сделать что-то интерактивное?
И тут нам на помощь приходит Glass Development Kit. Официально он уже разрешён, хотя ещё не опубликован. Google призывает использовать обычный Android SDK. Можно и так, но не стоит забывать о весьма необычных свойствах Google Glass в плане “пользовательского ввода”. У нас нет кнопок. Нет touch-панели в привычном нам смысле. То, по чему Glass Explorer-ы “тапают” и “свайпают” понимает только жесты. OnTouch на нём поймать не получится. У нас нет возможности перехватить долгое нажатие а жест сверху вниз зарезервирован и ловится в приложении как onBackPressed. Выручают, как ни странно, сенсоры. Кивок и поворот головы для этого устройства — вполне достойная замена кнопкам. С голосовым вводом, который должен заменять всё, пока не так хорошо как хотелось бы. По крайней мере у меня пока не получилось добавлять свои команды и получать события при их распознавании. Но, возможно, я недостаточно старался и у вас получится лучше.
В общем, делается это как-то так
Находим какое-нибудь нативное приложение для Google Glass, например это. Берём оттуда glasslib.jar, который, предположительно и есть подобие того, что потом будет опубликовано как GDK. Добавляем его в свой проект и получаем возможность манипулировать timline-карточками так же, как и через Mirror API. Только есть два существенных преимущества. Никаких задержек и никаких ограничений. Если вы теперь сделаете карточке isPinned(true), то она послушно станет слева от “домашнего” экрана без всякого участия пользователя. Работаем с Timline через TimlineHelper и обязательно из сервиса. Обычная схема такая: у приложения есть только одно Activity, которое стартует Service при старте и завершается. Также не помешает подписаться на событие загрузки устройства и из BroadcastReceiver-а опять-таки поднимать наш сервис. В Service проверяем есть ли у пользователя карточка нашего приложения (для этого хорошо бы хранить её Id в SharedPreferences) удаляем старую и добавляем новую, опять же сохраняем её Id.
import android.app.Service; import android.content.ContentResolver; import android.content.Intent; import android.content.SharedPreferences; import android.os.IBinder; import android.preference.PreferenceManager; import com.google.glass.location.GlassLocationManager; import com.google.glass.timeline.TimelineHelper; import com.google.glass.timeline.TimelineProvider; import com.google.glass.util.SettingsSecure; import com.google.googlex.glass.common.proto.MenuItem; import com.google.googlex.glass.common.proto.MenuValue; import com.google.googlex.glass.common.proto.TimelineItem; import java.util.UUID; public class GlassService extends Service { private static final String HOME_CARD = "home_card"; @Override public int onStartCommand(Intent intent, int flags, int startid){ super.onStartCommand(intent, flags, startid); GlassLocationManager.init(this); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); String homeCardId = preferences.getString(HOME_CARD, null); TimelineHelper tlHelper = new TimelineHelper(); ContentResolver cr = getContentResolver(); if(homeCardId != null){ // find and delete previous home card TimelineItem timelineItem = tlHelper.queryTimelineItem(cr, homeCardId); if (timelineItem!=null && !timelineItem.getIsDeleted()) tlHelper.deleteTimelineItem(this, timelineItem); } // create new home card String id = UUID.randomUUID().toString(); MenuItem delOption = MenuItem.newBuilder().setAction(MenuItem.Action.DELETE).build(); MenuItem customOption = MenuItem.newBuilder().addValue(MenuValue.newBuilder().setDisplayName("Custom").build()).setAction(MenuItem.Action.BROADCAST).setBroadcastAction("net.multipi.TEST_ACTION").build(); TimelineItem.Builder builder = tlHelper.createTimelineItemBuilder(this, new SettingsSecure(cr)); TimelineItem item = builder.setId(id).setText("Hello, world!").setIsPinned(true).addMenuItem(customOption).addMenuItem(delOption).build(); cr.insert(TimelineProvider.TIMELINE_URI, TimelineHelper.toContentValues(item)); preferences.edit().putString(HOME_CARD, id).commit(); return START_NOT_STICKY; } @Override public IBinder onBind(Intent intent){ return null; } }
Как видно выше, наша карточка снабжена меню из двух пунктов: Delete и Custom. И если первый обрабатывает система, послушно удаляя карточку, то второй бросит нам broadcast, который мы можем поймать и обработать.
Чтобы не останавливаться на банальном «Hello, world» я сделал небольшой проект. Можете использовать его как более расширенный материал для изучения особенностей «нативной» работы с Google Glass. Ну, и, само собой, я всегда готов ответить на вопросы.
Конечно, никто не заставляет нас использовать TimeLine в качестве интерфейса для своего приложения. Мы вполне можем поднять Activity с простенькими элементами управления, научить пользователя обходиться с ними… Для графически насыщенных приложений, например игр, это вообще будет единственным выходом. Но, что касается обычных приложений, их, по-моему, стоит выполнять в “родном” стиле для этой необычной платформы. Тогда они смогут рассчитывать на гораздо более тёплый приём у пользователей.
ссылка на оригинал статьи http://habrahabr.ru/post/188710/
Добавить комментарий