La bambina e' riuscita, facendo cadere di piatto lato schermo il tablet per terra, ad aprirlo in un colpo solo
Una occasione per vedere come e' fatto dentro. Curiosa la posizione dello speaker (mono)
PS: il tablet e' sopravvissuto...e' decisamente resistente
lunedì 9 gennaio 2017
mercoledì 4 gennaio 2017
Mandelbrot su Pebble
Visto che sono riuscito ad installare SDK Pebble perche' non provarlo con un classico??
Per il codice mi sono basato su altro esempio di Mandelbrot su Pebble presente su GitHub (peraltro fatto molto meglio del mio)
La gestione dello schermo non e' banalissima perche' e' presente una gerarchia di livelli sovrapposti.
Una cosa significativa: non e' possibile avere dati di debug in formato float (non ne capisco il motivo ma e' cosi')
---------------------------------------------
#include <pebble.h>
static Window *schermo;
static Layer *render_layer;
static void disegna(Layer *layer, GContext *ctx)
{
float re_min = -2.0;
float im_min = -1.2;
float re_max = 1.0;
float im_max = 1.2;
int r = 0;
int itera = 40;
int xres=0;
int yres=0;
float a,b,x,y,x_new,y_new;
int i,j,k;
GRect layer_bounds = layer_get_bounds(layer);
xres=layer_bounds.size.w;
yres=layer_bounds.size.h;
a = 0.0;
b = 0.0;
x_new = 0.0;
y_new = 0.0;
float re_factor = (re_max-re_min);
float im_factor = (im_max-im_min);
// scrive messaggi di debug che possono essere letti in shell con il comando
// pebble logs
APP_LOG(APP_LOG_LEVEL_DEBUG,"WIDTH=%d HEIGHT=%d",xres,yres);
for (i=0;i<yres;i++)
{
a = re_min+(i*re_factor/yres);
for (j=0;j<xres;j++)
{
b = im_min+(j*im_factor/xres);
x = 0.0;
y = 0.0;
//APP_LOG(APP_LOG_LEVEL_DEBUG,"X=%d Y=%d",j,i);
for (k=1;k<itera;k++)
{
x_new = (x*x)-(y*y)+a;
y_new = (2*x*y)+b;
if (((x_new*x_new)+(y_new*y_new))>4)
{
r = k%2;
//APP_LOG(APP_LOG_LEVEL_DEBUG,"K=%d R=%d",k,r);
if (r == 1)
{
GPoint punto = GPoint(j,i);
//window_set_backgroung_color(&windows,GColorBlack);
graphics_draw_circle(ctx,punto,1);
}
break;
}
x = x_new;
y = y_new;
}
}
}
}
static void carica_schermo(Window *window)
{
APP_LOG(APP_LOG_LEVEL_DEBUG,"CARICA SCHERMO");
Layer *window_layer = window_get_root_layer(window);
GRect bounds = layer_get_bounds(window_layer);
render_layer = layer_create(bounds);
layer_set_update_proc(render_layer,disegna);
layer_add_child(window_layer, render_layer);
}
static void scarica_schermo(Window *window){
}
static void init(void){
APP_LOG(APP_LOG_LEVEL_DEBUG,"INIT");
schermo = window_create();
#ifdef PBL_SDK_2
window_set_fullscreen(schermo,true);
window_set_backgroung_color(schermo,GColorWhite);
#endif
window_set_window_handlers(schermo,(WindowHandlers){
.load = carica_schermo,
.unload = scarica_schermo,
});
const bool animated=true;
window_stack_push(schermo,animated);
}
static void deinit(void)
{
window_destroy(schermo);
}
int main(void) {
APP_LOG(APP_LOG_LEVEL_DEBUG,"MAIN");
init();
APP_LOG(APP_LOG_LEVEL_DEBUG,"%p",schermo);
app_event_loop();
deinit();
}
---------------------------------------------
e visto che ci siamo perche' non provare a pubblicarla sullo store di Pebble (non e' necessario un pagamento)
Per il codice mi sono basato su altro esempio di Mandelbrot su Pebble presente su GitHub (peraltro fatto molto meglio del mio)
La gestione dello schermo non e' banalissima perche' e' presente una gerarchia di livelli sovrapposti.
Una cosa significativa: non e' possibile avere dati di debug in formato float (non ne capisco il motivo ma e' cosi')
---------------------------------------------
#include <pebble.h>
static Window *schermo;
static Layer *render_layer;
static void disegna(Layer *layer, GContext *ctx)
{
float re_min = -2.0;
float im_min = -1.2;
float re_max = 1.0;
float im_max = 1.2;
int r = 0;
int itera = 40;
int xres=0;
int yres=0;
float a,b,x,y,x_new,y_new;
int i,j,k;
GRect layer_bounds = layer_get_bounds(layer);
xres=layer_bounds.size.w;
yres=layer_bounds.size.h;
a = 0.0;
b = 0.0;
x_new = 0.0;
y_new = 0.0;
float re_factor = (re_max-re_min);
float im_factor = (im_max-im_min);
// scrive messaggi di debug che possono essere letti in shell con il comando
// pebble logs
APP_LOG(APP_LOG_LEVEL_DEBUG,"WIDTH=%d HEIGHT=%d",xres,yres);
for (i=0;i<yres;i++)
{
a = re_min+(i*re_factor/yres);
for (j=0;j<xres;j++)
{
b = im_min+(j*im_factor/xres);
x = 0.0;
y = 0.0;
//APP_LOG(APP_LOG_LEVEL_DEBUG,"X=%d Y=%d",j,i);
for (k=1;k<itera;k++)
{
x_new = (x*x)-(y*y)+a;
y_new = (2*x*y)+b;
if (((x_new*x_new)+(y_new*y_new))>4)
{
r = k%2;
//APP_LOG(APP_LOG_LEVEL_DEBUG,"K=%d R=%d",k,r);
if (r == 1)
{
GPoint punto = GPoint(j,i);
//window_set_backgroung_color(&windows,GColorBlack);
graphics_draw_circle(ctx,punto,1);
}
break;
}
x = x_new;
y = y_new;
}
}
}
}
static void carica_schermo(Window *window)
{
APP_LOG(APP_LOG_LEVEL_DEBUG,"CARICA SCHERMO");
Layer *window_layer = window_get_root_layer(window);
GRect bounds = layer_get_bounds(window_layer);
render_layer = layer_create(bounds);
layer_set_update_proc(render_layer,disegna);
layer_add_child(window_layer, render_layer);
}
static void scarica_schermo(Window *window){
}
static void init(void){
APP_LOG(APP_LOG_LEVEL_DEBUG,"INIT");
schermo = window_create();
#ifdef PBL_SDK_2
window_set_fullscreen(schermo,true);
window_set_backgroung_color(schermo,GColorWhite);
#endif
window_set_window_handlers(schermo,(WindowHandlers){
.load = carica_schermo,
.unload = scarica_schermo,
});
const bool animated=true;
window_stack_push(schermo,animated);
}
static void deinit(void)
{
window_destroy(schermo);
}
int main(void) {
APP_LOG(APP_LOG_LEVEL_DEBUG,"MAIN");
init();
APP_LOG(APP_LOG_LEVEL_DEBUG,"%p",schermo);
app_event_loop();
deinit();
}
---------------------------------------------
e visto che ci siamo perche' non provare a pubblicarla sullo store di Pebble (non e' necessario un pagamento)
ed infine la prova reale (tempo di calcolo circa 6 secondi)
martedì 3 gennaio 2017
Pebble SDK su Centos 7
Colpo di genio del nuovo anno : comprare un Pebble (usato) e scoprire un paio di giorni dopo che Pebble e' stato acquistato da FitBit e che quindi dismetteranno tutto il supporto compreso il cloud !!
Mi sono quindi affrettato almeno a configurarmi l'SDK di Pebble prima che diventi non disponibile
Le istruzioni riportate sul sito sono per distribuzioni Linux basate su apt ma ho provato lo stesso l'installazione su Centos
Il pacchetto dell'SDK 64 di Pebble si scarica da qui
-----------------------------
mkdir ~/pebble-dev/
cd ~/pebble-dev/
tar -jxf ~/Downloads/pebble-sdk-4.5-linux64.tar.bz2
echo 'export PATH=~/pebble-dev/pebble-sdk-4.5-linux64/bin:$PATH' >> ~/.bash_profile
. ~/.bash_profile
-----------------------------
Per interagire con l'emulatore si usano i tasti freccia
Per visualizzare i log si usa
pebble log
per fare piu' in fretta si puo' fare
pebble wipe & pebble build & pebble install --emulator diorite --logs
Mi sono quindi affrettato almeno a configurarmi l'SDK di Pebble prima che diventi non disponibile
Le istruzioni riportate sul sito sono per distribuzioni Linux basate su apt ma ho provato lo stesso l'installazione su Centos
Il pacchetto dell'SDK 64 di Pebble si scarica da qui
-----------------------------
mkdir ~/pebble-dev/
cd ~/pebble-dev/
tar -jxf ~/Downloads/pebble-sdk-4.5-linux64.tar.bz2
echo 'export PATH=~/pebble-dev/pebble-sdk-4.5-linux64/bin:$PATH' >> ~/.bash_profile
. ~/.bash_profile
-----------------------------
si deve poi installare pip ed virtualenv di Python (e nessun problema)
---------------------------
cd ~/pebble-dev/pebble-sdk-4.5-linux64
virtualenv --no-site-packages .env
source .env/bin/activate
pip install -r requirements.txt
deactivate
---------------------------
in questo caso deactivate mi ha dato errore ma non ha creato problemi per i passi futuri
Vengono scaricati diversi pacchetti ma non sono riuscito a trovare una opzione per configurare il proxy server.
Si devono poi installare le dipendenze per il compilare. Nessun problema per installare libpixman e libsdl (peraltro gia' presenti) ma su Centos non esiste un pacchetto precompilato per la libreria libfdt e si deve quindi partire dai sorgenti.
Si scarica il file tgz da GitHub e si lancia
make
nella sottodirectory libfdt viene creata la libreria libfdt-1.3.0.so. Il problema e' che l'emulatore di Pebble ricerca la libreria libfdt.so.1. Quindi e' necessario o rinominare il file oppure creare un symlink con il nome richiesto.
Usanso make install non funziona e quindi ho copiato a mano la libreria compilato in /usr/lib e /usr/lib64
L'installazione delle applicazioni sul telefono non avviene mediante il cavo, che di fatto e' funzionale solo alla ricarica, ma passa attraverso il telefono a cui e' accoppiato l'orologio
Si deve quindi attivare il pulsante a scorrimento. Non funziona con il telefono in modalita' HotSpot ma in associazione ad un vero e proprio Access Point
per creare un nuovo progetto (Javascript o C) si usa
pebble new-project [--simple] [--javascript] [--worker] [--rocky] NAME
che genera un template su cui iniziare a lavorare
pebble build per compilare
make
nella sottodirectory libfdt viene creata la libreria libfdt-1.3.0.so. Il problema e' che l'emulatore di Pebble ricerca la libreria libfdt.so.1. Quindi e' necessario o rinominare il file oppure creare un symlink con il nome richiesto.
Usanso make install non funziona e quindi ho copiato a mano la libreria compilato in /usr/lib e /usr/lib64
L'installazione delle applicazioni sul telefono non avviene mediante il cavo, che di fatto e' funzionale solo alla ricarica, ma passa attraverso il telefono a cui e' accoppiato l'orologio
Si deve quindi attivare il pulsante a scorrimento. Non funziona con il telefono in modalita' HotSpot ma in associazione ad un vero e proprio Access Point
per creare un nuovo progetto (Javascript o C) si usa
pebble new-project [--simple] [--javascript] [--worker] [--rocky] NAME
che genera un template su cui iniziare a lavorare
pebble build per compilare
ed infine per installare si usa
pebble install --phone IP (per il telefono)
pebble install --emulator basalt (per l'emulatore. i nomi dei vari dispositivi sono riportati qui sotto)
Emulatore in esecuzione |
freccia su = Up
freccia giu' = Down
freccia destra = Select
freccia sinistra = Back
Per visualizzare i log si usa
pebble log
per fare piu' in fretta si puo' fare
pebble wipe & pebble build & pebble install --emulator diorite --logs
Cerberus App
In questi giorni sta avendo diffusione il video di un giovane filmmaker che racconta le vicessitudini sul furto (voluto) di un telefono Android
Invece di utilizzare le applicazioni tipiche di Android e IOS per tracciare la posizione del telefono, e' stata impiegata un app specifica Cerberus....vale la pena darci un'occhio
Una prima differenza: su Play Store esiste una versione del software mentre sul sito se ne possono scaricare due versioni differente (la prima e' identica a quella del Play Store la seconda utilizza dei metodi piu' avanzati per nascondersi come app di sistema)
Ovviamente per la prova ho utilizzato un telefono di prova settato su un account di prova..il software prende il controllo completo del telefono e quindi se cade nelle mani sbagliate sono guai. Cerbarus ha subito nella sua storia un leak delle informazioni degli utenti
Al momento attuale l'applicazione e' gratuita ma per una sola settimana ed per un solo dispositivo. Dopo l'abbonamento e' di 5 euro/anno
Altrettanto curiosamente non e' necessaria nessuna password per procedere...basta andare Impostazione/Sicurezza/Amministratori dispositivo e togliere la spunta a Cerberus. Dopo questa operazione l'applicazione e' disistallabile. A meno di un blocco remoto quindi chi ha in mano il telefono puo' sempre rimuovere il blocco
Invece di utilizzare le applicazioni tipiche di Android e IOS per tracciare la posizione del telefono, e' stata impiegata un app specifica Cerberus....vale la pena darci un'occhio
Una prima differenza: su Play Store esiste una versione del software mentre sul sito se ne possono scaricare due versioni differente (la prima e' identica a quella del Play Store la seconda utilizza dei metodi piu' avanzati per nascondersi come app di sistema)
Ovviamente per la prova ho utilizzato un telefono di prova settato su un account di prova..il software prende il controllo completo del telefono e quindi se cade nelle mani sbagliate sono guai. Cerbarus ha subito nella sua storia un leak delle informazioni degli utenti
Al momento attuale l'applicazione e' gratuita ma per una sola settimana ed per un solo dispositivo. Dopo l'abbonamento e' di 5 euro/anno
Schermata di installazione |
Tutti i servizi passano dai server di Cerberus (di fatto non si ha una diretta interazione con il telefono remoto ma solo con l'interfaccia web ospitata sui server Cerberus). L'username e password di login sono le stesse per loggarsi sul sito e per configurare l'app
alcune funzioni richiedono che il terminale sia rootato
Un aspetto divertente e' che se si cerca di disinstallare l'applicazione nel modo standard il pulsante non e' cliccabile.
Altrettanto curiosamente non e' necessaria nessuna password per procedere...basta andare Impostazione/Sicurezza/Amministratori dispositivo e togliere la spunta a Cerberus. Dopo questa operazione l'applicazione e' disistallabile. A meno di un blocco remoto quindi chi ha in mano il telefono puo' sempre rimuovere il blocco
Nell'interfaccia web sulla sinistra si selezionano i comandi da inviare al terminale e sulla destra si ha il log
Si possono scattare foto da remoto ed acquisire l'audio ambientale
Visto che l'apk e' semplicemente ho provato a disassemblarlo con Jadx
Librerie offuscate |
Come era facile da prevedere il codice principale e' stato offuscato ma si sono un po' di cose interessanti. Prima di tutto il file Manifest piu' mostruoso che si possa immaginare (la API di Google e' stata modificata)
----------------------------
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="11" android:="2.1.2" package="com.lsdroid.cerberus.client" platformBuildVersionCode="22" platformBuildVersionName="5.1.1-1819727">
<uses-sdk android:="15" android:="22" />
<uses-permission android:="android.permission.SEND_SMS" />
<uses-permission android:="android.permission.READ_CONTACTS" />
<uses-permission android:="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:="android.permission.RECEIVE_SMS" />
<uses-permission android:="android.permission.READ_SMS" />
<uses-permission android:="android.permission.READ_PHONE_STATE" />
<uses-permission android:="android.permission.INTERNET" />
<uses-permission android:="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:="android.permission.WRITE_SETTINGS" />
<uses-feature android:="20000" android:="true" />
<uses-feature android:="android.hardware.telephony" android:="false" />
<application android:="@style/" android:="@string/" android:="@drawable/icon" android:="o.ᑊ">
<activity android:="@style/" android:="@string/" android:="o.ᐠ" android:="2" android:="fb0" android:="2" />
<activity android:="@style/" android:="@string/" android:="o.ᕀ" android:="1" android:="fb0" android:="2" />
<activity android:="@string/" android:=".StartActivity" android:="1" android:="fb0" android:="2">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:="@string/" android:="o.ᔊ" android:="1" android:="fb0" android:="2" />
<activity android:="@style/" android:="@string/" android:="o.เ" android:="1b0" android:="@string/" android:="2" />
<receiver android:=".StartReceiver">
<intent-filter android:="2147483647">
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:=".SmsReceiver">
<intent-filter android:="100">
<action android:name="android.intent.action.DATA_SMS_RECEIVED" />
<data android:="sms" android:="*" android:="12346" />
</intent-filter>
</receiver>
<service android:="o.ˆ" />
<service android:="o.ᕑ" />
<service android:="o.ˀ" />
<service android:="com.google.android.gms.analytics.CampaignTrackingService" />
<receiver android:="com.google.android.gms.analytics.CampaignTrackingReceiver" android:="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
<meta-data android:="com.google.android.gms.version" android:="@integer/" />
<meta-data android:="com.google.android.maps.v2.API_KEY" android:="AIzaSyCLvVIVynRBR7yC2Wa18i" />
</application>
</manifest>
----------------------------
c'e' anche l'uso della libreria okhttp
Ovviamente,e per fortuna, per l'uso del software ci vuole almeno un accesso fisico al dispositivo e cio' ne limita l'uso non idoneo alla sua funzione principale. In definitiva comunque un buon software (se non fosse che la licenza d'uso permette agli sviluppatori di divulgare dati...e visto il controllo di informazioni che si possono raccogliere e' meglio stare attenti a non dare la propria chiave di casa in mani sconosciute)
lunedì 2 gennaio 2017
Integrazione Google Maps e Firebase per mappatura collaborativa
Firebase puo' essere utilizzato come base dati per salvare anche dati semplici di tipo cartografico.
Il vantaggio di questo approccio e' che ogni modifica effettuata da un client viene immediatamente visualizzato sugli altri client senza necessita' di aggiornare la pagina (utile quindi nel caso si voglia fare per esempio il tracking di un oggetto che si muove)
Un esempio live puo' essere provato a questo link
La struttura dati e' molto semplice: un alberi in cui ad ogni entrata sono presenti una longitudine ed una latitudine. Cliccando sulla mappa si aggiunge un nuovo nodo alla mappa
Esempio del sistema in uso
Attenzione : Firebase non conosce il tipo float per cui ci sono un po' di magheggi nel convertire i dati float da e per tipi stringhe
------------------------
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
html, body { height: 100%; margin: 0; padding: 0; }
#map { height: 100%; }
</style>
<script src="https://www.gstatic.com/firebasejs/3.6.4/firebase.js"></script>
<script type="text/javascript">
var latitudine = 0.0;
var longitudine = 0.0;
var conta = 0;
// Initialize Firebase
var config = {
apiKey: "AIzaSyAchx8oVeLUgYnGujAEfwOxxxxxxxxxxxxxxxx",
authDomain: "notifica-23xxxxxxfirebaseapp.com",
databaseURL: "https://notifica-23xxxxxfirebaseio.com",
storageBucket: "notifica-2xxxxxx.appspot.com",
messagingSenderId: "392723xxxxxxx"
};
firebase.initializeApp(config);
</script>
<script type="text/javascript">
/*
questi sono solo esempi di come si possano inserire dati in Firebase in Javascript
le righe sono commentate e quindi non in uso/
firebase.database().ref('punti/').set({
lat: 43,
lng : 11
});*/
/*
firebase.database().ref('punti/').push({
lat: 43.0,
lng : 12.0
});
firebase.database().ref('punti/').push({
lat: 42,
lng: 11
});
*/
</script>
</head>
<body>
<div id="map"></div>
<script>
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
center: {
lat: 43,
lng: 11
},
zoom: 6,
styles: [{
featureType: 'poi',
stylers: [{
visibility: 'off'
}] // Turn off points of interest.
}, {
featureType: 'transit.station',
stylers: [{
visibility: 'off'
}] // Turn off bus stations, train stations, etc.
}],
disableDoubleClickZoom: false
});
//questa e' la funzione che all'evento click sulla mappa aggiunge il corrispondente
// punto nel database map.addListener('click', function(e) {
firebase.database().ref('punti/').push({
lat: JSON.stringify(e.latLng.lat()),
lng : JSON.stringify(e.latLng.lng())
});
var marker = new google.maps.Marker({
position: {
lat: e.latLng.lat(),
lng: e.latLng.lng()
},
map: map
});
});
//fine della funzione di inserimento
// crea un evento sull'aggiornamento dei punti
//sicuramente esiste un sistema piu' furbo di fare la stessa cosa
const dbRefPunti = firebase.database().ref().child('punti');
dbRefPunti.on('child_added',function(snap,prevChildKey)
{
var la1;
var lo1;
snap.forEach(function (snapshot) {
var obj = snapshot.val();
var nome = snapshot.key;
if (snapshot.key == "lat")
{
latitudine = JSON.stringify(obj);
la1 = obj;
console.log("latitudine : "+latitudine);
}
if (snapshot.key == "lng")
{
longitudine = JSON.stringify(obj);
lo1 = obj;
console.log("longitudine : "+longitudine);
}
conta++;
console.log("Conta : "+conta);
if (conta%2 == 0)
{
console.log("Stampa : " + latitudine+":"+longitudine);
console.log(isNaN(la1));
//var latLng = new google.maps.LatLng(parseFloat(latitudine),parseFloat(longitudine));
var latLng = new google.maps.LatLng(la1,lo1);
var marker = new google.maps.Marker({position: latLng,map: map});
}
});
}
);
// fine evento
//fine initMaps
google.maps.event.addDomListener(window, "load", initMap);
};
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDkeozFISVmCAB3ta1rEXvMNDDzSxxxxxxxx&callback=initMap">
</script>
</body>
</html>
------------------------
Il vantaggio di questo approccio e' che ogni modifica effettuata da un client viene immediatamente visualizzato sugli altri client senza necessita' di aggiornare la pagina (utile quindi nel caso si voglia fare per esempio il tracking di un oggetto che si muove)
Un esempio live puo' essere provato a questo link
La struttura dati e' molto semplice: un alberi in cui ad ogni entrata sono presenti una longitudine ed una latitudine. Cliccando sulla mappa si aggiunge un nuovo nodo alla mappa
Esempio del sistema in uso
Attenzione : Firebase non conosce il tipo float per cui ci sono un po' di magheggi nel convertire i dati float da e per tipi stringhe
------------------------
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
html, body { height: 100%; margin: 0; padding: 0; }
#map { height: 100%; }
</style>
<script src="https://www.gstatic.com/firebasejs/3.6.4/firebase.js"></script>
<script type="text/javascript">
var latitudine = 0.0;
var longitudine = 0.0;
var conta = 0;
// Initialize Firebase
var config = {
apiKey: "AIzaSyAchx8oVeLUgYnGujAEfwOxxxxxxxxxxxxxxxx",
authDomain: "notifica-23xxxxxxfirebaseapp.com",
databaseURL: "https://notifica-23xxxxxfirebaseio.com",
storageBucket: "notifica-2xxxxxx.appspot.com",
messagingSenderId: "392723xxxxxxx"
};
firebase.initializeApp(config);
</script>
<script type="text/javascript">
/*
questi sono solo esempi di come si possano inserire dati in Firebase in Javascript
le righe sono commentate e quindi non in uso/
firebase.database().ref('punti/').set({
lat: 43,
lng : 11
});*/
/*
firebase.database().ref('punti/').push({
lat: 43.0,
lng : 12.0
});
firebase.database().ref('punti/').push({
lat: 42,
lng: 11
});
*/
</script>
</head>
<body>
<div id="map"></div>
<script>
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
center: {
lat: 43,
lng: 11
},
zoom: 6,
styles: [{
featureType: 'poi',
stylers: [{
visibility: 'off'
}] // Turn off points of interest.
}, {
featureType: 'transit.station',
stylers: [{
visibility: 'off'
}] // Turn off bus stations, train stations, etc.
}],
disableDoubleClickZoom: false
});
//questa e' la funzione che all'evento click sulla mappa aggiunge il corrispondente
// punto nel database map.addListener('click', function(e) {
firebase.database().ref('punti/').push({
lat: JSON.stringify(e.latLng.lat()),
lng : JSON.stringify(e.latLng.lng())
});
var marker = new google.maps.Marker({
position: {
lat: e.latLng.lat(),
lng: e.latLng.lng()
},
map: map
});
});
//fine della funzione di inserimento
// crea un evento sull'aggiornamento dei punti
//sicuramente esiste un sistema piu' furbo di fare la stessa cosa
const dbRefPunti = firebase.database().ref().child('punti');
dbRefPunti.on('child_added',function(snap,prevChildKey)
{
var la1;
var lo1;
snap.forEach(function (snapshot) {
var obj = snapshot.val();
var nome = snapshot.key;
if (snapshot.key == "lat")
{
latitudine = JSON.stringify(obj);
la1 = obj;
console.log("latitudine : "+latitudine);
}
if (snapshot.key == "lng")
{
longitudine = JSON.stringify(obj);
lo1 = obj;
console.log("longitudine : "+longitudine);
}
conta++;
console.log("Conta : "+conta);
if (conta%2 == 0)
{
console.log("Stampa : " + latitudine+":"+longitudine);
console.log(isNaN(la1));
//var latLng = new google.maps.LatLng(parseFloat(latitudine),parseFloat(longitudine));
var latLng = new google.maps.LatLng(la1,lo1);
var marker = new google.maps.Marker({position: latLng,map: map});
}
});
}
);
// fine evento
//fine initMaps
google.maps.event.addDomListener(window, "load", initMap);
};
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDkeozFISVmCAB3ta1rEXvMNDDzSxxxxxxxx&callback=initMap">
</script>
</body>
</html>
------------------------
venerdì 30 dicembre 2016
Firebase Storage
A differenza del serivizio Hosting, con il quale potrebbe essere confuso per alcuni usi comuni, lo Storage di Firebase impiega un sistema nativo di permessi per cui e' possibile rendere i contenuti privati e pubblici con un filtro sulla base dell'utente.
Inoltre se in Hosting l'aggiornamento avviene con una metodologia simile ai commit di GitHub, ovvero a livello di intero progetto, in Storage si gestiscono i singoli file
Nel profilo gratuito sono inclusi 5Gb di spazio disco per lo Storage (1 Gb per Hosting)
i permessi di accesso vengono gestiti dalla Console di Firebase sul tab Regole (come in Realtime Databases)
Per interagire con Storage, oltre alla Console, si possono usare client Javascript, Android ed IOS (operazioni di Upload, Download e Delete)
Inoltre se in Hosting l'aggiornamento avviene con una metodologia simile ai commit di GitHub, ovvero a livello di intero progetto, in Storage si gestiscono i singoli file
Nel profilo gratuito sono inclusi 5Gb di spazio disco per lo Storage (1 Gb per Hosting)
Per recuperare i file si ha a disposizione un link del tipo
https://firebasestorage.googleapis.com/v0/b/notifica-23425.appspot.com/o/images%2Fa1.jpg?alt=media&token=4f930e8d-cxxxxxxxxxxxxxxxxxxxxxx
Esempio di accesso non autenticato |
oppure e' possibile scaricare il medesimo file utilizzando le URI di Google Cloud (indirizzo del formato gs://)
Per interagire con Storage, oltre alla Console, si possono usare client Javascript, Android ed IOS (operazioni di Upload, Download e Delete)
mercoledì 28 dicembre 2016
Adb over Wifi
In caso si debba sviluppare una applicazione che usa l'ingresso USB, tipo Midi via USB-OTG, puo' essere utile impiegare Adb via Wifi
Per prima cosa si collega il telefono alla USB e si seleziona Terminale in Android Studio
Il telefono puo' essere connesso ad un access point o funzionare da HotSpot
Si digita quindi
adb tcpip 5555
adb connect IP_Telefono
si puo' scollegare il cavo USB e procedere allo sviluppo
Per prima cosa si collega il telefono alla USB e si seleziona Terminale in Android Studio
Il telefono puo' essere connesso ad un access point o funzionare da HotSpot
Si digita quindi
adb tcpip 5555
adb connect IP_Telefono
si puo' scollegare il cavo USB e procedere allo sviluppo
Iscriviti a:
Post (Atom)
Debugger integrato ESP32S3
Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede nell'ID USB della porta Jtag. Nel modulo...
-
In questo post viene indicato come creare uno scatterplot dinamico basato da dati ripresi da un file csv (nel dettaglio il file csv e' c...
-
Questo post e' a seguito di quanto gia' visto nella precedente prova Lo scopo e' sempre il solito: creare un sistema che permet...
-
La scheda ESP32-2432S028R monta un Esp Dev Module con uno schermo TFT a driver ILI9341 di 320x240 pixels 16 bit colore.Il sito di riferiment...