Category Archives: code

Using GestureDetector to detect Long Touch, Double Tap, Scroll or other touch events in Android

Most of the Android UI elements already come with some easy way to detect and handle touch events. For example have a look to the following code:

TextView myTextView = (TextView) findViewById(R.id.myTextView);
myTextView.setOnLongClickListener(new OnLongClickListener() {
	@Override
	public boolean onLongClick(View v) {
		Log.i("MyExample", "A Long Click has been detected");
		return true;
	}
});

When you touch the myTextView long enough, you will see in the logs the print A Long Click has been detected.
In other cases, however, in which this kind of solution is not available, or doesn’t fit your needs. For example

  • the UI element does not let you set a listener for the action you want to detect. You can’t set a double click listener for a TextView widget, and other elements, like the Map Overlay, can only detect a very limited set of actions;
  • you need more information about the action, e.g. the exact position of the pointer (finger).

In those cases the best solution is to use the GestureDetector.

The GestureDetector works a little bit differently from what you may be used to. In fact it is not listening to the actions: it is in charge of translating what a widget or another UI element sees as a generic touch event, to a more specific action. Fortunately any UI element gives you some way to handle a generic touch event.

Let’s see a complete example of how to put the GestureDetector to work within a simple Activity class.

package com.example;
 
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
 
public class GestureDetectorExample extends Activity {
    static private String TAG = "GestureDetectorExample";
    private GestureDetector mGestureDetector;
    private TextView mTextView;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        mTextView = (TextView) findViewById(R.id.myTextView);
        mTextView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return mGestureDetector.onTouchEvent(event);
            }
        });
 
        mGestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
            @Override
            public void onLongPress(MotionEvent e) {
                Log.d(TAG, "Long Press event");
            }
 
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                Log.d(TAG, "Double Tap event");
                return true;
            }
 
            @Override
            public boolean onDown(MotionEvent e) {
                return true;
            }
        });
        mGestureDetector.setIsLongpressEnabled(true);
    }
}

Let’s see now what happens in the example:

  • a TouchListener is set for the TextView;
  • a GestureDetector object is instantiated, with a reference to an object which implements the OnGestureListener interface (we’ll come back on this later);
  • when a touch event is detected by the TextView, the method onTouch is called;
  • the method onTouch calls the GestureDetector and pass it the MotionEvent, an object containing the information needed by the GestureDetector to recognize the different touch events;
  • the GestureDetector uses the MotionEvent object to identify the touch events;
  • once identified the type of the event, the GestureDetector calls the appropriate method of the OnGestureListener (double tap, long press, etc.).

It’s time to run the program and perform some long tap, or double click on the TextView while keeping an eye on the logs in the LogCat.

A couple of notes.

  • The onDown method.
    If you try to remove it you will see that the onDoubleTap method is not called anymore. Same if the onDown method returns false. So keep in mind that to make onDoubleTap work you must have a onDown method returning true.
  • SimpleOnGestureListener class vs OnGestureListener interface
    In the example, the SimpleOnGestureListener class is used. It is a commodity class that implements the OnGestureListener interface. If you decide to implement the OnGestureListener interface you must implement all its methods, even you only need to handle one event. When you inherit from the SimpleOnGestureListener, instead, you will only override the methods you need.

Let’s now see another example, this time using the Overlay from the Google Maps API.

package com.example;
 
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
 
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
 
public class GestureDetectExampleMap extends MapActivity {
    private static String TAG = "GestureDetectorExampleMap";
    MapView mMapView;
    GestureDetector mGestureDetector;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        mMapView = (MapView) findViewById(R.id.MapView);
 
        mMapView.getOverlays().add(new Overlay() {
            @Override
            public boolean onTouchEvent(MotionEvent e, MapView mapView) {
                mGestureDetector.onTouchEvent(e);
                return super.onTouchEvent(e, mapView);
            }
        });
 
        mGestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
            @Override
            public void onLongPress(MotionEvent e) {
                Log.d(TAG, "Long Press event");
            }
 
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                Log.d(TAG, "Double Tap event");
                return true;
            }
 
            @Override
            public boolean onDown(MotionEvent e) {
                return true;
            }
        });
    }
 
    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }
}

