Skip to content
Archive of posts filed under the Mobile category.

Tethering dallo smartphone, ecco come gli operatori telefonici possono scoprirlo

Molte delle promozioni per la navigazione web dal proporio smartphone precisano che l’accesso ad Internet e’ consentito *solo dal device*, e non attaccando il device ad un computer attraverso il tethering (wifi o usb). Mi sono sempre chiesto come facessero i carrier a capire quando stavo navigando nell’uno o nell’altro modo, e grazie a questo commento a questo post ho avuto la risposta, almeno per Android:

The built-in tether support acts as a WiFi hotspot and router. This does a USB tether, and acts as a network proxy. Very different.

The biggest difference, from the carrier’s end, is that routing is pretty easy to detect; each packet that goes through the router, the time-to-live (TTL) field in the IPv4 header is decremented. In addition, there is NAT going on, and there are heuristics to detect that. There are ways around this using Linux’s iptables that can masquerade the routing/NAT, but I’m unaware of any mainstream implementations of this on Android, and it would require root. This app doesn’t; I’m like 90% sure it’s all done over ADB (Android Debug Bridge), which every Android device supports.

With the USB tether acting as a network proxy, there is simply no routing/NAT going on, so there is no way for the carrier to detect what’s going on. It just appears to be data coming from the phone.

Ottimo, penso anche che il meccanismo sia estendibile anche ad altre piattaforme, non si finisce mai di imparare dai commenti! Prossima mossa, vedere se veramente il tethering USB non viene scoperto dai carrier.

Performance test con Appcelerator Titanium

Ci sono tante scelte che possono portare o non portare all’uso di un framework mobile come Appcelerator Titanium. Tra queste, sicuramente, le performance delle applicazioni realizzate.

Per fare alcuni test ho usato il progetto KitchenSink, fornito da Titanium stessa come “banco di prova” per dimostrare quello di cui e’ capace. Effettivamente la meraviglia c’e’ stata, vedere la stessa identica app (a livello di sorgente JavaScript) girare su un Android e su un iPhone riprendendo aspetto e comportamenti tipici del sistema applicativo.

Titanium infatti crea un progetto in codice nativo (Android o iPhone) dal file Javascript di origine e quel progetto viene poi compilato per il dispositivo. Non ci sono quindi librerie grafiche intermedie di supporto e, a meno di personalizzazioni grafiche, il look’nd feel dell’applicazione realizzata e’ quello del particolare dispositivo dove si andra’ ad eseguire. Quindi conta molto la bonta’ del codice generato nella valutazione delle performance. Ovvio che nessun codice generato automaticamente per uno scenario medio-complesso puo’ essere allo stesso livello di un codice scritto a manina e ottimizzato per quella specifica esigenza, ma a volte le differenze sono trascurabili.

Purtroppo non e’ successo cosi’ per una delle viste di Titanium, composta da una ListView per Android o da una UITableView per iPhone un po’ complessa. Come si puo’ vedere dal video, le performance sono bassine su Android, sotto l’usabile, mentre rimangono soddisfacenti su iPhone.

Continue reading ‘Performance test con Appcelerator Titanium’ »

Che editor usare per Appcelerator Titanium?

Configurato l’ambiente di sviluppo, e’ ora di scrivere la prima applicazione con Appcelerator Titanium. Una volta creato il progetto, ci si accorge pero’ che non c’e’ modo di editarlo. Quindi niente autocompletamento del codice, niente reference dei metodi e documentazione inline mentre si scrive, niente refactoring e facilitazioni varie. A meno di qualche trucchetto.

In primis, si puo’ usare Notepad++ con un’apposito plugin che permettera’ l’autocompletamento del codice.

Se invece si cerca qualcosa di piu’ integrato, si puo’ passare ad Eclipse, utilizzando Aptana Studio ed alcune configurazioni aggiuntive. Aptana perche’ mette a disposizione un editor per file Javascript sia in versione standalone, sia come plugin per Eclipse, e perche’ di recente e’ stata acquistata proprio da Appcelerator, una mossa che fa presagire una futura forte integrazione tra i due.

Scaricato ed installato il plugin di Aptana per Eclipse, l’autocompletamento del codice piu’ essere ottenuto grazie a questo utile post in cui c’e’ un programma php per convertire le API doc di Appcelerator Titanium nell’header JavaScript. Per generare quello relativo al Mobile SDK 1.5.1 ecco cosa ho fatto:

