Bug 816547: Make sure the Bitmap is accessed in UI thread in LWTheme. [r=mfinkle]

--HG--
extra : rebase_source : 7f99818a2395fdc4f03b24927f706a4f81197038
This commit is contained in:
Sriram Ramasubramanian 2013-02-26 11:42:24 -08:00
Родитель a8e0a1a69c
Коммит 2560db822a
1 изменённых файлов: 74 добавлений и 77 удалений

Просмотреть файл

@ -18,13 +18,17 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.Shader; import android.graphics.Shader;
import android.os.Build; import android.os.Build;
import android.os.Looper;
import android.os.Handler;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.view.Gravity; import android.view.Gravity;
import android.view.View; import android.view.View;
import android.view.ViewParent; import android.view.ViewParent;
import java.net.URL;
import java.io.InputStream; import java.io.InputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
@ -34,15 +38,13 @@ public class LightweightTheme implements GeckoEventListener {
private static final String LOGTAG = "GeckoLightweightTheme"; private static final String LOGTAG = "GeckoLightweightTheme";
private Application mApplication; private Application mApplication;
private Handler mHandler;
private Bitmap mBitmap; private Bitmap mBitmap;
private int mColor; private int mColor;
private boolean mIsLight; private boolean mIsLight;
public static interface OnChangeListener { public static interface OnChangeListener {
// This is the View's default post.
// This is required to post the change/rest on UI thread.
public boolean post(Runnable action);
// The View should change its background/text color. // The View should change its background/text color.
public void onLightweightThemeChanged(); public void onLightweightThemeChanged();
@ -54,8 +56,10 @@ public class LightweightTheme implements GeckoEventListener {
public LightweightTheme(Application application) { public LightweightTheme(Application application) {
mApplication = application; mApplication = application;
mHandler = new Handler(Looper.getMainLooper());
mListeners = new ArrayList<OnChangeListener>(); mListeners = new ArrayList<OnChangeListener>();
// unregister isn't needed as the lifetime is same as the application.
GeckoAppShell.getEventDispatcher().registerEventListener("LightweightTheme:Update", this); GeckoAppShell.getEventDispatcher().registerEventListener("LightweightTheme:Update", this);
GeckoAppShell.getEventDispatcher().registerEventListener("LightweightTheme:Disable", this); GeckoAppShell.getEventDispatcher().registerEventListener("LightweightTheme:Disable", this);
} }
@ -70,76 +74,6 @@ public class LightweightTheme implements GeckoEventListener {
mListeners.remove(listener); mListeners.remove(listener);
} }
public void setLightweightTheme(String headerURL) {
try {
// Get the image and convert it to a bitmap.
URL url = new URL(headerURL);
InputStream stream = url.openStream();
mBitmap = BitmapFactory.decodeStream(stream);
stream.close();
// The download could be HTTP for previews, so let's be sure we have a bitmap
if (mBitmap == null || mBitmap.getWidth() == 0 || mBitmap.getHeight() == 0) {
mBitmap = null;
return;
}
// To find the dominant color only once, take the bottom 25% of pixels.
DisplayMetrics dm = mApplication.getResources().getDisplayMetrics();
int maxWidth = Math.max(dm.widthPixels, dm.heightPixels);
int height = (int) (mBitmap.getHeight() * 0.25);
Bitmap cropped = Bitmap.createBitmap(mBitmap, mBitmap.getWidth() - maxWidth,
mBitmap.getHeight() - height,
maxWidth, height);
mColor = BitmapUtils.getDominantColor(cropped, false);
double luminance = (0.2125 * ((mColor & 0x00FF0000) >> 16)) +
(0.7154 * ((mColor & 0x0000FF00) >> 8)) +
(0.0721 * (mColor &0x000000FF));
mIsLight = (luminance > 110) ? true : false;
notifyListeners();
} catch(java.net.MalformedURLException e) {
mBitmap = null;
} catch(java.io.IOException e) {
mBitmap = null;
}
}
public void resetLightweightTheme() {
if (mBitmap != null) {
// Reset the bitmap.
mBitmap = null;
// Post the reset on the UI thread.
for (OnChangeListener listener : mListeners) {
final OnChangeListener oneListener = listener;
oneListener.post(new Runnable() {
@Override
public void run() {
oneListener.onLightweightThemeReset();
}
});
}
}
}
public void notifyListeners() {
if (mBitmap == null)
return;
// Post the change on the UI thread.
for (OnChangeListener listener : mListeners) {
final OnChangeListener oneListener = listener;
oneListener.post(new Runnable() {
@Override
public void run() {
oneListener.onLightweightThemeChanged();
}
});
}
}
@Override @Override
public void handleMessage(String event, JSONObject message) { public void handleMessage(String event, JSONObject message) {
try { try {
@ -149,15 +83,78 @@ public class LightweightTheme implements GeckoEventListener {
int mark = headerURL.indexOf('?'); int mark = headerURL.indexOf('?');
if (mark != -1) if (mark != -1)
headerURL = headerURL.substring(0, mark); headerURL = headerURL.substring(0, mark);
setLightweightTheme(headerURL); try {
// Get the image and convert it to a bitmap.
URL url = new URL(headerURL);
InputStream stream = url.openStream();
final Bitmap bitmap = BitmapFactory.decodeStream(stream);
stream.close();
mHandler.post(new Runnable() {
public void run() {
setLightweightTheme(bitmap);
}
});
} catch(MalformedURLException e) {
} catch(IOException e) {
}
} else if (event.equals("LightweightTheme:Disable")) { } else if (event.equals("LightweightTheme:Disable")) {
resetLightweightTheme(); mHandler.post(new Runnable() {
public void run() {
resetLightweightTheme();
}
});
} }
} catch (Exception e) { } catch (Exception e) {
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e); Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
} }
} }
/**
* Set a new lightweight theme with the given bitmap.
* Note: This should be called on the UI thread to restrict accessing the
* bitmap to a single thread.
*
* @param bitmap The bitmap used for the lightweight theme.
*/
private void setLightweightTheme(Bitmap bitmap) {
mBitmap = bitmap;
if (mBitmap == null || mBitmap.getWidth() == 0 || mBitmap.getHeight() == 0) {
mBitmap = null;
return;
}
// To find the dominant color only once, take the bottom 25% of pixels.
DisplayMetrics dm = mApplication.getResources().getDisplayMetrics();
int maxWidth = Math.max(dm.widthPixels, dm.heightPixels);
int height = (int) (mBitmap.getHeight() * 0.25);
Bitmap cropped = Bitmap.createBitmap(mBitmap, mBitmap.getWidth() - maxWidth,
mBitmap.getHeight() - height,
maxWidth, height);
mColor = BitmapUtils.getDominantColor(cropped, false);
double luminance = (0.2125 * ((mColor & 0x00FF0000) >> 16)) +
(0.7154 * ((mColor & 0x0000FF00) >> 8)) +
(0.0721 * (mColor &0x000000FF));
mIsLight = (luminance > 110) ? true : false;
for (OnChangeListener listener : mListeners)
listener.onLightweightThemeChanged();
}
/**
* Reset the lightweight theme.
* Note: This should be called on the UI thread to restrict accessing the
* bitmap to a single thread.
*/
private void resetLightweightTheme() {
if (mBitmap != null) {
// Reset the bitmap.
mBitmap = null;
for (OnChangeListener listener : mListeners)
listener.onLightweightThemeReset();
}
}
/** /**
* A lightweight theme is enabled only if there is an active bitmap. * A lightweight theme is enabled only if there is an active bitmap.