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;