Finalmente e' arrivato l'aggiornamento di Android Wear 2 sul mio LG R...e' quindi tempo di provare le nuove applicazioni per Android Wear che non hanno piu' bisogno dell'app companion sul telefono
Ho quindi preso un vecchio progetto (Aptic Metronome) di Wear 1 per adattarlo ad Wear 2
E' sufficiente in Android Studio crea un progetto per solo Android Wear con un targetSDKVersion pari a 25 (anche la minSDKVersion deve corrispondere a 25 per il solo Android Wear)
Per istruire il Play Store che l'apk non ha un app companion in AndroidManifest.xml e' necessario indicare
Fatto cio' il progetto e' compatibile per l'upload su PlayStore. La preparazione su PlayStore e' identica a quella di Wear 1 con la conseguente revisione da parte di Google
Le Message API permettono di scambiare messaggi tra dispositivi Android, nel caso specifico tra il telefono e l'orologio mediante Android Wear
Nell'esempio in esame vengono sincronizzati due NumberPicker
Questo e' un tentativo di realizzare un homekit, un sistema di domotica, che permetta di accendere dei dispositivi con un sensore di prossimita' (tipo il lampadario quando si entra in una stanza)
I componenti di questo kit sono
1) un orologio con Android Wear
2) un Raspberry (qualsiasi modello) con un dongle Bluetooth LE
3) un rele
L'orologio e' stato programmato come emettitore di beacon (e' possibile modificare il valore del minor in modo da personalizzarlo)
package luca_innocenti.beacontrasmitter;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.wearable.view.WatchViewStub;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.TextView;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.pm.PackageManager;
import org.altbeacon.beacon.Beacon;
import org.altbeacon.beacon.BeaconParser;
import org.altbeacon.beacon.BeaconTransmitter;
import org.altbeacon.beacon.Identifier;
import java.util.Arrays;
@TargetApi(21)
public class MainActivity extends Activity {
private BeaconTransmitter mBeaconTransmitter;
private TextView testo;
private SeekBar barra;
private Button pulsante;
private int stato;
private TextView testo2;
private TextView testo3;
private void trasmetti(){
if (checkPrerequisites()) {
// //mBeaconTransmitter = new BeaconTransmitter(this, new BeaconParser().setBeaconLayout("m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"));mBeaconTransmitter = new BeaconTransmitter(this, new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
//beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:0-3=4c000215,i:4-19,i:20-21,i:22-23,p:24-24")); // iBeacons //beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24")); // Estimotes //beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:0-3=a7ae2eb7,i:4-19,i:20-21,i:22-23,p:24-24")); // easiBeacons // uuid estimote B9407F30-F5F8-466E-AFF9-25556B57FE6DBeacon beacon = new Beacon.Builder()
.setId1("B9407F30-F5F8-466E-AFF9-25556B57FE6D")
.setId2("999")
.setId3(testo.getText().toString())
.setManufacturer(0x015D) // Simula Estimote.setTxPower(-59)
.setDataFields(Arrays.asList(new Long[]{0l}))
.build();
mBeaconTransmitter.startAdvertising(beacon);
stato = 1;
}
}
@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
@Overridepublic void onLayoutInflated(WatchViewStub stub) {
barra = (SeekBar) stub.findViewById(R.id.seekBar);
testo = (TextView) stub.findViewById(R.id.textView);
testo2 = (TextView) stub.findViewById(R.id.textView2);
testo3 = (TextView) stub.findViewById(R.id.textView3);
pulsante = (Button) stub.findViewById(R.id.button);
barra.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
testo.setText(String.valueOf(new Integer(progress)));
}
@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {
}
@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {
}
}
);
pulsante.setOnClickListener(new View.OnClickListener() {
@Overridepublic void onClick(View v) {
testo2.setText("Trasmitter ON");
testo3.setText("B9407F30-F5F8-466E-AF\nF9-25556B-57FE6D-999-"+testo.getText());
pulsante.setEnabled(false);
barra.setEnabled(false);
trasmetti();
}
});
}
});
}
@Overrideprotected void onDestroy() {
super.onDestroy();
if (stato == 1) {
mBeaconTransmitter.stopAdvertising();
}
}
@TargetApi(21)
private boolean checkPrerequisites() {
if (android.os.Build.VERSION.SDK_INT < 18) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Bluetooth LE not supported by this device's operating system");
builder.setMessage("You will not be able to transmit as a Beacon");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Overridepublic void onDismiss(DialogInterface dialog) {
finish();
}
});
builder.show();
return false;
}
if (!getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Bluetooth LE not supported by this device");
builder.setMessage("You will not be able to transmit as a Beacon");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Overridepublic void onDismiss(DialogInterface dialog) {
finish();
}
});
builder.show();
return false;
}
if (!((BluetoothManager) getApplicationContext().getSystemService(Context.BLUETOOTH_SERVICE)).getAdapter().isEnabled()){
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Bluetooth not enabled");
builder.setMessage("Please enable Bluetooth and restart this app.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Overridepublic void onDismiss(DialogInterface dialog) {
finish();
}
});
builder.show();
return false;
}
try {
// Check to see if the getBluetoothLeAdvertiser is available. If not, this will throw an exception indicating we are not running Android L((BluetoothManager) this.getApplicationContext().getSystemService(Context.BLUETOOTH_SERVICE)).getAdapter().getBluetoothLeAdvertiser();
}
catch (Exception e) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Bluetooth LE advertising unavailable");
builder.setMessage("Sorry, the operating system on this device does not support Bluetooth LE advertising. As of July 2014, only the Android L preview OS supports this feature in user-installed apps.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Overridepublic void onDismiss(DialogInterface dialog) {
finish();
}
});
builder.show();
return false;
}
return true;
}
}
--------------------------------------
Per leggere la prossimita' dell'orologio ho montato sulla Raspberry un dongle Broadcome (gia' visto qui) ed il programma in Python iBeacon-Scanner (Github) leggermente modificato
Il programma cicla fino quando non vede un dispositivo con minor=1, allora controlla l'Rssi e stima la distanza. Se la distanza e' inferiore ad un determinato valore si puo' agire sulle porte GPIO ed attivare il rele' (funzione da implementare ma di facilissima realizzazione)
-------------------------------------- import blescan import sys import bluetooth._bluetooth as bluez dev_id = 0 try: sock = bluez.hci_open_dev(dev_id) #print "ble thread started" except: print "error accessing bluetooth device..." sys.exit(1) blescan.hci_le_set_scan_parameters(sock) blescan.hci_enable_le_scan(sock) while True: returnedList = blescan.parse_events(sock, 10) #print "----------" for beacon in returnedList: #print beacon valori = beacon.split(",") mac = valori[0] uuid = valori[1] major = valori[2] minor = valori[3] rssi = valori[4] rssi2 = valori[5] #print minor if (minor == "1"): #print minor+" "+rssi2 if (int(rssi2) > -75): print "vicino" else: print "lontano" --------------------------------------
Per disinstallare applicazione da Android Wear non esiste un sistema integrato all'interno dell'orologio.
Se si ha l'applicazione/installer sul telefono basta agire sul telefono che la modifica si replica anche sull'orologio ma se si sta per esempio sviluppando una applicazione in proprio questa strada non risulta applicabile
Ci viene quindi in aiuto adb ma si deve conoscere il nome reale del pacchetto installato (e non il nome dell'applicazione)
Per listare le applicazioni installazione sull'orologio si puo' digitare
adb shell pm list packages
diciamo che il pacchetto che si vuole disinstallare luca_innocenti.soundwear si esce dalla shell e si digita
adb uninstall luca_innocenti.soundwear
queste istruzioni funzionano se l'orologio e' collegato via USB (ovvero se e' collegato sulla sua basetta). Se invece il debug e' avviato via bluetooth si deve procedere con
Ho un vecchio progetto (vecchio per modo di dire ... ma nell'informatica un anno ha una valenza un po' particolare) in Eclipse a cui volevo aggiungere il supporto ad Android Wear senza trasportare tutto in Android Studio
La procedura per impostare l'ambiente di sviluppo non e' molto lineare e deriva da quanto descritto a questo link
Per prima cosa da Sdk Manager deve essere aggiunto il Google Repository
Una volta terminato il download si deve andare nella directory del proprio SDK ed in particolare in
./extras/google/m2repository/com/google/android/support/wearable/1.0.0/wearable-1.0.0.aar
copiare il file .aar, rinominarlo in .zip e decomprimerlo (attenzione esiste anche un file wearable-1.0.0.jar da non usare)
Dopo lo scompattamento si entra nella cartella, si crea un directory libs e vi si copia il file classes.jar
Si apre quindi Eclipse e si importa la directory con File/New/Project/Android Project From Existing Code
Dopo l'importazione si clicca destro sulla directory wearable-1.0.0. /Properties/Android, si flagga IsLibrary, Apply, Ok e da questo punto in poi e' stato aggiunto il supporto di Android Wear ad Eclipse
Per aggiungere il supporto ad Android Wear ad un progetto si clicca sulle proprieta' del progetto/Android e si aggiunge la libreria wereable
Dopo aver modificato il telefono per avere un dispositivo ad Android 4.4, ho provato Android Wear, la versione per i futuri Smart Watch di Google.
Al momento e' disponibile solo una developer preview (per cui bisogna essere registrati) all'interno dell'emulatore
Sul telefono si installa l'applicazione Android Wear Preview App mentre dall'Android SDK Manager si deve scaricare Android Wear ARM EABI v7a System Image.
e si crea una nuova macchina virtuale AVD basata sull'immagine di Android Wear
A questo punto si esegue l'emulatore, si connette il telefono via USB e si attiva l'applicazione sul telefono.
Al computer si digita quindi il comando
adb -d forward tcp:5601 tcp:5601
l'applicazione sul telefono mostra lo stato di connessione e l'icona sull'emulatore mostra lo stato di connessione.
Per generare quindi una notifica ho effettuato una telefonata al cellulare e sul display dello Smart Watch e' comparsa la notizia
Di fatto il sistema reagisce sostanzialmente alle notifiche che gli derivano dal telefono a cui e' accoppiato.
Non e' necessario che le notifiche siano di sistema. Si puo' creare una applicazione che generi notifiche e queste vengono instradate verso lo smartwatch
Per esempio il codice sottostante genera una piccola applicazione che lancia una notifica all'avvio (codice modificato dal post originale, da notare che il codice originale non era stato concepito per Android Wear a dimostrazione di come si possa importare semplicemente codice relativo ad altre API) Per compilare il codice e' necessario inserire tra le librerie wereable-preview-support.jar tra le Referenced Libraries
----------------------------------------------------------------------------- package com.wear.orologio; import android.app.Activity; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; public class MainActivity extends Activity { NotificationManager notificationManager; Notification myNotification; private static final int MY_NOTIFICATION_ID=1; private final String myBlog = "http://www.google.com/"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Context context = getApplicationContext(); Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(myBlog)); PendingIntent pendingIntent = PendingIntent.getActivity( MainActivity.this, 0, myIntent, Intent.FLAG_ACTIVITY_NEW_TASK); myNotification = new Notification.Builder(context) .setContentTitle("Notifica") .setContentText("Dal Luca Innocenti") .setTicker("Notifica") .setWhen(System.currentTimeMillis()) .setContentIntent(pendingIntent) .setDefaults(Notification.DEFAULT_SOUND) .setAutoCancel(true) .setSmallIcon(R.drawable.ic_launcher) .build(); notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(MY_NOTIFICATION_ID, myNotification); } }
Non sembra in quanto sull'emulatore dello Smart Watch funziona tranquillamente Hello World per cui il dispositivo sembra avere una propria autonomia dal telefono