wget http://jamesdlow.googlecode.com/svn/trunk/Eclipse/Aptana/Titanium/titanium.php
wget http://developer.appcelerator.com/apidoc/mobile/1.5.1/api.json
sudo apt-get install php-cli
php titanium.php > timobile.js

Il seguente video mostra invece come configurare Eclipse ed abilitare quindi l’autocompletamento:

Continue reading ‘Che editor usare per Appcelerator Titanium?’ »

Nokia e Microsoft: il terzo polo del mondo mobile

L’unione tra Nokia e Microsoft in una partnership dove la l’azienda finlandese produrra’ “cellulari” equipaggiati con Windows Phone 7 mi ha toccato abbastanza profondamente per una serie di motivi.

Innanzitutto l’importanza strategica di una decisione del genere: dal mio punto di vista Nokia negli ultimi anni avra’ anche prodotto nuovi telefoni, ma non e’ riuscita ad innovare sul software. Esattamente un anno fa annuncio’ al Mobile World Congress del 2010 l’alleanza con Intel per creare la piattaforma Meego, ma dopo 363 giorni esatti non si e’ visto un solo prototipo pronto per il mercato. Microsoft, dal canto suo, dopo aver lanciato Windows Phone 7, sta cercando con il massimo interesse sviluppatori che realizzino applicazioni per il suo nuovo sistema operativo, ma la diffusione sul mercato di quest’ultimo e’ ancora bassissima, quindi e’ poco appetibile. Entrambe hanno qualcosa che all’altra interessa, e sono interessate all’altra per qualcosa che gli manca: Nokia possiede device e utenti fidelizzati, Microsoft software e strumenti per lo sviluppo. Una collaborazione cosi’ perfettamente incastrata e simbiotica tra i due giganti e’ capace di grandi cose, se poi Nokia viene pure pagata da Microsoft per la partnership…

Stiamo parlando di due aziende che hanno una poderosa batteria di cannoni a disposizione dei reparti marketing e commerciale: con un’intelligente mossa che e’ andata oltre la visione a breve periodo che le vedeva concorrenti per le molliche del mobile (Symbian-MeeGo vs WP7),  qualcuno ha capito che nel medio-lungo periodo l’unione fa la forza, e che e’ inutile sprecare munizione una contro l’altra per prendersi gli avanzi, ma e’ molto piu’ profiquo impiegarle assieme per fiaccare la concorrenza (Apple e Android) e tentare di mordere la torta intera. Utenti, sviluppatori e partner commerciali si trovera’ il modo per convincerli, pubblicita’ dopo pubblicita’, iniziativa dopo iniziativa, mossa dopo mossa.

Dopo questo annuncio e a meno di strani cambiamenti, sono abbastanza convinto che Windows Phone 7 ora abbia tutte le carte giuste per diventare il terzo polo nel mondo dello sviluppo per mobile.

Poi certo, ogni grande allenza, se fatta nel mezzo di una battaglia, porta con se’ morti e feriti. Alcuni di questi potrebbero essere:

Continue reading ‘Nokia e Microsoft: il terzo polo del mondo mobile’ »

Appcelerator Titanium su Ubuntu 10.10 64bit

Incuriosito dalla possibilita’ di sviluppare applicazioni multipiattaforma per Android e iPhone, ho provato ad installare Appcelerator Titanium sulla mia Linuxbox, una Ubunto 10.10 a 64 bit. Di seguito i passi seguiti.

Ho scaricato il runtime di Titanium Developer per Linux 64 bit. La versione corrente e’ la 1.2.2. L’ho scompattato e l’ho lanciato. Alla richiesta del percorso di installazione, sotto la mia home oppure in /opt/titanium, ho scelto la seconda opzione, e il programma si e’ chiuso senza altri segni di vita. Per farlo funzionare, sono stato costretto a far partire l’installer con
sudo ./Titanium\ Developer
eseguendo poi a fine installazione un cambio di permessi delle cartelle create con il comando
sudo chown -R rainbowbreeze:rainbowbreeze /opt/titanium

