O documento fornece informações sobre o desenvolvimento de aplicativos para dispositivos wearables com Android Wear, abordando notificações, API's, layouts e referências. É descrito como enviar e receber notificações e dados entre dispositivos, utilizando as API's Node, Message e Data.
4. Wearables
São dispositivos que interagem com os smartphones;
Bluetooth;
Wifi
Dispositivos:
Lg SmartWatch
Motorola 360
Samsung gear
Lançados no Google IO 2014;
Permitem uma interação do usuário, sem que ele precise interagir com
smartphone (interações rápidas ou micro interações)
6. Notificações
Qualquer notificação gerada é enviada para ao wearables (desde que a versão do
Smartphone seja android 4.4+)
Tipos de Notificações:
Notificações Simples
Notificações com ações
Notificações Big picture style
Notificações focadas em wearables
Respostas por voz
Opções default:
Abrir no Smartphone;
Bloquear App;
8. Notificações com Ações
Permite interagir com a notificação sem necessidade de interagir com
smartphone;
Possibilita uma ação rápida;
Deixa o usuário satisfeito
10. Notificações – Big Picture style e Inbox style
Big Picture Inbox Style
NotificationCompat.BigPictureStyle bigPicStyle = new NotificationCompat.BigPictureStyle();
11. NotificationCompat.Builder notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Título")
.setContentText("Este é o texto de uma notificação")
.setContentIntent(pendingIntent)
.addAction(curtirAction)
.extend(extender);
Notificações Wearables
Uma extensão para customizações de notificações que são específicas para os
wearables – Wearable Extender;
São aplicáveis somente a wearables;
Permitem maior customização das notificações focadas em wearables, e
coexistem com as notificações para smartphones;
Somente
Wearable
Somente
Smartphone
NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender()
.setHintHideIcon(true)
.setBackground(bitmap)
.addAction(actionWearable);
NotificationCompat.Action actionWearable = new NotificationCompat.Action(
R.mipmap.ic_launcher,
"Curtir Wear",
pendingIntentWear);
*setLocalOnly(boolean) para
notificação não ser enviada ao
wearable
12. Exibição em Páginas
Exibe o conteúdo em páginas;
Contém um indicador dar um feedbak ao usuário da página atual, bem
como quantas paginas restam;
As páginas aparecem à direita da notificação;
Com o gesto de swipe o usuário navega nas informações;
Exemplo: Google Now
14. Exibição em Pilha (Stack)
A informação é exibida em pilha (cards empilhados);
Contém informação de quantos cards empilhados existem;
Ao clicar no item (+1 card) os cards são expandidos, sendo exibidos em
uma espécie de lista;
15. Notificação em Pilha (Stack)
Notification notificacao1= new
NotificationCompat.Builder(this)
.setContentTitle("Notificacao 1")
.setContentText("Conteúdo do email 1")
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(icon)
.setGroup("Group")
.build();
manager.notify(0, notificacao1);
Notification notificacao2= new
NotificationCompat.Builder(this)
.setContentTitle("Notificacao 2")
.setContentText("Conteúdo do email 2")
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(icon)
.setGroup("Group")
.build();
manager.notify(1, notificacao2);
NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle()
.addLine("xxx@yyy.com")
.addLine("xxx@zzz.com")
.setBigContentTitle(0 + "novos emails")
.setSummaryText("info@fhf.com");
Notification sumario = new NotificationCompat.Builder(this)
.setContentTitle("sumario titulo")
.setContentText("sumario content texto")
.setSmallIcon(R.mipmap.ic_launcher)
.setGroup("Group")
.setGroupSummary(true)
.setStyle(style)
.extend(extender)
.build();
manager.notify(2, sumario);
NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender()
.setBackground(icon);
16. Notificações – respostas à ações via
comandos de voz
Usados nas notificações para que o usuário possa responder uma
notificação via comandos de voz;
Definição de um input de voz
Passa-se um array de Strings para um objeto RemoteInput
Mensagens pré-definidas:
Cria-se um recurso string-array passando-as no método setChoice(String[])
Permite que o usuário utilize respostas rápidas
17. Notificações: respostas via comandos de voz
NotificationCompat.Action actionWearable = new NotificationCompat.Action.Builder(
R.mipmap.ic_launcher,
"Responder",
pendingIntent)
.addRemoteInput(gerarRespostaVoz())
.build();
NotificationCompat.WearableExtender extender = new
NotificationCompat.WearableExtender()
.setHintHideIcon(true)
.addAction(actionWearable);
NotificationCompat.Builder notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Título 2")
.setContentText("Este é o texto de uma notificação, em pilha")
.setContentIntent(pendingIntent)
.extend(extender);
private RemoteInput gerarRespostaAutomatica() {
String[] respostas = getResources().getStringArray(R.array.respostas);
return new RemoteInput.Builder(EXTRA_RESPOSTAS_VOZ)
.setLabel("Respostas!")
.setChoices(respostas)
.build();
}
Cria um objeto do tipo RemoteInput passando um array de strings
Passa o remoteInput criado no método addRemoteInput(RemoteInput)
Adiciona-se a ação ao objeto extender (pois deve ser uma ação wearable)
Adiciona-se o extender à notificação
18. Obtendo input de voz
Permite capturar o input de resposta (voz ou resposta pré-definida) e
utilizar o dado na aplicação;
É uma funcionalidade útil em aplicativos de conversa (whatsapp, hangouts)
Bundle input = RemoteInput.getResultsFromIntent(getIntent());
if(input != null) {
resposta =
input.getCharSequence(EXTRA_RESPOSTAS_VOZ).toString();
}
20. Trabalhando com API´s
Podem ser acionadas tanto no smartphone quanto no wear;
Necessitam conectar com Google Play Services;
Dados trafegados são privados;
Servem para sincronizar dados entre smartphone e wearables;
compile 'com.google.android.gms:play-services-wearable:7.5.0'
Recomendação: conectar Google Play Services no método onStart e
desconectar no onStop;
private GoogleApiClient googleApiClient() {
GoogleApiClient client = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(connectionCallbacks)
.addOnConnectionFailedListener(failedListener)
.build();
return client;
}
21. Trabalhando com API´s
private GoogleApiClient.ConnectionCallbacks connectionCallbacks =
new GoogleApiClient.ConnectionCallbacks() {
@Override
public void onConnected(Bundle bundle) {
}
@Override
public void onConnectionSuspended(int i) {
}
};
private GoogleApiClient.OnConnectionFailedListener failedListener =
new GoogleApiClient.OnConnectionFailedListener() {
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
};
Adicionando callback de conexão:
Adicionando callback de falha de conexão:
22. Node API
Permite saber quando um
dispositivo se conectou ou
desconectou;
Permite também saber quais os
dipositivos conectados atualmente;
Pode estar associada a outras API´s
23. Node API
private void nodeConnection() {
Wearable.NodeApi.addListener(googleApiClient(), new NodeApi.NodeListener() {
@Override
public void onPeerConnected(Node node) {
boolean isNear = node.isNearby();
String nodeId = node.getId();
String name = node.getDisplayName();
}
@Override
public void onPeerDisconnected(Node node) {
}
});
}
private void getConnectedNodes() {
Wearable.NodeApi.getConnectedNodes(googleApiClient()).setResultCallback(
new ResultCallback<NodeApi.GetConnectedNodesResult>() {
@Override
public void onResult(NodeApi.GetConnectedNodesResult getConnectedNodesResult) {
Node connectedNode = getConnectedNodesResult.getNodes().get(0);
}
}
);
}
Detectando conexão de um nó:
Obter os nós conectados:
24. Message API
Dados:path: uma única String,
iniciando com “/” (exemplo:
“/path/data”)
Não há sincronização, e sim um
envio em uma direção (“one-way
communication mechanism);
Exemplo: abrir uma activity via
wearable;
Exemplo: receber uma
confirmação do usuário
25. Message API
Enviando uma mensagem:
private void receiveMessage() {
Wearable.MessageApi.addListener(googleApiClient(), new MessageApi.MessageListener()
{
@Override
public void onMessageReceived(MessageEvent messageEvent) {
byte[] dado = messageEvent.getData();
System.out.println("Log data: " + dado);
}
});
}
Recebendo uma mensagem:
if (getConnectedNodes().isNearby()) {
Wearable.MessageApi.sendMessage(
googleApiClient(),
getConnectedNodes().getId(),
"/mensagens",
new byte[]{3, 2, 1});
26. Data API
Funciona como um repositório
temporário: permite inserir, alterar,
remover dados;
Informa quando houver alteração
ou exclusão de dados;
Permite fluxo de dados em ambos
os sentidos
device wearable
wearable device
Utiliza uma string como endereço:
“/dados”
27. Data API – Envio de dados
Cria-se um objeto PutDataMapRequest passando um path (string)
Define o envio
Envia o dado
PutDataMapRequest mapRequest = PutDataMapRequest.create("/exemplogdg");
Passa-se os objetos
PutDataRequest request = mapRequest.asPutDataRequest();
Wearable.DataApi.putDataItem(client, request)
.setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
@Override
public void onResult(DataApi.DataItemResult dataItemResult) {
if (dataItemResult.getStatus().isSuccess()) {
Log.i("sucesso", "--> OK");
} else {
Log.i("falha", "--> NOK");
}
}
});
Verifica
Envio
mapRequest.getDataMap().putInt("userId", id);
mapRequest.getDataMap().putString("userPhoneNumber", name);
28. Data API – Recebimento de dados
Cria-se uma instância de GooglePlayServices (build)
@Override
protected void onStart() {
super.onStart();
client.connect();
}
Conecta-se Google Play Services
@Override
public void onConnected(Bundle bundle) {
Wearable.DataApi.addListener(client, this);
}
Adiciona listener de DataApi
@Override
protected void onPause() {
Wearable.DataApi.removeListener(client, this);
client.disconnect();
super.onPause();
}
Remove listener de DataApi e desconecta Google Play Services
@Override
public void onCreate() {
super.onCreate();
googleApiClient();
}
29. Data API – Recebimento de dados
Percorre o objeto DataEventBuffer
@Override
public void onDataChanged(DataEventBuffer dataEventBuffer) {
for (DataEvent dataEvent : dataEventBuffer) {
Condição para dados que foram atualizados
Obtem-se a Uri que teve alteração de dados
Dados excluídos
} else if(dataEvent.getType() == DataEvent.TYPE_DELETED) {
//Dados que foram excluídos
}
if(dataEvent.getType() == DataEvent.TYPE_CHANGED) {
DataMap dataMap =
DataMapItem.fromDataItem(dataEvent.getDataItem()).getDataMap();
String path = dataEvent.getDataItem().getUri().getPath();
int id = dataMap.getInt("userId");
String nome = dataMap.getString("userPhoneNumber");
if(path.equals("/exemplogdg")) {
Envio dados
30. Wearable Listener Service
Recebe eventos de outros nós, como mudança de dados, envio de
mensagem e mudanças de conectividade;
O ciclo de vida do service é gerenciado pelo Android Wear;
É indicado quando há necessidade de executar um evento em
background;
Situações onde há uma activity aberta não necessitam do Service, e
podem ser executadas implementando as interfaces citadas
anteriormente;
onBind(Intent)
onChannelClosed(Channel, int closeReason, int erro)
/onChannelOpened(Channel)
onDataChanged(DataEventBuffer)
onCreate() / onDestroy()
onMessageReceived(MessageEvent)
onPeerConnected(Node) / onPeerDisconnected(Node)
31. Wearable Listener Service
Declara o service no Manifest
<service
android:name="com.example.deals.DataListenerService"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name=
"com.google.android.gms.wearable.BIND_LISTENER" />
</intent-filter>
</service>
32. Wearable Listener Service
@Override
public void onDataChanged(DataEventBuffer dataEvents) {
for(DataEvent dataEvent : dataEvents) {
if(dataEvent.getType() == DataEvent.TYPE_CHANGED) {
DataMap dataMap = DataMapItem.fromDataItem(dataEvent.getDataItem()).getDataMap();
String path = dataEvent.getDataItem().getUri().getPath();
Log.i("log path: ", "-->" + path);
if(path.equals("/exemplogdg")) {
int id = dataMap.getInt("userId");
String nome = dataMap.getString("userPhoneNumber");
}
}
}
}
33. Wearable Layouts
WatchViewStub
<android.support.wearable.view.WatchViewStub/>
App:rectLayout=“@layout/layout_retangular”
App:roundLayout =“@layout/layout_circular”
BoxInsetLayout – layout adaptável para telas retangulares e circulares;
Cards
FrameLayout – Troca de CardFragment em tempo de execução (na activity)
CardScrollView que contém um CardFrame
Telas de confirmação - DelayedConfirmationView
34. Rodando aplicação
Vá até o path de instalação da sdk e vá no diretório platform-tools
Instala-se o aplicativo Android Wear no device, para fazer o pareamento.