The GestureDetector part is exactly the same, but in this case the GestureDetector.onTouchEvent is called by the map Overlay, and unlike a generic View element, there is no need to instantiate a Listener for it.
A touch event will go through the following steps:

  • the touch event triggers the onTouchEvent inside the Overlay;
  • the onTouchEvent of the Overlay calls the correspondent method of the GestureDetector and pass it the MotionEvent, an object containing the information needed by the GestureDetector to recognize the different touch events;
  • the GestureDetector uses the MotionEvent object to identify the touch events;
  • once identified the type of the event, the GestureDetector calls the appropriate method of the OnGestureListener (double tap, long press, etc.).

For lazy people only: download a zip file with the two examples.

It may be useful for you to have a look to a few articles that I also consulted before writing this article:

Feel free to comment to ask any question, correct any mistake or suggest any improvement.

C++

Sono sempre più convinto che Bjarne Stroustrup abbia qualche disturbo associativo che gli impedisce di scrivere libri in maniera ordinata o creare linguaggi di programmazione in cui la complicazione delle operazioni più semplici sembra essere la norma più che l’eccezione.

F-Spot – Quando i due punti sono di troppo

Un grosso grosso baco affligge le ultime versioni di F-Spot, impedendo agli utenti di usare fotografie che contengano nel nome del file il carattere ‘ : ‘ (due punti), che pure è ampiamente usato su Linux (diversi software di gestione delle foto hanno una funzione di rinomina dei file in base a data e orario).

La soluzione, senza scendere troppo nei dettagli, riguarda un aggiornamento del database di F-Spot e nel rinominare i nomi dei file delle foto incriminate. Sperando in una patch e in tempi migliori.

Scoprendo C#

Sto dando un’occhiata a C#. Non che mi interessi particolarmente, almeno non per ora, ma è una tacca in più da aggiungere al coltello1 . Per quanto si dica che C# derivi da C++ e non da Java, a me sembra che da Java ci sia stata una nemmeno tanto celata scopiazzatura. Probabilmente non sto dicendo nulla di nuovo, ma nel mio piccolo questa è una rivelazione, quasi un sollievo.

Per quello che ho visto finora le differenze sono minime: rispetto a Java il C# ha il goto, e in alcuni condizioni non si possono accodare i case dello switch. Per il resto è roba fatta con la copia carbone: dal Garbage Collector, fino alle funzioni che si chiamano “Metodi” proprio come in Java (in C/C++ si chiamano ancora funzioni).

In compenso altri tipi di copiatura non sono andati a buon fine. Secondo le intenzioni di Microsoft il frame work .NET dovrebbe permettere di avere programmi estremamente portabili. Peccato che mentre la Java Virtual Machine giri veramente dappertutto (Windows, Unix, telefonini, Linux e telefonini con Linux) l’equivalente di casa Microsoft giri decentemente solo su Windows. Microsoft non si è mai degnata di scrivere una versione di .NET per sistemi operativi che non fossero controllati direttamente da lei. Direte voi: c’è Mono l’implementazione opensource .NET sponsorizzata da Novell sotto la minaccia di non ben chiari accordi commerciali proprio con Microsoft. Tuttavia quanti programmi scritti per .NET girano anche su Mono? E quanti scritti per Mono riescono a funzionare anche su Windows?

Nonostante queste mie perplessità .NET e C# (insieme a ASP.NET a quanto mi dicono) si diffondono sempre di più. Non riesco a capirne l’esigenza visto che Java, a parte la salute del produttore2 , non ha nulla da invidiare a C#. Nemmeno l’ambiente di sviluppo, il Microsoft Visual C#, può reggere il confronto con gli IDE disponibili per Java come Eclipse e NetBeans che, tra parentesi, sono totalmente gratuiti e open source.

Insomma se uno mi venisse a chiedere in quale linguaggio sia meglio sviluppare i propri progetti (o quelli degli altri se ben pagati) risponderei che occorre scegliere caso per caso, ma difficilmente metterei C# tra le possibili opzioni.

  1. e comunque spero di non dover usare troppo questo coltello: sono ingegnere prima che informatico []
  2. Sun era ormai al tracollo ed è stata acquistata da Oracle, mentre Microsoft ora si appresta a raccogliere qualche miliardo in più grazie ai suoi stessi errori []

Make Gengo and Simple Tags live together in WordPress

