am d023f9a9: Merge change 24829 into eclair

Merge commit 'd023f9a9a90705410250cd86bc6446c738423a99' into eclair-plus-aosp

* commit 'd023f9a9a90705410250cd86bc6446c738423a99':
  Some optizations to wallpaper drawing/scrolling.
This commit is contained in:
Dianne Hackborn
2009-09-14 15:54:08 -07:00
committed by Android Git Automerger
13 changed files with 449 additions and 73 deletions

View File

@@ -22,7 +22,9 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -56,9 +58,96 @@ public class WallpaperManager {
private final Context mContext;
/**
* Special drawable that draws a wallpaper as fast as possible. Assumes
* no scaling or placement off (0,0) of the wallpaper (this should be done
* at the time the bitmap is loaded).
*/
static class FastBitmapDrawable extends Drawable {
private final Bitmap mBitmap;
private final int mWidth;
private final int mHeight;
private int mDrawLeft;
private int mDrawTop;
private FastBitmapDrawable(Bitmap bitmap) {
mBitmap = bitmap;
mWidth = bitmap.getWidth();
mHeight = bitmap.getHeight();
setBounds(0, 0, mWidth, mHeight);
}
@Override
public void draw(Canvas canvas) {
canvas.drawBitmap(mBitmap, mDrawLeft, mDrawTop, null);
}
@Override
public int getOpacity() {
return PixelFormat.OPAQUE;
}
@Override
public void setBounds(int left, int top, int right, int bottom) {
mDrawLeft = left + (right-left - mWidth) / 2;
mDrawTop = top + (bottom-top - mHeight) / 2;
}
@Override
public void setBounds(Rect bounds) {
// TODO Auto-generated method stub
super.setBounds(bounds);
}
@Override
public void setAlpha(int alpha) {
throw new UnsupportedOperationException(
"Not supported with this drawable");
}
@Override
public void setColorFilter(ColorFilter cf) {
throw new UnsupportedOperationException(
"Not supported with this drawable");
}
@Override
public void setDither(boolean dither) {
throw new UnsupportedOperationException(
"Not supported with this drawable");
}
@Override
public void setFilterBitmap(boolean filter) {
throw new UnsupportedOperationException(
"Not supported with this drawable");
}
@Override
public int getIntrinsicWidth() {
return mWidth;
}
@Override
public int getIntrinsicHeight() {
return mHeight;
}
@Override
public int getMinimumWidth() {
return mWidth;
}
@Override
public int getMinimumHeight() {
return mHeight;
}
}
static class Globals extends IWallpaperManagerCallback.Stub {
private IWallpaperManager mService;
private Bitmap mWallpaper;
private Bitmap mDefaultWallpaper;
private static final int MSG_CLEAR_WALLPAPER = 1;
@@ -74,6 +163,7 @@ public class WallpaperManager {
case MSG_CLEAR_WALLPAPER:
synchronized (this) {
mWallpaper = null;
mDefaultWallpaper = null;
}
break;
}
@@ -90,12 +180,19 @@ public class WallpaperManager {
mHandler.sendEmptyMessage(MSG_CLEAR_WALLPAPER);
}
public Bitmap peekWallpaperBitmap(Context context) {
public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
synchronized (this) {
if (mWallpaper != null) {
return mWallpaper;
}
if (mDefaultWallpaper != null) {
return mDefaultWallpaper;
}
mWallpaper = getCurrentWallpaperLocked(context);
if (mWallpaper == null && returnDefault) {
mDefaultWallpaper = getDefaultWallpaperLocked(context);
return mDefaultWallpaper;
}
return mWallpaper;
}
}
@@ -134,48 +231,48 @@ public class WallpaperManager {
fd.close();
} catch (IOException e) {
}
if (bm == null) {
return generateBitmap(context, bm, width, height);
}
} catch (RemoteException e) {
}
return null;
}
private Bitmap getDefaultWallpaperLocked(Context context) {
try {
InputStream is = context.getResources().openRawResource(
com.android.internal.R.drawable.default_wallpaper);
if (is != null) {
int width = mService.getWidthHint();
int height = mService.getHeightHint();
if (width <= 0 || height <= 0) {
// Degenerate case: no size requested, just load
// bitmap as-is.
Bitmap bm = BitmapFactory.decodeStream(is, null, null);
try {
is.close();
} catch (IOException e) {
}
if (bm != null) {
bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
}
return bm;
}
bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
// This is the final bitmap we want to return.
Bitmap newbm = Bitmap.createBitmap(width, height,
bm.getConfig());
newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
Canvas c = new Canvas(newbm);
c.setDensity(DisplayMetrics.DENSITY_DEVICE);
Rect targetRect = new Rect();
targetRect.left = targetRect.top = 0;
targetRect.right = bm.getWidth();
targetRect.bottom = bm.getHeight();
int deltaw = width - targetRect.right;
int deltah = height - targetRect.bottom;
if (deltaw > 0 || deltah > 0) {
// We need to scale up so it covers the entire
// area.
float scale = 1.0f;
if (deltaw > deltah) {
scale = width / (float)targetRect.right;
} else {
scale = height / (float)targetRect.bottom;
}
targetRect.right = (int)(targetRect.right*scale);
targetRect.bottom = (int)(targetRect.bottom*scale);
deltaw = width - targetRect.right;
deltah = height - targetRect.bottom;
// Load the bitmap with full color depth, to preserve
// quality for later processing.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bm = BitmapFactory.decodeStream(is, null, options);
try {
is.close();
} catch (IOException e) {
}
targetRect.offset(deltaw/2, deltah/2);
Paint paint = new Paint();
paint.setFilterBitmap(true);
paint.setDither(true);
c.drawBitmap(bm, null, targetRect, paint);
bm.recycle();
return newbm;
return generateBitmap(context, bm, width, height);
}
} catch (RemoteException e) {
}
@@ -219,9 +316,13 @@ public class WallpaperManager {
* @return Returns a Drawable object that will draw the wallpaper.
*/
public Drawable getDrawable() {
Drawable dr = peekDrawable();
return dr != null ? dr : Resources.getSystem().getDrawable(
com.android.internal.R.drawable.default_wallpaper);
Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);
if (bm != null) {
Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
dr.setDither(false);
return dr;
}
return null;
}
/**
@@ -234,8 +335,51 @@ public class WallpaperManager {
* null pointer if these is none.
*/
public Drawable peekDrawable() {
Bitmap bm = sGlobals.peekWallpaperBitmap(mContext);
return bm != null ? new BitmapDrawable(mContext.getResources(), bm) : null;
Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
if (bm != null) {
Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
dr.setDither(false);
return dr;
}
return null;
}
/**
* Like {@link #peekFastDrawable}, but always returns a valid Drawable. If
* no wallpaper is set, the system default wallpaper is returned.
*
* @return Returns a Drawable object that will draw the wallpaper.
*/
public Drawable getFastDrawable() {
Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);
if (bm != null) {
Drawable dr = new FastBitmapDrawable(bm);
return dr;
}
return null;
}
/**
* Like {@link #peekDrawable()}, but the returned Drawable has a number
* of limitations to reduce its overhead as much as possible: it will
* never scale the wallpaper (only centering it if the requested bounds
* do match the bitmap bounds, which should not be typical), doesn't
* allow setting an alpha, color filter, or other attributes, etc. The
* bounds of the returned drawable will be initialized to the same bounds
* as the wallpaper, so normally you will not need to touch it. The
* drawable also assumes that it will be used in a context running in
* the same density as the screen (not in density compatibility mode).
*
* @return Returns an optimized Drawable object that will draw the
* wallpaper or a null pointer if these is none.
*/
public Drawable peekFastDrawable() {
Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
if (bm != null) {
Drawable dr = new FastBitmapDrawable(bm);
return dr;
}
return null;
}
/**
@@ -429,8 +573,10 @@ public class WallpaperManager {
*/
public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
try {
//Log.v(TAG, "Sending new wallpaper offsets from app...");
ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
windowToken, xOffset, yOffset);
//Log.v(TAG, "...app returning after sending offsets!");
} catch (RemoteException e) {
// Ignore.
}
@@ -466,4 +612,51 @@ public class WallpaperManager {
public void clear() throws IOException {
setResource(com.android.internal.R.drawable.default_wallpaper);
}
static Bitmap generateBitmap(Context context, Bitmap bm, int width, int height) {
if (bm == null) {
return bm;
}
bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
// This is the final bitmap we want to return.
// XXX We should get the pixel depth from the system (to match the
// physical display depth), when there is a way.
Bitmap newbm = Bitmap.createBitmap(width, height,
Bitmap.Config.RGB_565);
newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
Canvas c = new Canvas(newbm);
c.setDensity(DisplayMetrics.DENSITY_DEVICE);
Rect targetRect = new Rect();
targetRect.left = targetRect.top = 0;
targetRect.right = bm.getWidth();
targetRect.bottom = bm.getHeight();
int deltaw = width - targetRect.right;
int deltah = height - targetRect.bottom;
if (deltaw > 0 || deltah > 0) {
// We need to scale up so it covers the entire
// area.
float scale = 1.0f;
if (deltaw > deltah) {
scale = width / (float)targetRect.right;
} else {
scale = height / (float)targetRect.bottom;
}
targetRect.right = (int)(targetRect.right*scale);
targetRect.bottom = (int)(targetRect.bottom*scale);
deltaw = width - targetRect.right;
deltah = height - targetRect.bottom;
}
targetRect.offset(deltaw/2, deltah/2);
Paint paint = new Paint();
paint.setFilterBitmap(true);
paint.setDither(true);
c.drawBitmap(bm, null, targetRect, paint);
bm.recycle();
return newbm;
}
}