Scaricati i due pacchetti necessari, l’installer si chiude di nuovo con l’errore
symbol lookup error: /usr/lib/libgdk-x11-2.0.so.0: undefined symbol: g_malloc_n
che sembra essere ben documentato e risolto:
cd /opt/titanium (oppure cd ~/.titanium se l’avete installato nella vostra home)
rm runtime/linux/1.0.0/libgobject-2.0.*
rm runtime/linux/1.0.0/libglib-2.0.*
rm runtime/linux/1.0.0/libgio-2.0.*
rm runtime/linux/1.0.0/libgthread-2.0.*

Superato anche questo ostacolo, ho rilanciato l’installazione, accettato le condizioni di contratto e mi trovo davanti un nuovo errore:
icedteanp plugin error: Failed to run /etc/alternatives/../../bin/java.  For more detail rerun “firefox -g” in a terminal window.
anche questo errore e’ documentato e risolto:
sudo aptitude remove openjdk-6-jre icedtea6-plugin
sudo aptitude install sun-java6-jre sun-java6-plugin sun-java6-fonts

Continue reading ‘Appcelerator Titanium su Ubuntu 10.10 64bit’ »

Forzare l’uso della connessione mobile (3G o GPRS) con il WiFi in Android

In Android, l’attivazione della connessione WiFi porta immediatamente alla disattivazione delle altre connessioni, compresa quella mobile, e tutto il traffico dati viene instradato su di essa. Assieme ad una serie di vantaggi, come l’indubbio risparmio per connessioni dati a consumo e il guadagno di velocita’, questo comportampo porta ad alcuni problemi, principalmente:

  • La sospensione senza preavviso di connessioni gia’ in piedi sulla rete dati mobile
  • L’impossibilita’ di accedere a quei servizi legati alla SIM. Ad esempio, un operatori telefonico potrebbe effettuano un accredito direttamente all’utente basandosi sulla SIM che genera il traffico. Con il Wifi, non si puo’ ottenere questa informazione.

Quindi, per quanto l’utilita’ di forzare l’uso della connessione dati mobile per raggiungere un certo indirizzo all’interno della proprio applicazione possa sembrare scontata, purtroppo Android non mette a disposizione nessuna API documentata e sicura per farlo, ma occorre passare per una serie di workaround che funzionano solo dalla versione 2.2.

/**
 * Enable mobile connection for a specific address
 * @param context a Context (application or activity)
 * @param address the address to enable
 * @return true for success, else false
 */
private boolean forceMobileConnectionForAddress(Context context, String address) {
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    if (null == connectivityManager) {
        Log.debug(TAG_LOG, "ConnectivityManager is null, cannot try to force a mobile connection");
        return false;
    }

    //check if mobile connection is available and connected
    State state = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
    Log.debug(TAG_LOG, "TYPE_MOBILE_HIPRI network state: " + state);
    if (0 == state.compareTo(State.CONNECTED) || 0 == state.compareTo(State.CONNECTING)) {
        return true;
    }

    //activate mobile connection in addition to other connection already activated
    int resultInt = connectivityManager.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableHIPRI");
    Log.debug(TAG_LOG, "startUsingNetworkFeature for enableHIPRI result: " + resultInt);

    //-1 means errors
    // 0 means already enabled
    // 1 means enabled
    // other values can be returned, because this method is vendor specific
    if (-1 == resultInt) {
        Log.error(TAG_LOG, "Wrong result of startUsingNetworkFeature, maybe problems");
        return false;
    }
    if (0 == resultInt) {
        Log.debug(TAG_LOG, "No need to perform additional network settings");
        return true;
    }

    //find the host name to route
    String hostName = StringUtil.extractAddressFromUrl(address);
    Log.debug(TAG_LOG, "Source address: " + address);
    Log.debug(TAG_LOG, "Destination host address to route: " + hostName);
    if (TextUtils.isEmpty(hostName)) hostName = address;

    //create a route for the specified address
    int hostAddress = lookupHost(hostName);
    if (-1 == hostAddress) {
        Log.error(TAG_LOG, "Wrong host address transformation, result was -1");
        return false;
    }
    //wait some time needed to connection manager for waking up
    try {
        for (int counter=0; counter<10; counter++) {
            State checkState = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
            if (0 == checkState.compareTo(State.CONNECTED))
                break;
            Thread.sleep(1000);
        }
    } catch (InterruptedException e) {
        //nothing to do
    }
    boolean resultBool = connectivityManager.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, hostAddress);
    Log.debug(TAG_LOG, "requestRouteToHost result: " + resultBool);
    if (!resultBool)
        Log.error(TAG_LOG, "Wrong requestRouteToHost result: expected true, but was false");

    return resultBool;
}

