Tout se passe dans le fichier /data/data/com.android.providers.media/databases/external.db. Cette base de données SQLite 3 semble garder en mémoire la liste des fichiers musicaux, photos, vidéos... Pour ces derniers, il existe un champ datetaken, c'est lui qui détermine l'ordre d'affichage dans la Galerie. Si après avoir copié vos photos/vidéos sur le téléphone, elles sont dans le mauvais ordre, c'est probablement que l'application Galerie les ajoute dans l'ordre du répertoire et met une mauvaise valeur pour datetaken.

Nous allons récupérer ce fichier, remettre des valeurs de datetaken qui correspondent à la date de prise des photos, et renvoyer ce fichier sur le téléphone.

Récupérer external.db

Pour ça c'est très simple, avec votre téléphone rooté et ADB :

ordi$ adb shell
android$ su
android# cp /data/data/com.android.providers.media/databases/external.db \
             /sdcard/
android# exit
android$ exit
ordi$ adb pull /sdcard/external.db .

Important : faites une sauvegarde de ce fichier. En cas de pépin, vous pourrez toujours restaurer la version originale.

Réécrire les dates de prise de vue des photos/vidéos

L'idée est d'utiliser la date contenue dans le nom du fichier (exemple : IMG_20130313_173025.jpg), de la convertir en timestamp, et de l'écrire dans le champ datetaken. J'ai écrit un petit script bash qui fait ça automatiquement. Il vous faudra l'utilitaire sqlite3.

#!/bin/bash
# Adrien Vergé, 2013-03-13
# Reset photos from gallery in the right order

db="external.db"

function is_numeric() {
	local val=$1
	if ((val)) 2>/dev/null; then
		return 0
	fi
	return 1
}

if [ ! -f "$db" ]; then
	echo "  ERROR   File '$db' does not exist"
	exit 1
fi

req="SELECT _id, _data FROM files WHERE files._data LIKE '%/DCIM/Camera/%';"
list=$(sqlite3 "$db" "$req")

for row in $list; do
	id=$(echo $row | awk '{split($0,a,"|"); print a[1]}')
	filename=$(echo $row | awk '{split($0,a,"|"); print a[2]}')
	filename=$(basename "$filename")
	if ! is_numeric "$id"; then
		echo "  ERROR   Wrong id: $id"
		continue
	fi

	# parse date
	date=$(echo "$filename" | sed -e "s/^[A-Z]\+_\([0-9]\{4\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)_\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\(_.\)\?.\w\+$/\1-\2-\3 \4:\5:\6/")
	timestamp=$(date -d "$date" +%s 2> /dev/null)
	if [ $? -ne 0 ] || ! is_numeric "$timestamp"; then
		echo "  ERROR   Wrong filename: $filename"
		continue
	fi
	datetaken="${timestamp}000"

	req="UPDATE files SET datetaken = '$datetaken' WHERE _id = $id;"
	result=$(sqlite3 "$db" "$req" 2>&1)
	if [ $? -ne 0 ] || [ -n "$result" ]; then
		echo "  ERROR   With request: $req"
		continue
	fi

	echo "  UPDATED $filename	$datetaken"
done

Enregistrez-le par exemple sous update-media-db.sh, rendez-le exécutable et lancez-le :

ordi$ chmod +x update-media-db.sh
ordi$ ./update-media-db.sh
  UPDATED VID_20120130_220004.mp4	1327978804000
  UPDATED PANO_20120113_200223.jpg	1326502943000
  UPDATED IMG_20120113_201326.jpg	1326503606000
  UPDATED IMG_20120113_201341.jpg	1326503621000
...

Si tout s'est bien passé, votre base de données external.db est prête à être renvoyée sur le téléphone !

Renvoyer external.db

ordi$ adb push external.db /sdcard/
ordi$ adb shell
android$ su
android# cp /sdcard/external.db /data/data/com.android.providers.media/databases/
android# chown u0_a14:u0_a14 /data/data/com.android.providers.media/databases/external.db
android# chmod 660 /data/data/com.android.providers.media/databases/external.db
android# rm /sdcard/external.db
android# reboot

N'oubliez pas l'étape du chown/chmod, sinon les nouvelles photos que vous prendrez ne s'ajouteront pas à la Galerie. Il est possible que vous deviez remplacer u0_a14:u0_a14 par la valeur qui convient à votre téléphone. Cette valeur est l'identifiant de l'utilisateur associé à l'application Galerie, pour lui permettre de modifier la base de données. Faites un :

android# ls -l /data/data/com.android.providers.media/databases/

pour voir quelle est la bonne valeur à appliquer.