View File

@@ -22,8 +22,6 @@ import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.pm.ApplicationInfo;
import android.graphics.BitmapFactory;
import android.graphics.Movie;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ColorDrawable;
@@ -1699,7 +1697,7 @@ public class Resources {
} else {
try {
InputStream is = mAssets.openNonAsset(
value.assetCookie, file, AssetManager.ACCESS_BUFFER);
value.assetCookie, file, AssetManager.ACCESS_STREAMING);
// System.out.println("Opened file " + file + ": " + is);
dr = Drawable.createFromResourceStream(this, value, is,
file, null);

View File

@@ -64,7 +64,7 @@ public class HandlerThread extends Thread {
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will blocked until the looper has been initialized.
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
@@ -84,6 +84,21 @@ public class HandlerThread extends Thread {
return mLooper;
}
/**
* Ask the currently running looper to quit. If the thread has not
* been started or has finished (that is if {@link #getLooper} returns
* null), then false is returned. Otherwise the looper is asked to
* quit and true is returned.
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/

View File

@@ -28,9 +28,11 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.util.LogPrinter;
import android.view.Gravity;
import android.view.IWindowSession;
import android.view.MotionEvent;
@@ -74,6 +76,8 @@ public abstract class WallpaperService extends Service {
private static final int MSG_WINDOW_RESIZED = 10030;
private static final int MSG_TOUCH_EVENT = 10040;
private Looper mCallbackLooper;
/**
* The actual implementation of a wallpaper. A wallpaper service may
* have multiple instances running (for example as a real wallpaper
@@ -120,6 +124,7 @@ public abstract class WallpaperService extends Service {
boolean mOffsetMessageEnqueued;
float mPendingXOffset;
float mPendingYOffset;
boolean mPendingSync;
MotionEvent mPendingMove;
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -212,10 +217,14 @@ public abstract class WallpaperService extends Service {
}
@Override
public void dispatchWallpaperOffsets(float x, float y) {
public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
synchronized (mLock) {
if (DEBUG) Log.v(TAG, "Dispatch wallpaper offsets: " + x + ", " + y);
mPendingXOffset = x;
mPendingYOffset = y;
if (sync) {
mPendingSync = true;
}
if (!mOffsetMessageEnqueued) {
mOffsetMessageEnqueued = true;
Message msg = mCaller.obtainMessage(MSG_WALLPAPER_OFFSETS);
@@ -551,9 +560,12 @@ public abstract class WallpaperService extends Service {
float xOffset;
float yOffset;
boolean sync;
synchronized (mLock) {
xOffset = mPendingXOffset;
yOffset = mPendingYOffset;
sync = mPendingSync;
mPendingSync = false;
mOffsetMessageEnqueued = false;
}
if (DEBUG) Log.v(TAG, "Offsets change in " + this
@@ -563,6 +575,14 @@ public abstract class WallpaperService extends Service {
final int availh = mIWallpaperEngine.mReqHeight-mCurHeight;
final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0;
onOffsetsChanged(xOffset, yOffset, xPixels, yPixels);
if (sync) {
try {
if (DEBUG) Log.v(TAG, "Reporting offsets change complete");
mSession.wallpaperOffsetsComplete(mWindow.asBinder());
} catch (RemoteException e) {
}
}
}
void detach() {
@@ -622,7 +642,13 @@ public abstract class WallpaperService extends Service {
IWallpaperEngineWrapper(WallpaperService context,
IWallpaperConnection conn, IBinder windowToken,
int windowType, boolean isPreview, int reqWidth, int reqHeight) {
mCaller = new HandlerCaller(context, this);
if (DEBUG && mCallbackLooper != null) {
mCallbackLooper.setMessageLogging(new LogPrinter(Log.VERBOSE, TAG));
}
mCaller = new HandlerCaller(context,
mCallbackLooper != null
? mCallbackLooper : context.getMainLooper(),
this);
mConnection = conn;
mWindowToken = windowToken;
mWindowType = windowType;
@@ -736,5 +762,18 @@ public abstract class WallpaperService extends Service {
return new IWallpaperServiceWrapper(this);
}
/**
* This allows subclasses to change the thread that most callbacks
* occur on. Currently hidden because it is mostly needed for the
* image wallpaper (which runs in the system process and doesn't want
* to get stuck running on that seriously in use main thread). Not
* exposed right now because the semantics of this are not totally
* well defined and some callbacks can still happen on the main thread).
* @hide
*/
public void setCallbackLooper(Looper looper) {
mCallbackLooper = looper;
}
public abstract Engine onCreateEngine();
}

View File

@@ -60,5 +60,5 @@ oneway interface IWindow {
/**
* Called for wallpaper windows when their offsets change.
*/
void dispatchWallpaperOffsets(float x, float y);
void dispatchWallpaperOffsets(float x, float y, boolean sync);
}

View File

@@ -114,4 +114,6 @@ interface IWindowSession {
* larger than the screen, set the offset within the screen.
*/
void setWallpaperPosition(IBinder windowToken, float x, float y);
void wallpaperOffsetsComplete(IBinder window);
}

View File

@@ -2868,7 +2868,13 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
public void dispatchWallpaperOffsets(float x, float y) {
public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
if (sync) {
try {
sWindowSession.wallpaperOffsetsComplete(asBinder());
} catch (RemoteException e) {
}
}
}
}