In pratica, se non lo e’ gia’, viene attivata la connessione mobile grazie alla chiamata
startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, “enableHIPRI”)
per poi creare una route all’indirizzo da raggiungere che forza il passaggio sulla connessione mobile
requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, hostAddress)

Continue reading ‘Forzare l’uso della connessione mobile (3G o GPRS) con il WiFi in Android’ »

Pinch zoom in Android

La possibilita’ di zoomare e muovere le immagini usando gesture delle dita, il cosiddetto pinch-zoom, era una particolarita’ introdotta e supportata agli inizi solo dall’iPhone. Nel tempo, anche Android ha incluso questa feature, purtroppo pero’ senza api semplificate per implementarla nel proprio codice. Per fortuna, Luke Hutchison ha creato android-multitouch-controller, una libreria che permette di gestire la cosa abbastanza agevolmente, con supporto sia allo zoom, che al rotate. Licenziata sia sotto i termini dell’Apache License v2 e della GPL v2, puo’ essere usata in ogni progetto.

Personalmente ho fatto mio questo pezzo di codice, inglobandolo nelle Rainbowlibs e creando un controllo da usare bello che pronto nelle proprie applicazioni, la RainbowZoomableImageView, una specie di ImageView meno potente, che pero’ supporta il pitch-zoom out of the box, senza configurazioni aggiuntive.

Seguendo gli esempi proposti dalla libreria di Luke, ho creato la classe RainbowZoomableImageView.Img e la RainbowZoomableImageView che la utilizza, a cui ho aggiunto alcuni metodi di comodo, tra cui quelli per impostare l’immagine da visualizzare e per settare lo zoom manualmente, fondamentale per quei rari dispositivi che non hanno uno schermo o una versione di Android con il multitouch. Questi metodi sono assignImage(…) e incrementScale(…).

Come esempio di utilizzo di si puo’ buttare un occhio sull’activity ActImageFullScreen,java e sul relativo layout actimagefullscreen.xml di WebcamHolmes, un’altro progetto opensource che sto sviluppando.

La dichiarazione del layout e’ molto semplice, ed include solo il controllo personalizzato e quello per fare lo zoom










Mentre nell’activity, queste sono le parti salienti per gestire il tutto:

public class ActImageFullscreen extends Activity {

  private final static float ZOOM_INCREMENT = 0.1f;
  private static final int DIALOG_PROGRESS = 10;
  private static final int OPTIONMENU_SHOWHIDE_ZOOM = 10;
  private RainbowZoomableImageView mImage;
  private ActivityHelper mActivityHelper;
  private ZoomControls mZoomControls;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    //make the view fullscreen
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(R.layout.actimagefullscreen);

    //load the image
    mImage = (RainbowZoomableImageView) findViewById(R.id.actimagefullscreen_imgMain);
    mImage.setBackgroundColor(Color.BLACK);
    //choose how to obtain the bitmap with the image
    Bitmap bitmap = ... //BitmapFactory.decodeStream(fis);
    mImage.assignImage(getResources(), bitmap);

    //link zoom press with image in/out zoom
    mZoomControls = (ZoomControls) findViewById(R.id.actimagefullscreen_zoomcontrols);
    mZoomControls.setOnZoomInClickListener(mOnZoomInClickListener);
    mZoomControls.setOnZoomOutClickListener(mOnZoomOutClickListener);
  }

  @Override
  protected void onPause() {
    mImage.onPause();
    super.onPause();
  }

  @Override
  protected void onResume() {
    super.onResume();
    mImage.onResume(getResources());
  }

  private OnClickListener mOnZoomInClickListener = new OnClickListener() {
    public void onClick(View v) {
      mImage.incrementScale(ZOOM_INCREMENT);
    }
  };

  private OnClickListener mOnZoomOutClickListener = new OnClickListener() {
    public void onClick(View v) {
      mImage.incrementScale(-ZOOM_INCREMENT);
    }
  };
}

Facile, no? ;)

android.app.Application, static singleton per variabili globali e NullPointerException

Leggendo l’Android reference guide a proposito di android.app.Application, troviamo scritto:

