Some optizations to wallpaper drawing/scrolling.
First, fix some issues with the final wallpaper bitmap we use: ensure it is always 16bpp, and make sure dithering of its bitmap is turned off. We take of dithering when loading, to make sure we don't use it when drawing. Also add new APIs to return the wallpaper with the equivalent of Launcher's old FastBitmapDrawable. As doing this, also load the default wallpaper the same way as custom ones, taking care to resize it as needed at load time. Finally implement a mechanism for the window manager to wait for the wallpaper to redraw at its new position before returning from the application's call to change the offset. This ensures that the wallpaper better tracks the application. Note that there is a timeout in this wait that is relatively short, and if it expires we will run for a while without waiting. Change-Id: Ife449437746da85958bd447e0a6cf3d2223b398c
This commit is contained in:
@@ -24714,6 +24714,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getFastDrawable"
|
||||
return="android.graphics.drawable.Drawable"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getInstance"
|
||||
return="android.app.WallpaperManager"
|
||||
abstract="false"
|
||||
@@ -24738,6 +24749,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="peekFastDrawable"
|
||||
return="android.graphics.drawable.Drawable"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="setBitmap"
|
||||
return="void"
|
||||
abstract="false"
|
||||
@@ -101558,6 +101580,17 @@
|
||||
visibility="protected"
|
||||
>
|
||||
</method>
|
||||
<method name="quit"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
</class>
|
||||
<interface name="IBinder"
|
||||
abstract="true"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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().
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,6 +418,17 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
int mWallpaperAnimLayerAdjustment;
|
||||
float mLastWallpaperX;
|
||||
float mLastWallpaperY;
|
||||
// Lock for waiting for the wallpaper.
|
||||
final Object mWaitingOnWallpaperLock = new Object();
|
||||
// This is set when we are waiting for a wallpaper to tell us it is done
|
||||
// changing its scroll position.
|
||||
WindowState mWaitingOnWallpaper;
|
||||
// The last time we had a timeout when waiting for a wallpaper.
|
||||
long mLastWallpaperTimeoutTime;
|
||||
// We give a wallpaper up to 150ms to finish scrolling.
|
||||
static final long WALLPAPER_TIMEOUT = 150;
|
||||
// Time we wait after a timeout before trying to wait again.
|
||||
static final long WALLPAPER_TIMEOUT_RECOVERY = 10000;
|
||||
|
||||
AppWindowToken mFocusedApp = null;
|
||||
|
||||
@@ -1427,7 +1438,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
WindowState wallpaper = token.windows.get(curWallpaperIndex);
|
||||
|
||||
if (visible) {
|
||||
updateWallpaperOffsetLocked(wallpaper, dw, dh);
|
||||
updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
|
||||
}
|
||||
|
||||
// First, make sure the client has the current visibility
|
||||
@@ -1498,7 +1509,8 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh) {
|
||||
boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh,
|
||||
boolean sync) {
|
||||
boolean changed = false;
|
||||
boolean rawChanged = false;
|
||||
if (mLastWallpaperX >= 0) {
|
||||
@@ -1536,8 +1548,37 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
if (DEBUG_WALLPAPER) Log.v(TAG, "Report new wp offset "
|
||||
+ wallpaperWin + " x=" + wallpaperWin.mWallpaperX
|
||||
+ " y=" + wallpaperWin.mWallpaperY);
|
||||
if (sync) {
|
||||
synchronized (mWaitingOnWallpaperLock) {
|
||||
mWaitingOnWallpaper = wallpaperWin;
|
||||
}
|
||||
}
|
||||
wallpaperWin.mClient.dispatchWallpaperOffsets(
|
||||
wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY);
|
||||
wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY, sync);
|
||||
if (sync) {
|
||||
synchronized (mWaitingOnWallpaperLock) {
|
||||
if (mWaitingOnWallpaper != null) {
|
||||
long start = SystemClock.uptimeMillis();
|
||||
if ((mLastWallpaperTimeoutTime+WALLPAPER_TIMEOUT_RECOVERY)
|
||||
< start) {
|
||||
try {
|
||||
if (DEBUG_WALLPAPER) Log.v(TAG,
|
||||
"Waiting for offset complete...");
|
||||
mWaitingOnWallpaperLock.wait(WALLPAPER_TIMEOUT);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
if (DEBUG_WALLPAPER) Log.v(TAG, "Offset complete!");
|
||||
if ((start+WALLPAPER_TIMEOUT)
|
||||
< SystemClock.uptimeMillis()) {
|
||||
Log.i(TAG, "Timeout waiting for wallpaper to offset: "
|
||||
+ wallpaperWin);
|
||||
mLastWallpaperTimeoutTime = start;
|
||||
}
|
||||
}
|
||||
mWaitingOnWallpaper = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
@@ -1545,7 +1586,17 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
return changed;
|
||||
}
|
||||
|
||||
boolean updateWallpaperOffsetLocked() {
|
||||
void wallpaperOffsetsComplete(IBinder window) {
|
||||
synchronized (mWaitingOnWallpaperLock) {
|
||||
if (mWaitingOnWallpaper != null &&
|
||||
mWaitingOnWallpaper.mClient.asBinder() == window) {
|
||||
mWaitingOnWallpaper = null;
|
||||
mWaitingOnWallpaperLock.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean updateWallpaperOffsetLocked(boolean sync) {
|
||||
final int dw = mDisplay.getWidth();
|
||||
final int dh = mDisplay.getHeight();
|
||||
|
||||
@@ -1563,9 +1614,11 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
while (curWallpaperIndex > 0) {
|
||||
curWallpaperIndex--;
|
||||
WindowState wallpaper = token.windows.get(curWallpaperIndex);
|
||||
if (updateWallpaperOffsetLocked(wallpaper, dw, dh)) {
|
||||
if (updateWallpaperOffsetLocked(wallpaper, dw, dh, sync)) {
|
||||
wallpaper.computeShownFrameLocked();
|
||||
changed = true;
|
||||
// We only want to be synchronous with one wallpaper.
|
||||
sync = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1595,7 +1648,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
curWallpaperIndex--;
|
||||
WindowState wallpaper = token.windows.get(curWallpaperIndex);
|
||||
if (visible) {
|
||||
updateWallpaperOffsetLocked(wallpaper, dw, dh);
|
||||
updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
|
||||
}
|
||||
|
||||
if (wallpaper.mWallpaperVisible != visible) {
|
||||
@@ -1782,8 +1835,10 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
imMayMove = false;
|
||||
} else {
|
||||
addWindowToListInOrderLocked(win, true);
|
||||
if (attrs.type == TYPE_WALLPAPER ||
|
||||
(attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
|
||||
if (attrs.type == TYPE_WALLPAPER) {
|
||||
mLastWallpaperTimeoutTime = 0;
|
||||
adjustWallpaperWindowsLocked();
|
||||
} else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
|
||||
adjustWallpaperWindowsLocked();
|
||||
}
|
||||
}
|
||||
@@ -1992,8 +2047,10 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
if (win.mAttrs.type == TYPE_WALLPAPER ||
|
||||
(win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
|
||||
if (win.mAttrs.type == TYPE_WALLPAPER) {
|
||||
mLastWallpaperTimeoutTime = 0;
|
||||
adjustWallpaperWindowsLocked();
|
||||
} else if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
|
||||
adjustWallpaperWindowsLocked();
|
||||
}
|
||||
|
||||
@@ -2070,7 +2127,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
window.mWallpaperY = y;
|
||||
|
||||
if (mWallpaperTarget == window) {
|
||||
if (updateWallpaperOffsetLocked()) {
|
||||
if (updateWallpaperOffsetLocked(true)) {
|
||||
performLayoutAndPlaceSurfacesLocked();
|
||||
}
|
||||
}
|
||||
@@ -2258,7 +2315,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
performLayoutAndPlaceSurfacesLocked();
|
||||
if (displayed && win.mIsWallpaper) {
|
||||
updateWallpaperOffsetLocked(win, mDisplay.getWidth(),
|
||||
mDisplay.getHeight());
|
||||
mDisplay.getHeight(), false);
|
||||
}
|
||||
if (win.mAppToken != null) {
|
||||
win.mAppToken.updateReportedVisibilityLocked();
|
||||
@@ -6303,6 +6360,10 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
public void wallpaperOffsetsComplete(IBinder window) {
|
||||
WindowManagerService.this.wallpaperOffsetsComplete(window);
|
||||
}
|
||||
|
||||
void windowAddedLocked() {
|
||||
if (mSurfaceSession == null) {
|
||||
if (localLOGV) Log.v(
|
||||
@@ -6698,7 +6759,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
|
||||
if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) {
|
||||
updateWallpaperOffsetLocked(this, mDisplay.getWidth(),
|
||||
mDisplay.getHeight());
|
||||
mDisplay.getHeight(), false);
|
||||
}
|
||||
|
||||
if (localLOGV) {
|
||||
|
||||
@@ -1051,15 +1051,22 @@ public final class Bridge implements ILayoutBridge {
|
||||
// pass for now.
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setInsets(IWindow window, int touchable, Rect contentInsets,
|
||||
Rect visibleInsets) {
|
||||
// pass for now.
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setWallpaperPosition(IBinder window, float x, float y) {
|
||||
// pass for now.
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void wallpaperOffsetsComplete(IBinder window) {
|
||||
// pass for now.
|
||||
}
|
||||
|
||||
public IBinder asBinder() {
|
||||
// pass for now.
|
||||
return null;
|
||||
@@ -1114,7 +1121,7 @@ public final class Bridge implements ILayoutBridge {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void dispatchWallpaperOffsets(float x, float y) {
|
||||
public void dispatchWallpaperOffsets(float x, float y, boolean sync) {
|
||||
// pass for now.
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user