As I already pointed out before, Gengo and Simple Tags plugins are not made to live together. Luckily there is a fix that must be applied every time you update or reinstall the Simple Tags plugin on your WordPress. The fix consists in a small edit of the simple-tags.client.php file, which is part of Simple Tags.

I made a page that will link to the fixed version of this file, edited by me following the original instructions. What you need to do is to download the file and copy it in the right directory in your WordPress installation. Further information can be found on the dedicated page.

I cannot assure you I can keep this page updated, but I’m quite sure it will be updated as much as I will update plugins on my wordpress installations.

So, now you only need to visit the Gengo and Simple Tags fix page.

Twitter badge script updated

I just made a small update to the twitter script hosted on this website. For further details read the original post.

PS: For those who don’t know what it is about, very bad! It’s a great, magnificent and brilliant effort to improve the original Twitter Html/JavaScript based badge.

Podencoder script with Single Pass option

iPod TouchI recently bought an iPod Touch, very nice gadget, but with a very bad video section: only a few formats accepted, forcing me to recode almost all my video files.
I found the best way to do it on Linux is to use the Podencoder script by Mark Pilgrim. It mainly needs mencoder and mp4box, both easily installable on Ubuntu and Debian. The only problem is that my computer is really slow, and encoding an H.264 video seems to be never ending, also because the Podencoder script automatically use a Two Passes encoding, which gives the best quality, but also almost double the encoding time.
So I added an option to Podencoder to choose the Single Pass (the Two Passes is still the default action). If you want to encode using Single Pass just use the -1 option, like in this example:


podencoder -1 input_video.avi

You can download the modified script from here: podencoder.

Remember to make it executable. It’s also good to place is in the local bin path. To do all those actions just copy and paste the following lines into your terminal (you need to be root):


wget http://www.soccio.it/code/ipod/podencoder -O /usr/local/bin/podencoder
chmod +x /usr/local/bin/podencoder

If you are using Ubuntu or other sudo enabled distros, you can use these lines instead, without the need of being root:


sudo wget http://www.soccio.it/code/ipod/podencoder -O /usr/local/bin/podencoder
sudo chmod +x /usr/local/bin/podencoder

Nautilus Script Encode for iPod VideoI also prepared a few lines script to encode your videos from the Nautilus file manager. The result videos will be placed into your Desktop. Just place the Nautilus Scripts Encode for iPod – Single Pass and Encode for iPod – Two Passes into ~/.gnome2/nautilus-scripts. Again: remember to make them executable. Again, to download and place the two Nautilus scripts in the right place just copy and paste the following lines into your terminal.


cd ~/.gnome2/nautilus-scripts/
wget "http://www.soccio.it/code/ipod/Encode for iPod - Two Passes"
wget "http://www.soccio.it/code/ipod/Encode for iPod - Single Pass"
chmod +x *
cd

Clickable links in Twitter html/js badge

In standard Twitter badges, web addresses you write in your posts are not clickable and you need to copy and paste the link in the address bar to visit them. I partly modified the Twitter html/js badge javascript code to automatically recognize the http addresses and change them to proper links.

Twitter linkable badge

If you want to use it, you only need to change the code of your html badger, substituting “http://twitter.com/javascripts/blogger.js” in “http://www.soccio.it/code/twitter/blogger.js“.

Twitter code edit

If you want you can also download the file and place it in another place, or just copy the code and insert it inside your html code.

Magnificent Update!

Alan Hogan made an excellent work on the original script solving a bug and also making the @user clickable as well! Now everytime you address a twit to another user, the script will automatically insert a link to the addressed user twitter page. A great applause to Alan!

@User clickable

The old script has been updated: if you hot-linked it, you won’t need to change anything and it will start working automatically. Otherwise download it again.

Small Update [23 August 2008]

As asked by Jimmy in a comment, the script has been modified to handle links which are written without the classic http://. Now the script also recognizes addresses starting by www. So if you post an address remember to write the www at the beginning (unless there is already a http or other protocols prefix).

This is a quick and dirty edit maybe could be improved. if you hot-linked it, you won’t need to change anything and it will start working automatically. Otherwise download it again.

License [25 October 2008]

Alan and I were asked about the license. We decided the better license for this snippet is the BSD License. This means you can modify and distribute this code in both source and binary form, as long as you keep the copyright notice. A copy of the license is available as standalone file and is also included in the blogger.js file itself.