summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt7
-rw-r--r--core/java/android/app/IWallpaperManager.aidl6
-rw-r--r--core/java/android/app/WallpaperManager.java43
-rw-r--r--core/java/android/service/wallpaper/IWallpaperEngine.aidl2
-rw-r--r--core/java/android/service/wallpaper/IWallpaperService.aidl3
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java172
-rw-r--r--core/java/android/view/IWindowSession.aidl5
-rw-r--r--core/java/android/view/ViewRootImpl.java2
-rw-r--r--core/java/android/view/WindowInsets.java54
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindowManager.java26
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java86
-rw-r--r--services/core/java/com/android/server/wm/Session.java12
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java38
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java12
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java5
-rw-r--r--tests/WallpaperTest/Android.mk15
-rw-r--r--tests/WallpaperTest/AndroidManifest.xml31
-rw-r--r--tests/WallpaperTest/res/drawable-hdpi/test_wallpaper_thumb.pngbin0 -> 34700 bytes
-rw-r--r--tests/WallpaperTest/res/layout/activity_main.xml177
-rw-r--r--tests/WallpaperTest/res/values-v11/styles.xml28
-rw-r--r--tests/WallpaperTest/res/values-v21/styles.xml29
-rw-r--r--tests/WallpaperTest/res/values/colors.xml19
-rw-r--r--tests/WallpaperTest/res/values/strings.xml42
-rw-r--r--tests/WallpaperTest/res/values/styles.xml37
-rw-r--r--tests/WallpaperTest/res/xml/test_wallpaper.xml26
-rw-r--r--tests/WallpaperTest/src/com/example/wallpapertest/MainActivity.java176
-rw-r--r--tests/WallpaperTest/src/com/example/wallpapertest/TestWallpaper.java251
27 files changed, 1254 insertions, 50 deletions
diff --git a/api/current.txt b/api/current.txt
index fd72d34..ad36d73 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27275,6 +27275,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);
@@ -34989,12 +34990,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 4299e2e..7dd11f1 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 cd3eab5..c23468d 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 a1afe29..694e7b2 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
@@ -10880,6 +10912,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 3d4be12..1cd2dcd 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
new file mode 100644
index 0000000..df92eb5
--- /dev/null
+++ b/tests/WallpaperTest/res/drawable-hdpi/test_wallpaper_thumb.png
Binary files differ
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);
+ }
+ }
+ }
+}