auto import from //branches/cupcake/...@132276
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index d8fd3fa..0ca4248 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -16,26 +16,28 @@
 
 package com.android.browser;
 
+import com.google.android.googleapps.IGoogleLoginService;
+import com.google.android.googlelogin.GoogleLoginServiceConstants;
+
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.AlertDialog;
-import android.app.SearchManager;
 import android.app.ProgressDialog;
+import android.app.SearchManager;
 import android.content.ActivityNotFoundException;
-import android.content.res.AssetManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
-import android.content.DialogInterface.OnCancelListener;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.content.pm.ActivityInfo;
+import android.content.DialogInterface.OnCancelListener;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.res.AssetManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.Cursor;
@@ -75,10 +77,10 @@
 import android.os.SystemProperties;
 import android.preference.PreferenceManager;
 import android.provider.Browser;
-import android.provider.Contacts.Intents.Insert;
 import android.provider.Contacts;
 import android.provider.Downloads;
 import android.provider.MediaStore;
+import android.provider.Contacts.Intents.Insert;
 import android.text.IClipboard;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
@@ -86,8 +88,6 @@
 import android.util.Config;
 import android.util.Log;
 import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.MenuItem.OnMenuItemClickListener;
 import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -98,6 +98,8 @@
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.MenuItem.OnMenuItemClickListener;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 import android.view.animation.AnimationSet;
@@ -120,17 +122,13 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 import android.widget.Toast;
-import android.widget.ZoomRingController;
-
-import com.google.android.googleapps.IGoogleLoginService;
-import com.google.android.googlelogin.GoogleLoginServiceConstants;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URL;
@@ -141,9 +139,9 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Vector;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import java.util.Vector;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
@@ -205,7 +203,7 @@
                     if (googleUser == null || !hostedUser.equals(googleUser)) {
                         String domain = hostedUser.substring(hostedUser.lastIndexOf('@')+1);
                         homepage = "http://www.google.com/m/a/" + domain + "?client=ms-" +
-                            SystemProperties.get("ro.com.google.clientid", "unknown");
+                            SystemProperties.get("persist.sys.com.google.clientid", "unknown");
                     }
                 } catch (RemoteException ignore) {
                     // Login service died; carry on
@@ -745,9 +743,6 @@
                     }
                 }
             };
-            
-        // Show a tutorial for the new zoom interaction (the method ensure we only show it once)
-        ZoomRingController.showZoomTutorialOnce(this);
     }
 
     @Override
@@ -1589,10 +1584,8 @@
                 PackageManager pm = getPackageManager();
                 Intent send = new Intent(Intent.ACTION_SEND);
                 send.setType("text/plain");
-                List<ResolveInfo> list = pm.queryIntentActivities(send,
-                        PackageManager.MATCH_DEFAULT_ONLY);
-                menu.findItem(R.id.share_page_menu_id).setVisible(
-                        list.size() > 0);
+                ResolveInfo ri = pm.resolveActivity(send, PackageManager.MATCH_DEFAULT_ONLY);
+                menu.findItem(R.id.share_page_menu_id).setVisible(ri != null);
 
                 // If there is only 1 window, the text will be "New window"
                 final MenuItem windows = menu.findItem(R.id.windows_menu_id);
@@ -1699,10 +1692,8 @@
                 PackageManager pm = getPackageManager();
                 Intent send = new Intent(Intent.ACTION_SEND);
                 send.setType("text/plain");
-                List<ResolveInfo> list = pm.queryIntentActivities(send,
-                        PackageManager.MATCH_DEFAULT_ONLY);
-                menu.findItem(R.id.share_link_context_menu_id).setVisible(
-                        list.size() > 0);
+                ResolveInfo ri = pm.resolveActivity(send, PackageManager.MATCH_DEFAULT_ONLY);
+                menu.findItem(R.id.share_link_context_menu_id).setVisible(ri != null);
                 if (type == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
                     break;
                 }
@@ -3337,8 +3328,8 @@
             //     that matches.
             Intent intent = new Intent(Intent.ACTION_VIEW);
             intent.setDataAndType(Uri.parse(url), mimetype);
