diff options
27 files changed, 1254 insertions, 50 deletions
diff --git a/api/current.txt b/api/current.txt index 623716d..6cff617 100644 --- a/api/current.txt +++ b/api/current.txt @@ -27507,6 +27507,7 @@ package android.service.wallpaper { method public android.view.SurfaceHolder getSurfaceHolder(); method public boolean isPreview(); method public boolean isVisible(); + method public void onApplyWindowInsets(android.view.WindowInsets); method public android.os.Bundle onCommand(java.lang.String, int, int, int, android.os.Bundle, boolean); method public void onCreate(android.view.SurfaceHolder); method public void onDesiredSizeChanged(int, int); @@ -35217,12 +35218,18 @@ package android.view { public final class WindowInsets { ctor public WindowInsets(android.view.WindowInsets); + method public android.view.WindowInsets consumeStableInsets(); method public android.view.WindowInsets consumeSystemWindowInsets(); + method public int getStableInsetBottom(); + method public int getStableInsetLeft(); + method public int getStableInsetRight(); + method public int getStableInsetTop(); method public int getSystemWindowInsetBottom(); method public int getSystemWindowInsetLeft(); method public int getSystemWindowInsetRight(); method public int getSystemWindowInsetTop(); method public boolean hasInsets(); + method public boolean hasStableInsets(); method public boolean hasSystemWindowInsets(); method public boolean isConsumed(); method public boolean isRound(); diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl index 181eb63..3b5900b 100644 --- a/core/java/android/app/IWallpaperManager.aidl +++ b/core/java/android/app/IWallpaperManager.aidl @@ -16,6 +16,7 @@ package android.app; +import android.graphics.Rect; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.app.IWallpaperManagerCallback; @@ -73,6 +74,11 @@ interface IWallpaperManager { int getHeightHint(); /** + * Sets extra padding that we would like the wallpaper to have outside of the display. + */ + void setDisplayPadding(in Rect padding); + + /** * Returns the name of the wallpaper. Private API. */ String getName(); diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 48ff5b6..8bfe6d3 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -16,6 +16,7 @@ package android.app; +import android.annotation.SystemApi; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -951,6 +952,48 @@ public class WallpaperManager { } /** + * Specify extra padding that the wallpaper should have outside of the display. + * That is, the given padding supplies additional pixels the wallpaper should extend + * outside of the display itself. + * @param padding The number of pixels the wallpaper should extend beyond the display, + * on its left, top, right, and bottom sides. + * @hide + */ + @SystemApi + public void setDisplayPadding(Rect padding) { + try { + if (sGlobals.mService == null) { + Log.w(TAG, "WallpaperService not running"); + } else { + sGlobals.mService.setDisplayPadding(padding); + } + } catch (RemoteException e) { + // Ignore + } + } + + /** + * Apply a raw offset to the wallpaper window. Should only be used in + * combination with {@link #setDisplayPadding(android.graphics.Rect)} when you + * have ensured that the wallpaper will extend outside of the display area so that + * it can be moved without leaving part of the display uncovered. + * @param x The offset, in pixels, to apply to the left edge. + * @param y The offset, in pixels, to apply to the top edge. + * @hide + */ + @SystemApi + public void setDisplayOffset(IBinder windowToken, int x, int y) { + try { + //Log.v(TAG, "Sending new wallpaper display offsets from app..."); + WindowManagerGlobal.getWindowSession().setWallpaperDisplayOffset( + windowToken, x, y); + //Log.v(TAG, "...app returning after sending display offset!"); + } catch (RemoteException e) { + // Ignore. + } + } + + /** * Set the position of the current wallpaper within any larger space, when * that wallpaper is visible behind the given window. The X and Y offsets * are floating point numbers ranging from 0 to 1, representing where the diff --git a/core/java/android/service/wallpaper/IWallpaperEngine.aidl b/core/java/android/service/wallpaper/IWallpaperEngine.aidl index faccde2..de527e9 100644 --- a/core/java/android/service/wallpaper/IWallpaperEngine.aidl +++ b/core/java/android/service/wallpaper/IWallpaperEngine.aidl @@ -16,6 +16,7 @@ package android.service.wallpaper; +import android.graphics.Rect; import android.view.MotionEvent; import android.os.Bundle; @@ -24,6 +25,7 @@ import android.os.Bundle; */ oneway interface IWallpaperEngine { void setDesiredSize(int width, int height); + void setDisplayPadding(in Rect padding); void setVisibility(boolean visible); void dispatchPointer(in MotionEvent event); void dispatchWallpaperCommand(String action, int x, int y, diff --git a/core/java/android/service/wallpaper/IWallpaperService.aidl b/core/java/android/service/wallpaper/IWallpaperService.aidl index bc7a1d7..5fd0157 100644 --- a/core/java/android/service/wallpaper/IWallpaperService.aidl +++ b/core/java/android/service/wallpaper/IWallpaperService.aidl @@ -16,6 +16,7 @@ package android.service.wallpaper; +import android.graphics.Rect; import android.service.wallpaper.IWallpaperConnection; /** @@ -24,5 +25,5 @@ import android.service.wallpaper.IWallpaperConnection; oneway interface IWallpaperService { void attach(IWallpaperConnection connection, IBinder windowToken, int windowType, boolean isPreview, - int reqWidth, int reqHeight); + int reqWidth, int reqHeight, in Rect padding); } diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index f3c26c8..26e9a30 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -16,6 +16,14 @@ package android.service.wallpaper; +import android.content.res.TypedArray; +import android.os.Build; +import android.os.SystemProperties; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.ViewRootImpl; +import android.view.WindowInsets; +import com.android.internal.R; import com.android.internal.os.HandlerCaller; import com.android.internal.view.BaseIWindow; import com.android.internal.view.BaseSurfaceHolder; @@ -56,6 +64,8 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; + /** * A wallpaper service is responsible for showing a live wallpaper behind * applications that would like to sit on top of it. This service object @@ -90,7 +100,8 @@ public abstract class WallpaperService extends Service { private static final int DO_ATTACH = 10; private static final int DO_DETACH = 20; private static final int DO_SET_DESIRED_SIZE = 30; - + private static final int DO_SET_DISPLAY_PADDING = 40; + private static final int MSG_UPDATE_SURFACE = 10000; private static final int MSG_VISIBILITY_CHANGED = 10010; private static final int MSG_WALLPAPER_OFFSETS = 10020; @@ -150,13 +161,23 @@ public abstract class WallpaperService extends Service { WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS; int mCurWindowFlags = mWindowFlags; int mCurWindowPrivateFlags = mWindowPrivateFlags; + TypedValue mOutsetBottom; final Rect mVisibleInsets = new Rect(); final Rect mWinFrame = new Rect(); final Rect mOverscanInsets = new Rect(); final Rect mContentInsets = new Rect(); final Rect mStableInsets = new Rect(); + final Rect mDispatchedOverscanInsets = new Rect(); + final Rect mDispatchedContentInsets = new Rect(); + final Rect mDispatchedStableInsets = new Rect(); + final Rect mFinalSystemInsets = new Rect(); + final Rect mFinalStableInsets = new Rect(); final Configuration mConfiguration = new Configuration(); - + + private boolean mIsEmulator; + private boolean mIsCircularEmulator; + private boolean mWindowIsRound; + final WindowManager.LayoutParams mLayout = new WindowManager.LayoutParams(); IWindowSession mSession; @@ -406,7 +427,7 @@ public abstract class WallpaperService extends Service { */ public void onCreate(SurfaceHolder surfaceHolder) { } - + /** * Called right before the engine is going away. After this the * surface will be destroyed and this Engine object is no longer @@ -414,7 +435,7 @@ public abstract class WallpaperService extends Service { */ public void onDestroy() { } - + /** * Called to inform you of the wallpaper becoming visible or * hidden. <em>It is very important that a wallpaper only use @@ -422,7 +443,17 @@ public abstract class WallpaperService extends Service { */ public void onVisibilityChanged(boolean visible) { } - + + /** + * Called with the current insets that are in effect for the wallpaper. + * This gives you the part of the overall wallpaper surface that will + * generally be visible to the user (ignoring position offsets applied to it). + * + * @param insets Insets to apply. + */ + public void onApplyWindowInsets(WindowInsets insets) { + } + /** * Called as the user performs touch-screen interaction with the * window that is currently showing this wallpaper. Note that the @@ -432,7 +463,7 @@ public abstract class WallpaperService extends Service { */ public void onTouchEvent(MotionEvent event) { } - + /** * Called to inform you of the wallpaper's offsets changing * within its contain, corresponding to the container's @@ -443,7 +474,7 @@ public abstract class WallpaperService extends Service { float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) { } - + /** * Process a command that was sent to the wallpaper with * {@link WallpaperManager#sendWallpaperCommand}. @@ -465,14 +496,14 @@ public abstract class WallpaperService extends Service { Bundle extras, boolean resultRequested) { return null; } - + /** * Called when an application has changed the desired virtual size of * the wallpaper. */ public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) { } - + /** * Convenience for {@link SurfaceHolder.Callback#surfaceChanged * SurfaceHolder.Callback.surfaceChanged()}. @@ -561,16 +592,20 @@ public abstract class WallpaperService extends Service { if (mDestroyed) { Log.w(TAG, "Ignoring updateSurface: destroyed"); } - + + boolean fixedSize = false; int myWidth = mSurfaceHolder.getRequestedWidth(); if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.MATCH_PARENT; + else fixedSize = true; int myHeight = mSurfaceHolder.getRequestedHeight(); if (myHeight <= 0) myHeight = ViewGroup.LayoutParams.MATCH_PARENT; - + else fixedSize = true; + final boolean creating = !mCreated; final boolean surfaceCreating = !mSurfaceCreated; final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat(); boolean sizeChanged = mWidth != myWidth || mHeight != myHeight; + boolean insetsChanged = !mCreated; final boolean typeChanged = mType != mSurfaceHolder.getRequestedType(); final boolean flagsChanged = mCurWindowFlags != mWindowFlags || mCurWindowPrivateFlags != mWindowPrivateFlags; @@ -607,6 +642,32 @@ public abstract class WallpaperService extends Service { mLayout.token = mWindowToken; if (!mCreated) { + // Retrieve watch round and outset info + final WindowManager windowService = (WindowManager)getSystemService( + Context.WINDOW_SERVICE); + TypedArray windowStyle = obtainStyledAttributes( + com.android.internal.R.styleable.Window); + final Display display = windowService.getDefaultDisplay(); + final boolean shouldUseBottomOutset = + display.getDisplayId() == Display.DEFAULT_DISPLAY; + if (shouldUseBottomOutset && windowStyle.hasValue( + R.styleable.Window_windowOutsetBottom)) { + if (mOutsetBottom == null) mOutsetBottom = new TypedValue(); + windowStyle.getValue(R.styleable.Window_windowOutsetBottom, + mOutsetBottom); + } else { + mOutsetBottom = null; + } + mWindowIsRound = getResources().getBoolean( + com.android.internal.R.bool.config_windowIsRound); + windowStyle.recycle(); + + // detect emulator + mIsEmulator = Build.HARDWARE.contains("goldfish"); + mIsCircularEmulator = SystemProperties.getBoolean( + ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false); + + // Add window mLayout.type = mIWallpaperEngine.mWindowType; mLayout.gravity = Gravity.START|Gravity.TOP; mLayout.setTitle(WallpaperService.this.getClass().getName()); @@ -627,6 +688,11 @@ public abstract class WallpaperService extends Service { mSurfaceHolder.mSurfaceLock.lock(); mDrawingAllowed = true; + if (!fixedSize) { + mLayout.surfaceInsets.set(mIWallpaperEngine.mDisplayPadding); + } else { + mLayout.surfaceInsets.set(0, 0, 0, 0); + } final int relayoutResult = mSession.relayout( mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets, @@ -636,16 +702,39 @@ public abstract class WallpaperService extends Service { + ", frame=" + mWinFrame); int w = mWinFrame.width(); + int h = mWinFrame.height(); + + if (!fixedSize) { + final Rect padding = mIWallpaperEngine.mDisplayPadding; + w += padding.left + padding.right; + h += padding.top + padding.bottom; + mOverscanInsets.left += padding.left; + mOverscanInsets.top += padding.top; + mOverscanInsets.right += padding.right; + mOverscanInsets.bottom += padding.bottom; + mContentInsets.left += padding.left; + mContentInsets.top += padding.top; + mContentInsets.right += padding.right; + mContentInsets.bottom += padding.bottom; + mStableInsets.left += padding.left; + mStableInsets.top += padding.top; + mStableInsets.right += padding.right; + mStableInsets.bottom += padding.bottom; + } + if (mCurWidth != w) { sizeChanged = true; mCurWidth = w; } - int h = mWinFrame.height(); if (mCurHeight != h) { sizeChanged = true; mCurHeight = h; } + insetsChanged |= !mDispatchedOverscanInsets.equals(mOverscanInsets); + insetsChanged |= !mDispatchedContentInsets.equals(mContentInsets); + insetsChanged |= !mDispatchedStableInsets.equals(mStableInsets); + mSurfaceHolder.setSurfaceFrameSize(w, h); mSurfaceHolder.mSurfaceLock.unlock(); @@ -702,6 +791,25 @@ public abstract class WallpaperService extends Service { } } + if (insetsChanged) { + mDispatchedOverscanInsets.set(mOverscanInsets); + mDispatchedContentInsets.set(mContentInsets); + mDispatchedStableInsets.set(mStableInsets); + final boolean isRound = (mIsEmulator && mIsCircularEmulator) + || mWindowIsRound; + mFinalSystemInsets.set(mDispatchedOverscanInsets); + mFinalStableInsets.set(mDispatchedStableInsets); + if (mOutsetBottom != null) { + final DisplayMetrics metrics = getResources().getDisplayMetrics(); + mFinalSystemInsets.bottom = + ( (int) mOutsetBottom.getDimension(metrics) ) + + mIWallpaperEngine.mDisplayPadding.bottom; + } + WindowInsets insets = new WindowInsets(mFinalSystemInsets, + null, mFinalStableInsets, isRound); + onApplyWindowInsets(insets); + } + if (redrawNeeded) { onSurfaceRedrawNeeded(mSurfaceHolder); SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); @@ -781,7 +889,7 @@ public abstract class WallpaperService extends Service { mReportedVisible = false; updateSurface(false, false, false); } - + void doDesiredSizeChanged(int desiredWidth, int desiredHeight) { if (!mDestroyed) { if (DEBUG) Log.v(TAG, "onDesiredSizeChanged(" @@ -792,14 +900,24 @@ public abstract class WallpaperService extends Service { doOffsetsChanged(true); } } - + + void doDisplayPaddingChanged(Rect padding) { + if (!mDestroyed) { + if (DEBUG) Log.v(TAG, "onDisplayPaddingChanged(" + padding + "): " + this); + if (!mIWallpaperEngine.mDisplayPadding.equals(padding)) { + mIWallpaperEngine.mDisplayPadding.set(padding); + updateSurface(true, false, false); + } + } + } + void doVisibilityChanged(boolean visible) { if (!mDestroyed) { mVisible = visible; reportVisibility(); } } - + void reportVisibility() { if (!mDestroyed) { boolean visible = mVisible && mScreenOn; @@ -956,12 +1074,13 @@ public abstract class WallpaperService extends Service { boolean mShownReported; int mReqWidth; int mReqHeight; - + final Rect mDisplayPadding = new Rect(); + Engine mEngine; - + IWallpaperEngineWrapper(WallpaperService context, IWallpaperConnection conn, IBinder windowToken, - int windowType, boolean isPreview, int reqWidth, int reqHeight) { + int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding) { mCaller = new HandlerCaller(context, context.getMainLooper(), this, true); mConnection = conn; mWindowToken = windowToken; @@ -969,16 +1088,22 @@ public abstract class WallpaperService extends Service { mIsPreview = isPreview; mReqWidth = reqWidth; mReqHeight = reqHeight; + mDisplayPadding.set(padding); Message msg = mCaller.obtainMessage(DO_ATTACH); mCaller.sendMessage(msg); } - + public void setDesiredSize(int width, int height) { Message msg = mCaller.obtainMessageII(DO_SET_DESIRED_SIZE, width, height); mCaller.sendMessage(msg); } - + + public void setDisplayPadding(Rect padding) { + Message msg = mCaller.obtainMessageO(DO_SET_DISPLAY_PADDING, padding); + mCaller.sendMessage(msg); + } + public void setVisibility(boolean visible) { Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED, visible ? 1 : 0); @@ -1041,6 +1166,9 @@ public abstract class WallpaperService extends Service { mEngine.doDesiredSizeChanged(message.arg1, message.arg2); return; } + case DO_SET_DISPLAY_PADDING: { + mEngine.doDisplayPaddingChanged((Rect) message.obj); + } case MSG_UPDATE_SURFACE: mEngine.updateSurface(true, false, false); break; @@ -1102,9 +1230,9 @@ public abstract class WallpaperService extends Service { @Override public void attach(IWallpaperConnection conn, IBinder windowToken, - int windowType, boolean isPreview, int reqWidth, int reqHeight) { + int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding) { new IWallpaperEngineWrapper(mTarget, conn, windowToken, - windowType, isPreview, reqWidth, reqHeight); + windowType, isPreview, reqWidth, reqHeight, padding); } } diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 0f3f182..037ed28 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -177,6 +177,11 @@ interface IWindowSession { void wallpaperOffsetsComplete(IBinder window); + /** + * Apply a raw offset to the wallpaper service when shown behind this window. + */ + void setWallpaperDisplayOffset(IBinder windowToken, int x, int y); + Bundle sendWallpaperCommand(IBinder window, String action, int x, int y, int z, in Bundle extras, boolean sync); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 80b9ade..43ab4ef 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -121,7 +121,7 @@ public final class ViewRootImpl implements ViewParent, private static final String PROPERTY_MEDIA_DISABLED = "config.disable_media"; // property used by emulator to determine display shape - private static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular"; + public static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular"; /** * Maximum time we allow the user to roll the trackball enough to generate diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index 571a8f0..24c3c1a 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -378,35 +378,75 @@ public final class WindowInsets { } /** - * @hide + * Returns the top stable inset in pixels. + * + * <p>The stable inset represents the area of a full-screen window that <b>may</b> be + * partially or fully obscured by the system UI elements. This value does not change + * based on the visibility state of those elements; for example, if the status bar is + * normally shown, but temporarily hidden, the stable inset will still provide the inset + * associated with the status bar being shown.</p> + * + * @return The top stable inset */ public int getStableInsetTop() { return mStableInsets.top; } /** - * @hide + * Returns the left stable inset in pixels. + * + * <p>The stable inset represents the area of a full-screen window that <b>may</b> be + * partially or fully obscured by the system UI elements. This value does not change + * based on the visibility state of those elements; for example, if the status bar is + * normally shown, but temporarily hidden, the stable inset will still provide the inset + * associated with the status bar being shown.</p> + * + * @return The left stable inset */ public int getStableInsetLeft() { return mStableInsets.left; } /** - * @hide + * Returns the right stable inset in pixels. + * + * <p>The stable inset represents the area of a full-screen window that <b>may</b> be + * partially or fully obscured by the system UI elements. This value does not change + * based on the visibility state of those elements; for example, if the status bar is + * normally shown, but temporarily hidden, the stable inset will still provide the inset + * associated with the status bar being shown.</p> + * + * @return The right stable inset */ public int getStableInsetRight() { return mStableInsets.right; } /** - * @hide + * Returns the bottom stable inset in pixels. + * + * <p>The stable inset represents the area of a full-screen window that <b>may</b> be + * partially or fully obscured by the system UI elements. This value does not change + * based on the visibility state of those elements; for example, if the status bar is + * normally shown, but temporarily hidden, the stable inset will still provide the inset + * associated with the status bar being shown.</p> + * + * @return The bottom stable inset */ public int getStableInsetBottom() { return mStableInsets.bottom; } /** - * @hide + * Returns true if this WindowInsets has nonzero stable insets. + * + * <p>The stable inset represents the area of a full-screen window that <b>may</b> be + * partially or fully obscured by the system UI elements. This value does not change + * based on the visibility state of those elements; for example, if the status bar is + * normally shown, but temporarily hidden, the stable inset will still provide the inset + * associated with the status bar being shown.</p> + * + * @return true if any of the stable inset values are nonzero */ public boolean hasStableInsets() { return mStableInsets.top != 0 || mStableInsets.left != 0 || mStableInsets.right != 0 @@ -414,7 +454,9 @@ public final class WindowInsets { } /** - * @hide + * Returns a copy of this WindowInsets with the stable insets fully consumed. + * + * @return A modified copy of this WindowInsets */ public WindowInsets consumeStableInsets() { final WindowInsets result = new WindowInsets(this); diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index f69032d..8c65b71 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -3533,13 +3533,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop + mOverscanScreenHeight; } else if (attrs.type == TYPE_WALLPAPER) { - // The wallpaper also has Real Ultimate Power. - pf.left = df.left = of.left = cf.left = mUnrestrictedScreenLeft; - pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop; - pf.right = df.right = of.right = cf.right - = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth; - pf.bottom = df.bottom = of.bottom = cf.bottom - = mUnrestrictedScreenTop + mUnrestrictedScreenHeight; + // The wallpaper also has Real Ultimate Power, but we want to tell + // it about the overscan area. + pf.left = df.left = mOverscanScreenLeft; + pf.top = df.top = mOverscanScreenTop; + pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth; + pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight; + of.left = cf.left = mUnrestrictedScreenLeft; + of.top = cf.top = mUnrestrictedScreenTop; + of.right = cf.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth; + of.bottom = cf.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight; } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0 && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { @@ -3653,9 +3656,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it. if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && attrs.type != TYPE_SYSTEM_ERROR) { - df.left = df.top = of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000; - df.right = df.bottom = of.right = of.bottom = cf.right = cf.bottom - = vf.right = vf.bottom = 10000; + df.left = df.top = -10000; + df.right = df.bottom = 10000; + if (attrs.type != TYPE_WALLPAPER) { + of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000; + of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000; + } } if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle() diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 802df95..e1ade63 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -42,6 +42,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Point; +import android.graphics.Rect; import android.os.Binder; import android.os.Bundle; import android.os.Environment; @@ -206,6 +207,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { int width = -1; int height = -1; + final Rect padding = new Rect(0, 0, 0, 0); + WallpaperData(int userId) { this.userId = userId; wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER); @@ -222,6 +225,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { IRemoteCallback mReply; boolean mDimensionsChanged = false; + boolean mPaddingChanged = false; public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) { mInfo = info; @@ -283,6 +287,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } mDimensionsChanged = false; } + if (mPaddingChanged) { + try { + mEngine.setDisplayPadding(mWallpaper.padding); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to set wallpaper padding", e); + } + mPaddingChanged = false; + } } } @@ -719,6 +731,40 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } } + public void setDisplayPadding(Rect padding) { + checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); + synchronized (mLock) { + int userId = UserHandle.getCallingUserId(); + WallpaperData wallpaper = mWallpaperMap.get(userId); + if (wallpaper == null) { + throw new IllegalStateException("Wallpaper not yet initialized for user " + userId); + } + if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) { + throw new IllegalArgumentException("padding must be positive: " + padding); + } + + if (!padding.equals(wallpaper.padding)) { + wallpaper.padding.set(padding); + saveSettingsLocked(wallpaper); + if (mCurrentUserId != userId) return; // Don't change the properties now + if (wallpaper.connection != null) { + if (wallpaper.connection.mEngine != null) { + try { + wallpaper.connection.mEngine.setDisplayPadding(padding); + } catch (RemoteException e) { + } + notifyCallbacksLocked(wallpaper); + } else if (wallpaper.connection.mService != null) { + // We've attached to the service but the engine hasn't attached back to us + // yet. This means it will be created with the previous dimensions, so we + // need to update it to the new dimensions once it attaches. + wallpaper.connection.mPaddingChanged = true; + } + } + } + } + } + public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, Bundle outParams) { synchronized (mLock) { @@ -1006,7 +1052,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { try { conn.mService.attach(conn, conn.mToken, WindowManager.LayoutParams.TYPE_WALLPAPER, false, - wallpaper.width, wallpaper.height); + wallpaper.width, wallpaper.height, wallpaper.padding); } catch (RemoteException e) { Slog.w(TAG, "Failed attaching wallpaper; clearing", e); if (!wallpaper.wallpaperUpdating) { @@ -1055,6 +1101,18 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { out.startTag(null, "wp"); out.attribute(null, "width", Integer.toString(wallpaper.width)); out.attribute(null, "height", Integer.toString(wallpaper.height)); + if (wallpaper.padding.left != 0) { + out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left)); + } + if (wallpaper.padding.top != 0) { + out.attribute(null, "paddingTop", Integer.toString(wallpaper.padding.top)); + } + if (wallpaper.padding.right != 0) { + out.attribute(null, "paddingRight", Integer.toString(wallpaper.padding.right)); + } + if (wallpaper.padding.bottom != 0) { + out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom)); + } out.attribute(null, "name", wallpaper.name); if (wallpaper.wallpaperComponent != null && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) { @@ -1091,6 +1149,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } } + private int getAttributeInt(XmlPullParser parser, String name, int defValue) { + String value = parser.getAttributeValue(null, name); + if (value == null) { + return defValue; + } + return Integer.parseInt(value); + } + private void loadSettingsLocked(int userId) { if (DEBUG) Slog.v(TAG, "loadSettingsLocked"); @@ -1121,6 +1187,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width")); wallpaper.height = Integer.parseInt(parser .getAttributeValue(null, "height")); + wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0); + wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0); + wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0); + wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0); wallpaper.name = parser.getAttributeValue(null, "name"); String comp = parser.getAttributeValue(null, "component"); wallpaper.nextWallpaperComponent = comp != null @@ -1167,6 +1237,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { if (!success) { wallpaper.width = -1; wallpaper.height = -1; + wallpaper.padding.set(0, 0, 0, 0); wallpaper.name = ""; } @@ -1330,13 +1401,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { WallpaperData wallpaper = mWallpaperMap.valueAt(i); pw.println(" User " + wallpaper.userId + ":"); pw.print(" mWidth="); - pw.print(wallpaper.width); - pw.print(" mHeight="); - pw.println(wallpaper.height); - pw.print(" mName="); - pw.println(wallpaper.name); - pw.print(" mWallpaperComponent="); - pw.println(wallpaper.wallpaperComponent); + pw.print(wallpaper.width); + pw.print(" mHeight="); + pw.println(wallpaper.height); + pw.print(" mPadding="); pw.println(wallpaper.padding); + pw.print(" mName="); pw.println(wallpaper.name); + pw.print(" mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent); if (wallpaper.connection != null) { WallpaperConnection conn = wallpaper.connection; pw.print(" Wallpaper connection "); diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index f2703ad..d737e7f 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -415,6 +415,18 @@ final class Session extends IWindowSession.Stub mService.wallpaperOffsetsComplete(window); } + public void setWallpaperDisplayOffset(IBinder window, int x, int y) { + synchronized(mService.mWindowMap) { + long ident = Binder.clearCallingIdentity(); + try { + mService.setWindowWallpaperDisplayOffsetLocked( + mService.windowForClientLocked(this, window, true), x, y); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y, int z, Bundle extras, boolean sync) { synchronized(mService.mWindowMap) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 55c6d81..8e45081 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -572,6 +572,8 @@ public class WindowManagerService extends IWindowManager.Stub float mLastWallpaperY = -1; float mLastWallpaperXStep = -1; float mLastWallpaperYStep = -1; + int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE; + int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE; // This is set when we are waiting for a wallpaper to tell us it is done // changing its scroll position. WindowState mWaitingOnWallpaper; @@ -1892,6 +1894,12 @@ public class WindowManagerService extends IWindowManager.Stub mLastWallpaperY = mWallpaperTarget.mWallpaperY; mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep; } + if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) { + mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX; + } + if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) { + mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY; + } } // Start stepping backwards from here, ensuring that our wallpaper windows @@ -2030,6 +2038,9 @@ public class WindowManagerService extends IWindowManager.Stub float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f; int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw; int offset = availw > 0 ? -(int)(availw*wpx+.5f) : 0; + if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) { + offset += mLastWallpaperDisplayOffsetX; + } changed = wallpaperWin.mXOffset != offset; if (changed) { if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " @@ -2046,6 +2057,9 @@ public class WindowManagerService extends IWindowManager.Stub float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f; int availh = wallpaperWin.mFrame.bottom-wallpaperWin.mFrame.top-dh; offset = availh > 0 ? -(int)(availh*wpy+.5f) : 0; + if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) { + offset += mLastWallpaperDisplayOffsetY; + } if (wallpaperWin.mYOffset != offset) { if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " y: " + offset); @@ -2130,6 +2144,16 @@ public class WindowManagerService extends IWindowManager.Stub } else if (changingTarget.mWallpaperY >= 0) { mLastWallpaperY = changingTarget.mWallpaperY; } + if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) { + mLastWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX; + } else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) { + mLastWallpaperDisplayOffsetX = changingTarget.mWallpaperDisplayOffsetX; + } + if (target.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) { + mLastWallpaperDisplayOffsetY = target.mWallpaperDisplayOffsetY; + } else if (changingTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) { + mLastWallpaperDisplayOffsetY = changingTarget.mWallpaperDisplayOffsetY; + } } int curTokenIndex = mWallpaperTokens.size(); @@ -2826,6 +2850,14 @@ public class WindowManagerService extends IWindowManager.Stub } } + public void setWindowWallpaperDisplayOffsetLocked(WindowState window, int x, int y) { + if (window.mWallpaperDisplayOffsetX != x || window.mWallpaperDisplayOffsetY != y) { + window.mWallpaperDisplayOffsetX = x; + window.mWallpaperDisplayOffsetY = y; + updateWallpaperOffsetLocked(window, true); + } + } + public Bundle sendWindowWallpaperCommandLocked(WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) { if (window == mWallpaperTarget || window == mLowerWallpaperTarget @@ -10889,6 +10921,12 @@ public class WindowManagerService extends IWindowManager.Stub } pw.print(" mLastWallpaperX="); pw.print(mLastWallpaperX); pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY); + if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE + || mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) { + pw.print(" mLastWallpaperDisplayOffsetX="); pw.print(mLastWallpaperDisplayOffsetX); + pw.print(" mLastWallpaperDisplayOffsetY="); + pw.println(mLastWallpaperDisplayOffsetY); + } if (mInputMethodAnimLayerAdjustment != 0 || mWallpaperAnimLayerAdjustment != 0) { pw.print(" mInputMethodAnimLayerAdjustment="); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index e74de38..0baa2be 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -247,6 +247,11 @@ final class WindowState implements WindowManagerPolicy.WindowState { float mWallpaperXStep = -1; float mWallpaperYStep = -1; + // If a window showing a wallpaper: a raw pixel offset to forcibly apply + // to its window; if a wallpaper window: not used. + int mWallpaperDisplayOffsetX = Integer.MIN_VALUE; + int mWallpaperDisplayOffsetY = Integer.MIN_VALUE; + // Wallpaper windows: pixels offset based on above variables. int mXOffset; int mYOffset; @@ -1584,6 +1589,13 @@ final class WindowState implements WindowManagerPolicy.WindowState { pw.print(prefix); pw.print("mWallpaperXStep="); pw.print(mWallpaperXStep); pw.print(" mWallpaperYStep="); pw.println(mWallpaperYStep); } + if (mWallpaperDisplayOffsetX != Integer.MIN_VALUE + || mWallpaperDisplayOffsetY != Integer.MIN_VALUE) { + pw.print(prefix); pw.print("mWallpaperDisplayOffsetX="); + pw.print(mWallpaperDisplayOffsetX); + pw.print(" mWallpaperDisplayOffsetY="); + pw.println(mWallpaperDisplayOffsetY); + } } String makeInputChannelName() { diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index a871522..dd611ce 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1526,8 +1526,9 @@ class WindowStateAnimator { } void setWallpaperOffset(RectF shownFrame) { - final int left = (int) shownFrame.left; - final int top = (int) shownFrame.top; + final LayoutParams attrs = mWin.getAttrs(); + final int left = ((int) shownFrame.left) - attrs.surfaceInsets.left; + final int top = ((int) shownFrame.top) - attrs.surfaceInsets.top; if (mSurfaceX != left || mSurfaceY != top) { mSurfaceX = left; mSurfaceY = top; diff --git a/tests/WallpaperTest/Android.mk b/tests/WallpaperTest/Android.mk new file mode 100644 index 0000000..b4259cd --- /dev/null +++ b/tests/WallpaperTest/Android.mk @@ -0,0 +1,15 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + +LOCAL_PACKAGE_NAME := WallpaperTest + +LOCAL_PROGUARD_ENABLED := disabled + +include $(BUILD_PACKAGE) + diff --git a/tests/WallpaperTest/AndroidManifest.xml b/tests/WallpaperTest/AndroidManifest.xml new file mode 100644 index 0000000..4c914dd --- /dev/null +++ b/tests/WallpaperTest/AndroidManifest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.wallpapertest" > + + <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" /> + + <application + android:label="@string/app_name" + android:theme="@style/AppTheme" > + <activity + android:name=".MainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <service + android:label="@string/test_wallpaper" + android:name=".TestWallpaper" + android:permission="android.permission.BIND_WALLPAPER" + android:enabled="true"> + <intent-filter> + <action android:name="android.service.wallpaper.WallpaperService" /> + </intent-filter> + <meta-data android:name="android.service.wallpaper" + android:resource="@xml/test_wallpaper" /> + </service> + </application> +</manifest> diff --git a/tests/WallpaperTest/res/drawable-hdpi/test_wallpaper_thumb.png b/tests/WallpaperTest/res/drawable-hdpi/test_wallpaper_thumb.png Binary files differnew file mode 100644 index 0000000..df92eb5 --- /dev/null +++ b/tests/WallpaperTest/res/drawable-hdpi/test_wallpaper_thumb.png diff --git a/tests/WallpaperTest/res/layout/activity_main.xml b/tests/WallpaperTest/res/layout/activity_main.xml new file mode 100644 index 0000000..d968396 --- /dev/null +++ b/tests/WallpaperTest/res/layout/activity_main.xml @@ -0,0 +1,177 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/window_background"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/dimens"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="15dp" + android:textSize="17sp" + android:text="@string/width"/> + <EditText + android:id="@+id/dimen_width" + android:layout_width="60sp" + android:layout_height="wrap_content" + android:inputType="numberDecimal"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="15dp" + android:textSize="17sp" + android:text="@string/height"/> + <EditText + android:id="@+id/dimen_height" + android:layout_width="60sp" + android:layout_height="wrap_content" + android:inputType="numberDecimal"/> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/wallpaper_offset"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="15dp" + android:textSize="17sp" + android:text="@string/x"/> + <EditText + android:id="@+id/walloff_x" + android:layout_width="60sp" + android:layout_height="wrap_content" + android:inputType="numberDecimal"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="15dp" + android:textSize="17sp" + android:text="@string/y"/> + <EditText + android:id="@+id/walloff_y" + android:layout_width="60sp" + android:layout_height="wrap_content" + android:inputType="numberDecimal"/> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/padding"/> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="15dp" + android:textSize="17sp" + android:text="@string/left"/> + <EditText + android:id="@+id/padding_left" + android:layout_width="60sp" + android:layout_height="wrap_content" + android:inputType="number"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="15dp" + android:textSize="17sp" + android:text="@string/right"/> + <EditText + android:id="@+id/padding_right" + android:layout_width="60sp" + android:layout_height="wrap_content" + android:inputType="number"/> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="15dp" + android:textSize="17sp" + android:text="@string/top"/> + <EditText + android:id="@+id/padding_top" + android:layout_width="60sp" + android:layout_height="wrap_content" + android:inputType="number"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="15dp" + android:textSize="17sp" + android:text="@string/bottom"/> + <EditText + android:id="@+id/padding_bottom" + android:layout_width="60sp" + android:layout_height="wrap_content" + android:inputType="number"/> + </LinearLayout> + </LinearLayout> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/display_offset"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="15dp" + android:textSize="17sp" + android:text="@string/x"/> + <EditText + android:id="@+id/dispoff_x" + android:layout_width="60sp" + android:layout_height="wrap_content" + android:inputType="numberSigned"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="15dp" + android:textSize="17sp" + android:text="@string/y"/> + <EditText + android:id="@+id/dispoff_y" + android:layout_width="60sp" + android:layout_height="wrap_content" + android:inputType="numberSigned"/> + </LinearLayout> + </LinearLayout> +</ScrollView> diff --git a/tests/WallpaperTest/res/values-v11/styles.xml b/tests/WallpaperTest/res/values-v11/styles.xml new file mode 100644 index 0000000..95000b2 --- /dev/null +++ b/tests/WallpaperTest/res/values-v11/styles.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2013 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> + +<resources> + + <!-- + Base application theme for API 11+. This theme completely replaces + AppBaseTheme from res/values/styles.xml on API 11+ devices. + --> + <style name="AppBaseTheme" parent="android:Theme.Holo.Wallpaper"> + <!-- API 11 theme customizations can go here. --> + </style> + +</resources>
\ No newline at end of file diff --git a/tests/WallpaperTest/res/values-v21/styles.xml b/tests/WallpaperTest/res/values-v21/styles.xml new file mode 100644 index 0000000..e42d526 --- /dev/null +++ b/tests/WallpaperTest/res/values-v21/styles.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2013 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> + +<resources> + + <!-- + Base application theme for API 21+. This theme completely replaces + AppBaseTheme from BOTH res/values/styles.xml and + res/values-v11/styles.xml on API 14+ devices. + --> + <style name="AppBaseTheme" parent="android:Theme.Material.Wallpaper"> + <!-- API 14 theme customizations can go here. --> + </style> + +</resources>
\ No newline at end of file diff --git a/tests/WallpaperTest/res/values/colors.xml b/tests/WallpaperTest/res/values/colors.xml new file mode 100644 index 0000000..8c08249 --- /dev/null +++ b/tests/WallpaperTest/res/values/colors.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2014 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<resources> + <color name="window_background">#80000000</color> +</resources>
\ No newline at end of file diff --git a/tests/WallpaperTest/res/values/strings.xml b/tests/WallpaperTest/res/values/strings.xml new file mode 100644 index 0000000..fd21259 --- /dev/null +++ b/tests/WallpaperTest/res/values/strings.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2014 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> + +<resources> + <string name="app_name">Wallpaper Test</string> + + <string name="test_wallpaper">Test Wallpaper</string> + <string name="test_wallpaper_author">Google</string> + <string name="test_wallpaper_desc"> + Test wallpaper for use with the wallpaper test app. + </string> + + <string name="dimens">Dimens: </string> + <string name="width">Width: </string> + <string name="height">Height: </string> + + <string name="wallpaper_offset">Wall off: </string> + <string name="x">X: </string> + <string name="y">Y: </string> + + <string name="padding">Padding: </string> + <string name="left">Left: </string> + <string name="right">Right: </string> + <string name="top">Top: </string> + <string name="bottom">Bottom: </string> + + <string name="display_offset">Disp off: </string> +</resources> diff --git a/tests/WallpaperTest/res/values/styles.xml b/tests/WallpaperTest/res/values/styles.xml new file mode 100644 index 0000000..d2b91d6 --- /dev/null +++ b/tests/WallpaperTest/res/values/styles.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2013 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> + +<resources> + + <!-- + Base application theme, dependent on API level. This theme is replaced + by AppBaseTheme from res/values-vXX/styles.xml on newer devices. + --> + <style name="AppBaseTheme" parent="android:Theme.Wallpaper"> + <!-- + Theme customizations available in newer API levels can go in + res/values-vXX/styles.xml, while customizations related to + backward-compatibility can go here. + --> + </style> + + <!-- Application theme. --> + <style name="AppTheme" parent="AppBaseTheme"> + <!-- All customizations that are NOT specific to a particular API-level can go here. --> + </style> + +</resources>
\ No newline at end of file diff --git a/tests/WallpaperTest/res/xml/test_wallpaper.xml b/tests/WallpaperTest/res/xml/test_wallpaper.xml new file mode 100644 index 0000000..9f7d714 --- /dev/null +++ b/tests/WallpaperTest/res/xml/test_wallpaper.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2008, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> + +<!-- The attributes in this XML file provide configuration information --> +<!-- about the polar clock. --> + +<wallpaper xmlns:android="http://schemas.android.com/apk/res/android" + android:author="@string/test_wallpaper_author" + android:description="@string/test_wallpaper_desc" + android:thumbnail="@drawable/test_wallpaper_thumb" /> diff --git a/tests/WallpaperTest/src/com/example/wallpapertest/MainActivity.java b/tests/WallpaperTest/src/com/example/wallpapertest/MainActivity.java new file mode 100644 index 0000000..7880f67 --- /dev/null +++ b/tests/WallpaperTest/src/com/example/wallpapertest/MainActivity.java @@ -0,0 +1,176 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.wallpapertest; + +import android.app.Activity; +import android.app.WallpaperManager; +import android.content.Context; +import android.graphics.Point; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.IBinder; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.util.Log; +import android.view.WindowManager; +import android.widget.TextView; + +public class MainActivity extends Activity { + private static final String TAG = "MainActivity"; + + WallpaperManager mWallpaperManager; + WindowManager mWindowManager; + + TextView mDimenWidthView; + TextView mDimenHeightView; + + TextView mWallOffXView; + TextView mWallOffYView; + + TextView mPaddingLeftView; + TextView mPaddingRightView; + TextView mPaddingTopView; + TextView mPaddingBottomView; + + TextView mDispOffXView; + TextView mDispOffYView; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + mWallpaperManager = (WallpaperManager)getSystemService(Context.WALLPAPER_SERVICE); + mWindowManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE); + + mDimenWidthView = (TextView) findViewById(R.id.dimen_width); + mDimenWidthView.addTextChangedListener(mTextWatcher); + mDimenHeightView = (TextView) findViewById(R.id.dimen_height); + mDimenHeightView.addTextChangedListener(mTextWatcher); + + mWallOffXView = (TextView) findViewById(R.id.walloff_x); + mWallOffXView.addTextChangedListener(mTextWatcher); + mWallOffYView = (TextView) findViewById(R.id.walloff_y); + mWallOffYView.addTextChangedListener(mTextWatcher); + + mPaddingLeftView = (TextView) findViewById(R.id.padding_left); + mPaddingLeftView.addTextChangedListener(mTextWatcher); + mPaddingRightView = (TextView) findViewById(R.id.padding_right); + mPaddingRightView.addTextChangedListener(mTextWatcher); + mPaddingTopView = (TextView) findViewById(R.id.padding_top); + mPaddingTopView.addTextChangedListener(mTextWatcher); + mPaddingBottomView = (TextView) findViewById(R.id.padding_bottom); + mPaddingBottomView.addTextChangedListener(mTextWatcher); + + mDispOffXView = (TextView) findViewById(R.id.dispoff_x); + mDispOffXView.addTextChangedListener(mTextWatcher); + mDispOffYView = (TextView) findViewById(R.id.dispoff_y); + mDispOffYView.addTextChangedListener(mTextWatcher); + + updateDimens(); + updateWallOff(); + updatePadding(); + updateDispOff(); + } + + private int loadPropIntText(TextView view, int baseVal) { + String str = view.getText().toString(); + if (str != null && !TextUtils.isEmpty(str)) { + try { + float fval = Float.parseFloat(str); + return (int)(fval*baseVal); + } catch (NumberFormatException e) { + Log.i(TAG, "Bad number: " + str, e); + } + } + return baseVal; + } + + private float loadFloatText(TextView view) { + String str = view.getText().toString(); + if (str != null && !TextUtils.isEmpty(str)) { + try { + return Float.parseFloat(str); + } catch (NumberFormatException e) { + Log.i(TAG, "Bad number: " + str, e); + } + } + return 0; + } + + private int loadIntText(TextView view) { + String str = view.getText().toString(); + if (str != null && !TextUtils.isEmpty(str)) { + try { + return Integer.parseInt(str); + } catch (NumberFormatException e) { + Log.i(TAG, "Bad number: " + str, e); + } + } + return 0; + } + + public void updateDimens() { + Point minDims = new Point(); + Point maxDims = new Point(); + mWindowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims); + mWallpaperManager.suggestDesiredDimensions( + loadPropIntText(mDimenWidthView, maxDims.x), + loadPropIntText(mDimenHeightView, maxDims.y)); + } + + public void updateWallOff() { + IBinder token = getWindow().getDecorView().getWindowToken(); + if (token != null) { + mWallpaperManager.setWallpaperOffsets(token, loadFloatText(mWallOffXView), + loadFloatText(mWallOffYView)); + } + } + + public void updatePadding() { + Rect padding = new Rect(); + padding.left = loadIntText(mPaddingLeftView); + padding.top = loadIntText(mPaddingTopView); + padding.right = loadIntText(mPaddingRightView); + padding.bottom = loadIntText(mPaddingBottomView); + mWallpaperManager.setDisplayPadding(padding); + } + + public void updateDispOff() { + IBinder token = getWindow().getDecorView().getWindowToken(); + if (token != null) { + mWallpaperManager.setDisplayOffset(token, loadIntText(mDispOffXView), + loadIntText(mDispOffYView)); + } + } + + final TextWatcher mTextWatcher = new TextWatcher() { + @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override public void onTextChanged(CharSequence s, int start, int before, int count) { + updateDimens(); + updateWallOff(); + updatePadding(); + updateDispOff(); + } + + @Override public void afterTextChanged(Editable s) { + } + }; +} diff --git a/tests/WallpaperTest/src/com/example/wallpapertest/TestWallpaper.java b/tests/WallpaperTest/src/com/example/wallpapertest/TestWallpaper.java new file mode 100644 index 0000000..95db6d1 --- /dev/null +++ b/tests/WallpaperTest/src/com/example/wallpapertest/TestWallpaper.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.wallpapertest; + +import android.service.wallpaper.WallpaperService; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.Paint; +import android.graphics.Color; +import android.graphics.RectF; +import android.text.TextPaint; +import android.view.SurfaceHolder; +import android.content.res.XmlResourceParser; + +import android.os.Handler; +import android.util.Log; + +import android.view.WindowInsets; + +public class TestWallpaper extends WallpaperService { + private static final String LOG_TAG = "PolarClock"; + + private final Handler mHandler = new Handler(); + + @Override + public void onCreate() { + super.onCreate(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + public Engine onCreateEngine() { + return new ClockEngine(); + } + + class ClockEngine extends Engine { + private static final int OUTER_COLOR = 0xffff0000; + private static final int INNER_COLOR = 0xff000080; + private static final int STABLE_COLOR = 0xa000ff00; + private static final int TEXT_COLOR = 0xa0ffffff; + + private final Paint.FontMetrics mTextMetrics = new Paint.FontMetrics(); + + private int mPadding; + + private final Rect mMainInsets = new Rect(); + private final Rect mStableInsets = new Rect(); + private boolean mRound = false; + + private int mDesiredWidth; + private int mDesiredHeight; + + private float mOffsetX; + private float mOffsetY; + private float mOffsetXStep; + private float mOffsetYStep; + private int mOffsetXPixels; + private int mOffsetYPixels; + + private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final TextPaint mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + + private final Runnable mDrawClock = new Runnable() { + public void run() { + drawFrame(); + } + }; + private boolean mVisible; + + ClockEngine() { + } + + @Override + public void onCreate(SurfaceHolder surfaceHolder) { + super.onCreate(surfaceHolder); + + mDesiredWidth = getDesiredMinimumWidth(); + mDesiredHeight = getDesiredMinimumHeight(); + + Paint paint = mFillPaint; + paint.setStyle(Paint.Style.FILL); + + paint = mStrokePaint; + paint.setStrokeWidth(3); + paint.setStrokeCap(Paint.Cap.ROUND); + paint.setStyle(Paint.Style.STROKE); + + TextPaint tpaint = mTextPaint; + tpaint.density = getResources().getDisplayMetrics().density; + tpaint.setCompatibilityScaling(getResources().getCompatibilityInfo().applicationScale); + tpaint.setColor(TEXT_COLOR); + tpaint.setTextSize(18 * getResources().getDisplayMetrics().scaledDensity); + tpaint.setShadowLayer(4 * getResources().getDisplayMetrics().density, 0, 0, 0xff000000); + + mTextPaint.getFontMetrics(mTextMetrics); + + mPadding = (int)(16 * getResources().getDisplayMetrics().density); + + if (isPreview()) { + mOffsetX = 0.5f; + mOffsetY = 0.5f; + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + mHandler.removeCallbacks(mDrawClock); + } + + @Override + public void onVisibilityChanged(boolean visible) { + mVisible = visible; + if (!visible) { + mHandler.removeCallbacks(mDrawClock); + } + drawFrame(); + } + + @Override + public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { + super.onSurfaceChanged(holder, format, width, height); + drawFrame(); + } + + @Override + public void onSurfaceCreated(SurfaceHolder holder) { + super.onSurfaceCreated(holder); + } + + @Override + public void onSurfaceDestroyed(SurfaceHolder holder) { + super.onSurfaceDestroyed(holder); + mVisible = false; + mHandler.removeCallbacks(mDrawClock); + } + + @Override + public void onApplyWindowInsets(WindowInsets insets) { + super.onApplyWindowInsets(insets); + mMainInsets.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), + insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()); + mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(), + insets.getStableInsetRight(), insets.getStableInsetBottom()); + mRound = insets.isRound(); + drawFrame(); + } + + @Override + public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) { + super.onDesiredSizeChanged(desiredWidth, desiredHeight); + mDesiredWidth = desiredWidth; + mDesiredHeight = desiredHeight; + drawFrame(); + } + + @Override + public void onOffsetsChanged(float xOffset, float yOffset, + float xStep, float yStep, int xPixels, int yPixels) { + super.onOffsetsChanged(xOffset, yOffset, xStep, yStep, xPixels, yPixels); + + if (isPreview()) return; + + mOffsetX = xOffset; + mOffsetY = yOffset; + mOffsetXStep = xStep; + mOffsetYStep = yStep; + mOffsetXPixels = xPixels; + mOffsetYPixels = yPixels; + + drawFrame(); + } + + void drawFrame() { + final SurfaceHolder holder = getSurfaceHolder(); + final Rect frame = holder.getSurfaceFrame(); + final int width = frame.width(); + final int height = frame.height(); + + Canvas c = null; + try { + c = holder.lockCanvas(); + if (c != null) { + final Paint paint = mFillPaint; + + paint.setColor(OUTER_COLOR); + c.drawRect(0, 0, width, height, paint); + + paint.setColor(INNER_COLOR); + c.drawRect(0+mMainInsets.left, 0+mMainInsets.top, + width-mMainInsets.right, height-mMainInsets.bottom, paint); + + mStrokePaint.setColor(STABLE_COLOR); + c.drawRect(0 + mStableInsets.left, 0 + mStableInsets.top, + width - mStableInsets.right, height - mStableInsets.bottom, + mStrokePaint); + + final int ascdesc = (int)(-mTextMetrics.ascent + mTextMetrics.descent); + final int linegap = (int)(-mTextMetrics.ascent + mTextMetrics.descent + + mTextMetrics.leading); + + int x = mStableInsets.left + mPadding; + int y = height - mStableInsets.bottom - mPadding - ascdesc; + c.drawText("Surface Size: " + width + " x " + height, + x, y, mTextPaint); + y -= linegap; + c.drawText("Desired Size: " + mDesiredWidth + " x " + mDesiredHeight, + x, y, mTextPaint); + y -= linegap; + c.drawText("Cur Offset Raw: " + mOffsetX + ", " + mOffsetY, + x, y, mTextPaint); + y -= linegap; + c.drawText("Cur Offset Step: " + mOffsetXStep + ", " + mOffsetYStep, + x, y, mTextPaint); + y -= linegap; + c.drawText("Cur Offset Pixels: " + mOffsetXPixels + ", " + mOffsetYPixels, + x, y, mTextPaint); + y -= linegap; + c.drawText("Stable Insets: (" + mStableInsets.left + ", " + mStableInsets.top + + ") - (" + mStableInsets.right + ", " + mStableInsets.bottom + ")", + x, y, mTextPaint); + y -= linegap; + c.drawText("System Insets: (" + mMainInsets.left + ", " + mMainInsets.top + + ") - (" + mMainInsets.right + ", " + mMainInsets.bottom + ")", + x, y, mTextPaint); + + } + } finally { + if (c != null) holder.unlockCanvasAndPost(c); + } + } + } +} |