View File

@@ -57,6 +57,13 @@ public class HandlerCaller {
mCallback = callback;
}
public HandlerCaller(Context context, Looper looper, Callback callback) {
mContext = context;
mMainLooper = looper;
mH = new MyHandler(mMainLooper);
mCallback = callback;
}
public SomeArgs obtainArgs() {
synchronized (mH) {
SomeArgs args = mArgsPool;

View File

@@ -20,6 +20,8 @@ import android.app.WallpaperManager;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.HandlerThread;
import android.os.Process;
import android.service.wallpaper.WallpaperService;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
@@ -33,20 +35,29 @@ import android.content.BroadcastReceiver;
*/
public class ImageWallpaper extends WallpaperService {
WallpaperManager mWallpaperManager;
private HandlerThread mThread;
@Override
public void onCreate() {
super.onCreate();
mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
mThread = new HandlerThread("Wallpaper", Process.THREAD_PRIORITY_FOREGROUND);
mThread.start();
setCallbackLooper(mThread.getLooper());
}
public Engine onCreateEngine() {
return new DrawableEngine();
}
@Override
public void onDestroy() {
super.onDestroy();
mThread.quit();
}
class DrawableEngine extends Engine {
private final Object mLock = new Object();
private final Rect mBounds = new Rect();
private WallpaperObserver mReceiver;
Drawable mBackground;
float mXOffset;
@@ -56,6 +67,9 @@ public class ImageWallpaper extends WallpaperService {
public void onReceive(Context context, Intent intent) {
updateWallpaper();
drawFrame();
// Assume we are the only one using the wallpaper in this
// process, and force a GC now to release the old wallpaper.
System.gc();
}
}
@@ -67,7 +81,6 @@ public class ImageWallpaper extends WallpaperService {
registerReceiver(mReceiver, filter);
updateWallpaper();
surfaceHolder.setSizeFromLayout();
//setTouchEventsEnabled(true);
}
@Override
@@ -137,11 +150,7 @@ public class ImageWallpaper extends WallpaperService {
void updateWallpaper() {
synchronized (mLock) {
mBackground = mWallpaperManager.getDrawable();
mBounds.left = mBounds.top = 0;
mBounds.right = mBackground.getIntrinsicWidth();
mBounds.bottom = mBackground.getIntrinsicHeight();
mBackground.setBounds(mBounds);
mBackground = mWallpaperManager.getFastDrawable();
}
}
}

View File

@@ -90,6 +90,12 @@ public class BaseIWindow extends IWindow.Stub {
public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
}
public void dispatchWallpaperOffsets(float x, float y) {
public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
if (sync) {
try {
mSession.wallpaperOffsetsComplete(asBinder());
} catch (RemoteException e) {
}
}
}
}