-            if (getPackageManager().queryIntentActivities(intent,
-                        PackageManager.MATCH_DEFAULT_ONLY).size() != 0) {
+            if (getPackageManager().resolveActivity(intent,
+                        PackageManager.MATCH_DEFAULT_ONLY) != null) {
                 // someone knows how to handle this mime type with this scheme, don't download.
                 try {
                     startActivity(intent);
@@ -4392,7 +4383,7 @@
                     R.string.google_search_base, l.getLanguage(),
                     l.getCountry().toLowerCase())
                     + "client=ms-"
-                    + SystemProperties.get("ro.com.google.clientid", "unknown")
+                    + SystemProperties.get("persist.sys.com.google.clientid", "unknown")
                     + "&source=android-" + GOOGLE_SEARCH_SOURCE_SUGGEST + "&q=%s";
         } else {
             QuickSearch_G = url;
diff --git a/src/com/android/browser/BrowserHistoryPage.java b/src/com/android/browser/BrowserHistoryPage.java
index f7e97c0..c529fe8 100644
--- a/src/com/android/browser/BrowserHistoryPage.java
+++ b/src/com/android/browser/BrowserHistoryPage.java
@@ -183,10 +183,8 @@
         PackageManager pm = getPackageManager();
         Intent send = new Intent(Intent.ACTION_SEND);
         send.setType("text/plain");
-        List<ResolveInfo> list = pm.queryIntentActivities(send,
-                PackageManager.MATCH_DEFAULT_ONLY);
-        menu.findItem(R.id.share_link_context_menu_id).setVisible(
-                list.size() > 0);
+        ResolveInfo ri = pm.resolveActivity(send, PackageManager.MATCH_DEFAULT_ONLY);
+        menu.findItem(R.id.share_link_context_menu_id).setVisible(ri != null);
         
         super.onCreateContextMenu(menu, v, menuInfo);
     }
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 06ccf01..35b4096 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -53,7 +53,7 @@
     // Public variables for settings
     // NOTE: these defaults need to be kept in sync with the XML
     // until the performance of PreferenceManager.setDefaultValues()
-    // is improved. 
+    // is improved.
     private boolean loadsImagesAutomatically = true;
     private boolean javaScriptEnabled = true;
     private boolean pluginsEnabled = true;
@@ -64,12 +64,12 @@
     private boolean saveFormData = true;
     private boolean openInBackground = false;
     private String defaultTextEncodingName;
-    private String homeUrl = "http://www.google.com/m?client=ms-" + 
-        SystemProperties.get("ro.com.google.clientid", "unknown");
+    private String homeUrl = "http://www.google.com/m?client=ms-" +
+        SystemProperties.get("persist.sys.com.google.clientid", "unknown");
     private boolean loginInitialized = false;
     private boolean autoFitPage = true;
     private boolean showDebugSettings = false;
-    
+
     // Development settings
     public WebSettings.LayoutAlgorithm layoutAlgorithm =
         WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
@@ -78,7 +78,7 @@
     private boolean tracing = false;
     private boolean lightTouch = false;
     private boolean navDump = false;
-    // Browser only settings 
+    // Browser only settings
     private boolean doFlick = false;
 
     // Private preconfigured values
@@ -88,17 +88,17 @@
     private static int defaultFixedFontSize = 13;
     private static WebSettings.TextSize textSize =
         WebSettings.TextSize.NORMAL;
-    
+
     // Preference keys that are used outside this class
     public final static String PREF_CLEAR_CACHE = "privacy_clear_cache";
     public final static String PREF_CLEAR_COOKIES = "privacy_clear_cookies";
     public final static String PREF_CLEAR_HISTORY = "privacy_clear_history";
     public final static String PREF_HOMEPAGE = "homepage";
-    public final static String PREF_CLEAR_FORM_DATA = 
+    public final static String PREF_CLEAR_FORM_DATA =
             "privacy_clear_form_data";
-    public final static String PREF_CLEAR_PASSWORDS = 
+    public final static String PREF_CLEAR_PASSWORDS =
             "privacy_clear_passwords";
-    public final static String PREF_EXTRAS_RESET_DEFAULTS = 
+    public final static String PREF_EXTRAS_RESET_DEFAULTS =
             "reset_default_preferences";
     public final static String PREF_DEBUG_SETTINGS = "debug_menu";
     public final static String PREF_GEARS_SETTINGS = "gears_settings";
@@ -119,7 +119,7 @@
     public final static int MAX_TEXTVIEW_LEN = 80;
 
     private TabControl mTabControl;
-    
+
     // Single instance of the BrowserSettings for use in the Browser app.
     private static BrowserSettings sSingleton;
 
@@ -127,7 +127,7 @@
     // observer.
     private HashMap<WebSettings,Observer> mWebSettingsToObservers =
         new HashMap<WebSettings,Observer>();
- 
+
     /*
      * An observer wrapper for updating a WebSettings object with the new
      * settings after a call to BrowserSettings.update().
@@ -179,7 +179,7 @@
             s.setAllowFileAccess(false);
         }
     }
-   
+
     /**
      * Load settings from the browser app's database.
      * NOTE: Strings used for the preferences must match those specified
@@ -190,7 +190,7 @@
      *            observers of this object.
      */
     public void loadFromDb(Context ctx) {
-        SharedPreferences p = 
+        SharedPreferences p =
                 PreferenceManager.getDefaultSharedPreferences(ctx);
 
         // Set the default value for the plugins path to the application's
@@ -203,27 +203,27 @@
         //PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences);
         syncSharedPreferences(p);
     }
-    
+
     /* package */ void syncSharedPreferences(SharedPreferences p) {
-        homeUrl = 
+        homeUrl =
             p.getString(PREF_HOMEPAGE, homeUrl);
-        loadsImagesAutomatically = p.getBoolean("load_images", 
+        loadsImagesAutomatically = p.getBoolean("load_images",
                 loadsImagesAutomatically);
-        javaScriptEnabled = p.getBoolean("enable_javascript", 
+        javaScriptEnabled = p.getBoolean("enable_javascript",
                 javaScriptEnabled);
-        pluginsEnabled = p.getBoolean("enable_plugins", 
+        pluginsEnabled = p.getBoolean("enable_plugins",
                 pluginsEnabled);
         pluginsPath = p.getString("plugins_path", pluginsPath);
         javaScriptCanOpenWindowsAutomatically = !p.getBoolean(
-            "block_popup_windows", 
+            "block_popup_windows",
             !javaScriptCanOpenWindowsAutomatically);
-        showSecurityWarnings = p.getBoolean("show_security_warnings", 
+        showSecurityWarnings = p.getBoolean("show_security_warnings",
                 showSecurityWarnings);
-        rememberPasswords = p.getBoolean("remember_passwords", 
+        rememberPasswords = p.getBoolean("remember_passwords",
                 rememberPasswords);
-        saveFormData = p.getBoolean("save_formdata", 
+        saveFormData = p.getBoolean("save_formdata",
                 saveFormData);
-        boolean accept_cookies = p.getBoolean("accept_cookies", 
+        boolean accept_cookies = p.getBoolean("accept_cookies",
                 CookieManager.getInstance().acceptCookie());
         CookieManager.getInstance().setAcceptCookie(accept_cookies);
         openInBackground = p.getBoolean("open_in_background", openInBackground);
@@ -240,23 +240,23 @@
         defaultTextEncodingName =
                 p.getString(PREF_DEFAULT_TEXT_ENCODING,
                         defaultTextEncodingName);
-        
-        showDebugSettings = 
+
+        showDebugSettings =
                 p.getBoolean(PREF_DEBUG_SETTINGS, showDebugSettings);
         // Debug menu items have precidence if the menu is visible
         if (showDebugSettings) {
-            boolean small_screen = p.getBoolean("small_screen", 
-                    layoutAlgorithm == 
+            boolean small_screen = p.getBoolean("small_screen",
+                    layoutAlgorithm ==
                     WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
             if (small_screen) {
                 layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN;
             } else {
-                boolean normal_layout = p.getBoolean("normal_layout", 
+                boolean normal_layout = p.getBoolean("normal_layout",
                         layoutAlgorithm == WebSettings.LayoutAlgorithm.NORMAL);
                 if (normal_layout) {
                     layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL;
                 } else {
-                    layoutAlgorithm = 
+                    layoutAlgorithm =
                             WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
                 }
             }
@@ -271,7 +271,7 @@
         }
         update();
     }
-    
+
     public String getPluginsPath() {
         return pluginsPath;
     }
@@ -279,23 +279,23 @@
     public String getHomePage() {
         return homeUrl;
     }
-    
+
     public void setHomePage(Context context, String url) {
         Editor ed = PreferenceManager.
-                getDefaultSharedPreferences(context).edit();      
+                getDefaultSharedPreferences(context).edit();
         ed.putString(PREF_HOMEPAGE, url);
         ed.commit();
         homeUrl = url;
     }
-    
+
     public boolean isLoginInitialized() {
         return loginInitialized;
     }
-    
+
     public void setLoginInitialized(Context context) {
         loginInitialized = true;
         Editor ed = PreferenceManager.
-                getDefaultSharedPreferences(context).edit();      
+                getDefaultSharedPreferences(context).edit();
         ed.putBoolean("login_initialized", loginInitialized);
         ed.commit();
     }
@@ -327,11 +327,11 @@
     public boolean doFlick() {
         return doFlick;
     }
-    
+
     public boolean showDebugSettings() {
         return showDebugSettings;
     }
-    
+
     public void toggleDebugSettings() {
         showDebugSettings = !showDebugSettings;
         navDump = showDebugSettings;
@@ -341,7 +341,7 @@
     /**
      * Add a WebSettings object to the list of observers that will be updated
      * when update() is called.
-     * 
+     *
      * @param s A WebSettings object that is strictly tied to the life of a
      *            WebView.
      */
@@ -423,12 +423,12 @@
         db.clearUsernamePassword();
         db.clearHttpAuthUsernamePassword();
     }
-    
+
     /*package*/ void resetDefaultPreferences(Context context) {
-        SharedPreferences p = 
+        SharedPreferences p =
             PreferenceManager.getDefaultSharedPreferences(context);
         p.edit().clear().commit();
-        PreferenceManager.setDefaultValues(context, R.xml.browser_preferences, 
+        PreferenceManager.setDefaultValues(context, R.xml.browser_preferences,
                 true);
     }
 
diff --git a/src/com/android/browser/GearsBaseDialog.java b/src/com/android/browser/GearsBaseDialog.java
index 3379537..638ba27 100644
--- a/src/com/android/browser/GearsBaseDialog.java
+++ b/src/com/android/browser/GearsBaseDialog.java
@@ -68,6 +68,7 @@
   public static final int UPDATE_ICON = 5;
   public static final int REQUEST_ICON = 6;
   public static final int PAUSE_REQUEST_ICON = 7;
+  public static final int CLEAR_REQUEST_ICON = 8;
 
   protected final String LOCAL_DATA_STRING = "localData";
   protected final String LOCAL_STORAGE_STRING = "localStorage";
@@ -256,7 +257,12 @@
     if (rsc == 0) {
       return;
     }
-    View view = v.findViewById(rsc);
+    View view;
+    if (v == null) {
+      view = findViewById(rsc);
+    } else {
+      view = v.findViewById(rsc);
+    }
     if (view != null) {
       view.setVisibility(View.GONE);
     }
@@ -269,7 +275,12 @@
     if (rsc == 0) {
       return;
     }
-    View view = v.findViewById(rsc);
+    View view;
+    if (v == null) {
+      view = findViewById(rsc);
+    } else {
+      view = v.findViewById(rsc);
+    }
     if (view != null) {
       view.setVisibility(View.VISIBLE);
     }
diff --git a/src/com/android/browser/GearsFilePickerDialog.java b/src/com/android/browser/GearsFilePickerDialog.java
index 0bb28d4..10cc03f 100644
--- a/src/com/android/browser/GearsFilePickerDialog.java
+++ b/src/com/android/browser/GearsFilePickerDialog.java
@@ -18,6 +18,7 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Color;
@@ -27,6 +28,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.provider.MediaStore;
+import android.provider.MediaStore.Images.Media;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -41,6 +43,7 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.RandomAccessFile;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -66,6 +69,7 @@
   private static String SINGLE_FILE = "SINGLE_FILE";
 
   private static ImagesLoad mImagesLoader;
+  private static SystemThumbnails mSystemThumbnails;
   private FilePickerAdapter mAdapter;
   private String mSelectionMode;
   private boolean mMultipleSelection;
@@ -117,12 +121,19 @@
     view.setAdapter(mAdapter);
     view.setOnTouchListener(this);
 
+    showView(null, R.id.selection);
     setSelectionText();
 
     mImagesLoader = new ImagesLoad(mAdapter);
     mImagesLoader.setAdapterView(view);
-    Thread thread = new Thread(mImagesLoader);
-    thread.start();
+    Thread imagesLoaderThread = new Thread(mImagesLoader);
+    imagesLoaderThread.setPriority(Thread.MIN_PRIORITY);
+    imagesLoaderThread.start();
+
+    mSystemThumbnails = new SystemThumbnails();
+    Thread systemThumbnailsThread = new Thread(mSystemThumbnails);
+    systemThumbnailsThread.setPriority(Thread.MIN_PRIORITY);
+    systemThumbnailsThread.start();
   }
 
   public void setSelectionText() {
@@ -164,19 +175,89 @@
   }
 
   /**
+   * Utility class encapsulating thumbnails information
+   * for a file (file image id and magic number)
+   */
+  class SystemThumbnailInfo {
+    private long mID;
+    private long mMagicNumber;
+    SystemThumbnailInfo(long anID, long magicNumber) {
+      mID = anID;
+      mMagicNumber = magicNumber;
+    }
+    public long getID() {
+      return mID;
+    }
+    public long getMagicNumber() {
+      return mMagicNumber;
+    }
+  }
+
+  /**
+   * Utility class to pre-fetch the thumbnails information
+   */
+  class SystemThumbnails implements Runnable {
+    private Map<String, SystemThumbnailInfo> mThumbnails;
+
+    SystemThumbnails() {
+      mThumbnails = Collections.synchronizedMap(new HashMap());
+    }
+
+    public void run() {
+      Uri query = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+      Cursor cursor = mActivity.managedQuery(query,
+          new String[] { "_id", "mini_thumb_magic", "_data" },
+          null, null, null);
+
+      if (cursor != null) {
+        int count = cursor.getCount();
+        for (int i = 0; i < count; i++) {
+          cursor.moveToPosition(i);
+          SystemThumbnailInfo info = new SystemThumbnailInfo(cursor.getLong(0),
+                                                             cursor.getLong(1));
+          mThumbnails.put(cursor.getString(2), info);
+        }
+      }
+    }
+
+    public SystemThumbnailInfo getThumb(String path) {
+      SystemThumbnailInfo ret = mThumbnails.get(path);
+      if (ret == null) {
+        Uri query = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+        Cursor cursor = mActivity.managedQuery(query,
+          new String[] { "_id", "mini_thumb_magic", "_data" },
+              "_data = ?", new String[] { path }, null);
+        if (cursor != null && cursor.moveToFirst()) {
+          long longid = cursor.getLong(0);
+          long miniThumbMagic = cursor.getLong(1);
+          ret = new SystemThumbnailInfo(longid, miniThumbMagic);
+          mThumbnails.put(path, ret);
+        }
+      }
+      return ret;
+    }
+  }
+
+  /**
    * Utility class to load and generate thumbnails
    * for image files
    */
   class ImagesLoad implements Runnable {
-    private Map mImagesMap;
     private Vector mImagesPath;
     private BaseAdapter mAdapter;
     private AdapterView mAdapterView;
     private Vector<FilePickerElement> mElements;
     private Handler mLoaderHandler;
+    // We use the same value as in Camera.app's ImageManager.java
+    private static final int BYTES_PER_MINI_THUMB = 10000;
+    private final byte[] mMiniThumbData = new byte[BYTES_PER_MINI_THUMB];
+    private final int MINI_THUMB_DATA_FILE_VERSION = 3;
+    private final int THUMBNAIL_SIZE = 128;
+    private Map<Uri, RandomAccessFile> mThumbFiles;
 
     ImagesLoad(BaseAdapter adapter) {
       mAdapter = adapter;
+      mThumbFiles = Collections.synchronizedMap(new HashMap());
     }
 
     public void signalChanges() {
@@ -185,57 +266,130 @@
       mHandler.sendMessage(message);
     }
 
-    /**
-     * TODO: use the same thumbnails as the photo app
-     * (bug: http://b/issue?id=1497927)
-     */
-    public String getThumbnailPath(String path) {
-      File f = new File(path);
-      String myPath = f.getParent() + "/.thumbnails";
-      File d = new File(myPath);
-      if (!d.exists()) {
-        d.mkdirs();
+    private String getMiniThumbFileFromUri(Uri uri) {
+      if (uri == null) {
+        return null;
       }
-      return myPath + "/" + f.getName();
+      String directoryName =
+          Environment.getExternalStorageDirectory().toString() +
+          "/dcim/.thumbnails";
+      String path = directoryName + "/.thumbdata" +
+          MINI_THUMB_DATA_FILE_VERSION + "-" + uri.hashCode();
+      return path;
     }
 
-    public boolean saveImage(String path, Bitmap image) {
-      boolean ret = false;
+    private Bitmap getMiniThumbFor(Uri uri, long longid, long magic) {
+      RandomAccessFile thumbFile = mThumbFiles.get(uri);
       try {
-        FileOutputStream outStream = new FileOutputStream(path);
-        ret = image.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
-      } catch (IOException e) {
-        Log.e(TAG, "IOException ", e);
+        if (thumbFile == null) {
+          String path = getMiniThumbFileFromUri(uri);
+          File f = new File(path);
+          if (f.exists()) {
+            thumbFile = new RandomAccessFile(f, "rw");
+            mThumbFiles.put(uri, thumbFile);
+          }
+        }
+      } catch (IOException ex) {
       }
-      return ret;
+      if (thumbFile == null) {
+        return null;
+      }
+      byte[] data = getMiniThumbFromFile(thumbFile, longid,
+                                         mMiniThumbData, magic);
+      if (data != null) {
+        return BitmapFactory.decodeByteArray(data, 0, data.length);
+      }
+      return null;
     }
 
+    private byte [] getMiniThumbFromFile(RandomAccessFile r,
+                                         long id,
+                                         byte [] data,
+                                         long magicCheck) {
+      if (r == null)
+        return null;
+      long pos = id * BYTES_PER_MINI_THUMB;
+      RandomAccessFile f = r;
+      synchronized (f) {
+        try {
+          f.seek(pos);
+          if (f.readByte() == 1) {
+            long magic = f.readLong();
+            if (magic != magicCheck) {
+              return null;
+            }
+            int length = f.readInt();
+            f.read(data, 0, length);
+            return data;
+          } else {
+            return null;
+          }
+        } catch (IOException ex) {
+          long fileLength;
+          try {
+            fileLength = f.length();
+          } catch (IOException ex1) {
+            fileLength = -1;
+          }
+          return null;
+        }
+      }
+    }
+
+    /*
+     * Returns a thumbnail saved by the Camera application
+     * We pre-cached the information (image id and magic number)
+     * when starting the filepicker.
+     */
+    public Bitmap getSystemThumbnail(FilePickerElement elem) {
+      if (elem.askedForSystemThumbnail() == false) {
+        elem.setAskedForSystemThumbnail(true);
+        String path = elem.getPath();
+        SystemThumbnailInfo thumbInfo = mSystemThumbnails.getThumb(path);
+        if (thumbInfo != null) {
+          Uri query = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+          Bitmap bmp = getMiniThumbFor(query, thumbInfo.getID(),
+                                       thumbInfo.getMagicNumber());
+          if (bmp != null) {
+            return bmp;
+          }
+        }
+      }
+      return null;
+    }
+
+    /*
+     * Generate a thumbnail for a given element
+     */
     public Bitmap generateImage(FilePickerElement elem) {
       String path = elem.getPath();
       Bitmap finalImage = null;
       try {
-        String thumbnailPath = getThumbnailPath(path);
-        if (enableSavedThumbnails) {
-          File thumbnail = new File(thumbnailPath);
-          if (thumbnail.exists()) {
-            finalImage = BitmapFactory.decodeFile(thumbnailPath);
-            if (finalImage != null) {
-              return finalImage;
-            }
-          }
+
+        // First we try to get the thumbnail from the system
+        // (created by the Camera application)
+
+        finalImage = getSystemThumbnail(elem);
+        if (finalImage != null) {
+          return finalImage;
         }
+
+        // No thumbnail was found, so we have to create one
+        //
+        // First we get the image information and
+        // determine the sampleSize
+
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inJustDecodeBounds = true;
         BitmapFactory.decodeFile(path, options);
 
         int width = options.outWidth;
         int height = options.outHeight;
-        int size = 128;
         int sampleSize = 1;
-        if (width > size || height > size) {
+        if (width > THUMBNAIL_SIZE || height > THUMBNAIL_SIZE) {
           sampleSize = 2;
-          while ((width / sampleSize > size)
-                 || (height / sampleSize > size)) {
+          while ((width / sampleSize > 2*THUMBNAIL_SIZE)
+                 || (height / sampleSize > 2*THUMBNAIL_SIZE)) {
             sampleSize += 2;
           }
         }
@@ -245,16 +399,37 @@
         if (originalImage == null) {
           return null;
         }
-        finalImage = Bitmap.createScaledBitmap(originalImage, size, size, true);
-        if (enableSavedThumbnails) {
-          if (saveImage(thumbnailPath, finalImage)) {
-            if (mDebug) {
-              Log.v(TAG, "Saved thumbnail for file " + path);
-            }
-          } else {
-            Log.e(TAG, "Could NOT Save thumbnail for file " + path);
-          }
+
+        // Let's rescale the image to a THUMBNAIL_SIZE
+
+        width = originalImage.getWidth();
+        height = originalImage.getHeight();
+
+        if (width > height) {
+          width = (int) (width * (THUMBNAIL_SIZE / (double) height));
+          height = THUMBNAIL_SIZE;
+        } else {
+          height = (int) (height * (THUMBNAIL_SIZE / (double) width));
+          width = THUMBNAIL_SIZE;
         }
+        originalImage = Bitmap.createScaledBitmap(originalImage,
+                                                  width, height, true);
+
+        // We can now crop the image to a THUMBNAIL_SIZE rectangle
+
+        width = originalImage.getWidth();
+        height = originalImage.getHeight();
+        int d = 0;
+        if (width > height) {
+          d = (width - height) / 2;
+          finalImage = Bitmap.createBitmap(originalImage, d, 0,
+                                           THUMBNAIL_SIZE, THUMBNAIL_SIZE);
+        } else {
+          d = (height - width) / 2;
+          finalImage = Bitmap.createBitmap(originalImage, 0, d,
+                                           THUMBNAIL_SIZE, THUMBNAIL_SIZE);
+        }
+
         originalImage.recycle();
       } catch (java.lang.OutOfMemoryError e) {
         Log.e(TAG, "Intercepted OOM ", e);
@@ -267,24 +442,41 @@
                                        GearsBaseDialog.PAUSE_REQUEST_ICON);
       mLoaderHandler.sendMessageAtFrontOfQueue(message);
     }
-    public void postIconRequest(FilePickerElement item, int position) {
+
+    public void clearIconRequests() {
+      Message message = Message.obtain(mLoaderHandler,
+                                       GearsBaseDialog.CLEAR_REQUEST_ICON);
+      mLoaderHandler.sendMessageAtFrontOfQueue(message);
+    }
+
+    public void postIconRequest(FilePickerElement item,
+                                int position,
+                                boolean front) {
       if (item == null) {
         return;
       }
-      Message message = mLoaderHandler.obtainMessage(
-          GearsBaseDialog.REQUEST_ICON, position, 0, item);
-      mLoaderHandler.sendMessage(message);
+      if (item.isImage() && (item.getThumbnail() == null))  {
+        Message message = mLoaderHandler.obtainMessage(
+            GearsBaseDialog.REQUEST_ICON, position, 0, item);
+        if (front) {
+          mLoaderHandler.sendMessageAtFrontOfQueue(message);
+        } else {
+          mLoaderHandler.sendMessage(message);
+        }
+      }
     }
 
-    public void generateIcon(FilePickerElement elem) {
+    public boolean generateIcon(FilePickerElement elem) {
       if (elem.isImage()) {
         if (elem.getThumbnail() == null) {
           Bitmap image = generateImage(elem);
           if (image != null) {
             elem.setThumbnail(image);
+            return true;
           }
         }
       }
+      return false;
     }
 
     public void setAdapterView(AdapterView view) {
@@ -295,8 +487,12 @@
       Looper.prepare();
       mLoaderHandler = new Handler() {
         public void handleMessage(Message msg) {
-          int visibleElements = 10;
-          if (msg.what == GearsBaseDialog.PAUSE_REQUEST_ICON) {
+          if (msg.what == GearsBaseDialog.CLEAR_REQUEST_ICON) {
+            mLoaderHandler.removeMessages(
+                GearsBaseDialog.PAUSE_REQUEST_ICON);
+            mLoaderHandler.removeMessages(
+                GearsBaseDialog.REQUEST_ICON);
+          } else if (msg.what == GearsBaseDialog.PAUSE_REQUEST_ICON) {
             try {
               // We are busy (likely) scrolling the view,
               // so we just pause the loading.
@@ -307,24 +503,15 @@
               Log.e(TAG, "InterruptedException ", e);
             }
           } else if (msg.what == GearsBaseDialog.REQUEST_ICON) {
+            FilePickerElement elem = (FilePickerElement) msg.obj;
+            if (generateIcon(elem)) {
+              signalChanges();
+            }
             try {
-              Thread.sleep(10);
+              Thread.sleep(50);
             } catch (InterruptedException e) {
               Log.e(TAG, "InterruptedException ", e);
             }
-            FilePickerElement elem = (FilePickerElement) msg.obj;
-            int firstVisiblePosition = mAdapterView.getFirstVisiblePosition();
-            // If the elements are not visible, we slow down the update
-            // TODO: replace this by a low-priority thread
-            if ((msg.arg1 < firstVisiblePosition - visibleElements)
-                && msg.arg1 > firstVisiblePosition + visibleElements) {
-              try {
-                Thread.sleep(100);
-              } catch (InterruptedException e) {
-              }
-            }
-            generateIcon(elem);
-            signalChanges();
           }
         }
       };
@@ -348,6 +535,7 @@
     private String mExtension;
     private Bitmap mThumbnail;
     private boolean mIsImage;
+    private boolean mAskedForSystemThumbnail;
 
     public FilePickerElement(String name, BaseAdapter adapter) {
       this(name, adapter, null);
@@ -365,6 +553,7 @@
       mParent = parent;
       mIsSelected = false;
       mChildren = null;
+      mAskedForSystemThumbnail = false;
     }
 
     public FilePickerElement(String path,
@@ -378,10 +567,19 @@
       mParent = parent;
       mAdapter = adapter;
       mExtension = null;
+      mAskedForSystemThumbnail = false;
 
       setIcons();
     }
 
+    public void setAskedForSystemThumbnail(boolean value) {
+      mAskedForSystemThumbnail = value;
+    }
+
+    public boolean askedForSystemThumbnail() {
+      return mAskedForSystemThumbnail;
+    }
+
     public void setIcons() {
       if (mPath.isDirectory()) {
         if (mDirectoryIcon == null) {
@@ -486,10 +684,7 @@
     public void refresh() {
       mChildren = null;
       Vector children = getChildren();
-      for (int i = 0; i < children.size(); i++) {
-        FilePickerElement elem = (FilePickerElement) children.get(i);
-        mImagesLoader.postIconRequest(elem, i);
-      }
+      mImagesLoader.clearIconRequests();
     }
 
     public Vector getChildren() {
@@ -519,11 +714,19 @@
     public FilePickerElement getChild(int position) {
       Vector children = getChildren();
       if (children != null) {
-        return (FilePickerElement) children.get(position);
+        FilePickerElement elem = (FilePickerElement) children.get(position);
+        return elem;
       }
       return null;
     }
 
+    /*
+     * Depending on the type, we return either
+     * the icon (mIcon) or the back icon (mBackIcon).
+     * If we can load a system thumbnail we do this
+     * synchronously and return it, else we ask the
+     * mImagesLoader to generate a thumbnail for us.
+     */
     public Bitmap getIcon(int position) {
       if (mIsParent) {
         return mBackIcon;
@@ -532,7 +735,12 @@
         if (mThumbnail != null) {
           return mThumbnail;
         } else {
-          mImagesLoader.postIconRequest(this, position);
+          Bitmap image = mImagesLoader.getSystemThumbnail(this);
+          if (image != null) {
+            mThumbnail = image;
+            return mThumbnail;
+          }
+          mImagesLoader.postIconRequest(this, position, true);
         }
       }
       return mIcon;
@@ -586,9 +794,6 @@
       mImagesMap = Collections.synchronizedMap(new HashMap());
       mImagesSelected = new HashMap();
 
-      Uri requests[] = { MediaStore.Images.Media.INTERNAL_CONTENT_URI,
-                         MediaStore.Images.Media.EXTERNAL_CONTENT_URI };
-
       String startingPath = Environment.getExternalStorageDirectory().getPath();
       mRootElement = new FilePickerElement(startingPath, "SD Card", this);
       mCurrentElement = mRootElement;