Base class for those who need to maintain global application state. You can provide your own implementation by specifying its name in your AndroidManifest.xml’s <application> tag, which will cause that class to be instantiated for you when the process for your application/package is created.
There is normally no need to subclass Application. In most situation, static singletons can provide the same functionality in a more modular way.

Sembra quindi il posto giusto, e piu’ elegante di un singleton, per mettere le nostre variabili globali quando non occorre fare cose troppo complicate e per inizializzarle al primo avvio dell’applicazione, mediante override del metodo OnCreate() della classe base. Qualcosa del genere:

La classe App.java

package it.rainbowbreeze.singleton;

public class App extends Application {
public static int myGlobalStaticValue;
public int myGlobalValue;

  @Override
  public void onCreate() {
    super.onCreate();
    myGlobalStaticValue = 10;
    myGlobalValue = 20;
  }
}

La modifica all’AndroidManifest.xml


E la chiamata da fare in un metodo qualunque di un’Activity, ad esempio:

//access to static field
int value = App.myGlobalStaticValue;
//access to non static fields
int value = ((App)context.getApplication()).myGlobalValue;

Da principio tutto funzionava, poi pero’ mi sono accorto di un problema non banale: che di tanto in tanto le variabili persistite in questo modo non mantengono il loro valore, soprattutto dopo che l’applicazione rimane in background per parecchio tempo o si fanno nel frattempo diverse altre cose col dispositivo.

Basito da questo comportamento, mi sono messo a cercare in giro, ed ecco che escono fuori le prime conferme, di cui riporto un estratto:

Consider a case – your app goes into the background because somebody is calling you (Phone app is in the foreground now). In this case && under some other conditions (check the above link for what they could be) the OS may kill your application process, including the Application subclass instance. As a result the state is lost. When you later return to the application, then the OS will restore its activity stack and Application subclass instance, however the myState field will be null.

This was an unplesant surprise for us in production. Believe me Android kills processes, it just depends on RAM state and other factors described in the documentation. It was a nightmare for us so I just share my real experience. Well we did not have this on emulators, but in real world some devices are ‘overloaded’ with apps, so killing a background process is a normal situation. Yes, if user then decides to get the app up into foreground – the OS restores its stack including the Application instance, however there will not be your static data you count on unless you persisted it.

In pratica, anche il contenuto dell’Application, come quello di ogni altro static singleton, puo’ venire ripulito dal sistema operativo. Come fare quindi per ovviare a questo problema?

Continue reading ‘android.app.Application, static singleton per variabili globali e NullPointerException’ »

Augmented reality e dizionari, ecco cos’e’ possibile fare

World Lens e’ un prodotto di Quest Visual che traduce a volo quello che viene inquadrato dalla videocamera dell’iPhone, dall’inglese allo spagnolo e viceversa. Un’ottimo esempio di augmented reality basata sul riconoscimento di oggetti, e non sulla “semplice” sovrapposizione di informazione per mezzo della posizione GPS.

C’e’ qualche feedback di chi l’ha usato? E’ davvero cosi’ efficiente come mostrato nel video?

adb devices, ???????? no permissions e come risolverlo

Come nel caso del Nexus One, puo’ capitare che sotto Linux l’ADB non riesca a collegarsi correttamente ad un nuovo smartphone Android, mostrando un malinconico messaggio quando viene lanciato il comando adb devices.
List of devices attached
????????????     no permissions

Esiste un modo per risolvere completamente il problema, che permette di capire qual’e’ il giusto idVendor da aggiundere al file .rules di udev, indipendentemente dal device in uso.

per prima cosa, occorre lanciare il comando
lsusb -v | grep idVendor

l’output restituito potrebbe essere il seguente:
idVendor           0x1d6b Linux Foundation
idVendor           0x045e Microsoft Corp.
idVendor           0x1d6b Linux Foundation
idVendor           0x1d6b Linux Foundation
idVendor           0x05c6 Qualcomm, Inc.
idVendor           0×5986 Acer, Inc

Ora, staccando il device e rilanciando il comando, ho visto che la riga che cambia e’ la seguente
idVendor           0x05c6 Qualcomm, Inc.
che contiene quindi l’idVendor che mi serve per configurare udev.

Continue reading ‘adb devices, ???????? no permissions e come risolverlo’ »