Implement feature #2117336: Create event communication APIs for live wallpaper

Note: currently only implements an async version (no result), and not yet
actually tested.

Change-Id: Id47ed045a4b0eb309ea8c58daf41a0e03eff1d3a
This commit is contained in:
Dianne Hackborn
2009-10-20 20:15:20 -07:00
parent 86dc4d3122
commit 7580493b01
9 changed files with 249 additions and 28 deletions

View File

@@ -24659,6 +24659,29 @@
visibility="public"
>
</method>
<method name="sendWallpaperCommand"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="windowToken" type="android.os.IBinder">
</parameter>
<parameter name="action" type="java.lang.String">
</parameter>
<parameter name="x" type="int">
</parameter>
<parameter name="y" type="int">
</parameter>
<parameter name="z" type="int">
</parameter>
<parameter name="extras" type="android.os.Bundle">
</parameter>
</method>
<method name="setBitmap"
return="void"
abstract="false"

View File

@@ -591,6 +591,31 @@ public class WallpaperManager {
}
}
/**
* Send an arbitrary command to the current active wallpaper.
*
* @param windowToken The window who these offsets should be associated
* with, as returned by {@link android.view.View#getWindowToken()
* View.getWindowToken()}.
* @param action Name of the command to perform. This must be a scoped
* name to avoid collisions, such as "com.mycompany.wallpaper.DOIT".
* @param x Arbitrary integer argument based on command.
* @param y Arbitrary integer argument based on command.
* @param z Arbitrary integer argument based on command.
* @param extras Optional additional information for the command, or null.
*/
public void sendWallpaperCommand(IBinder windowToken, String action,
int x, int y, int z, Bundle extras) {
try {
//Log.v(TAG, "Sending new wallpaper offsets from app...");
ViewRoot.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
windowToken, action, x, y, z, extras, false);
//Log.v(TAG, "...app returning after sending offsets!");
} catch (RemoteException e) {
// Ignore.
}
}
/**
* Clear the offsets previously associated with this window through
* {@link #setWallpaperOffsets(IBinder, float, float)}. This reverts

View File

@@ -27,6 +27,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -73,11 +74,21 @@ public abstract class WallpaperService extends Service {
private static final int MSG_UPDATE_SURFACE = 10000;
private static final int MSG_VISIBILITY_CHANGED = 10010;
private static final int MSG_WALLPAPER_OFFSETS = 10020;
private static final int MSG_WALLPAPER_COMMAND = 10025;
private static final int MSG_WINDOW_RESIZED = 10030;
private static final int MSG_TOUCH_EVENT = 10040;
private Looper mCallbackLooper;
static final class WallpaperCommand {
String action;
int x;
int y;
int z;
Bundle extras;
boolean sync;
}
/**
* The actual implementation of a wallpaper. A wallpaper service may
* have multiple instances running (for example as a real wallpaper
@@ -233,6 +244,22 @@ public abstract class WallpaperService extends Service {
}
}
public void dispatchWallpaperCommand(String action, int x, int y,
int z, Bundle extras, boolean sync) {
synchronized (mLock) {
if (DEBUG) Log.v(TAG, "Dispatch wallpaper command: " + x + ", " + y);
WallpaperCommand cmd = new WallpaperCommand();
cmd.action = action;
cmd.x = x;
cmd.y = y;
cmd.z = z;
cmd.extras = extras;
cmd.sync = sync;
Message msg = mCaller.obtainMessage(MSG_WALLPAPER_COMMAND);
msg.obj = cmd;
mCaller.sendMessage(msg);
}
}
};
/**
@@ -337,6 +364,28 @@ public abstract class WallpaperService extends Service {
int xPixelOffset, int yPixelOffset) {
}
/**
* Process a command that was sent to the wallpaper with
* {@link WallpaperManager#sendWallpaperCommand(String, int, int, int, Bundle)}.
* The default implementation does nothing, and always returns null
* as the result.
*
* @param action The name of the command to perform. This tells you
* what to do and how to interpret the rest of the arguments.
* @param x Generic integer parameter.
* @param y Generic integer parameter.
* @param z Generic integer parameter.
* @param extras Any additional parameters.
* @param resultRequested If true, the caller is requesting that
* a result, appropriate for the command, be returned back.
* @return If returning a result, create a Bundle and place the
* result data in to it. Otherwise return null.
*/
public Bundle onCommand(String action, int x, int y, int z,
Bundle extras, boolean resultRequested) {
return null;
}
/**
* Called when an application has changed the desired virtual size of
* the wallpaper.
@@ -585,6 +634,23 @@ public abstract class WallpaperService extends Service {
}
}
void doCommand(WallpaperCommand cmd) {
Bundle result;
if (!mDestroyed) {
result = onCommand(cmd.action, cmd.x, cmd.y, cmd.z,
cmd.extras, cmd.sync);
} else {
result = null;
}
if (cmd.sync) {
try {
if (DEBUG) Log.v(TAG, "Reporting command complete");
mSession.wallpaperCommandComplete(mWindow.asBinder(), result);
} catch (RemoteException e) {
}
}
}
void detach() {
mDestroyed = true;
@@ -709,6 +775,10 @@ public abstract class WallpaperService extends Service {
case MSG_WALLPAPER_OFFSETS: {
mEngine.doOffsetsChanged();
} break;
case MSG_WALLPAPER_COMMAND: {
WallpaperCommand cmd = (WallpaperCommand)message.obj;
mEngine.doCommand(cmd);
} break;
case MSG_WINDOW_RESIZED: {
final boolean reportDraw = message.arg1 != 0;
mEngine.updateSurface(true, false);

View File

@@ -18,11 +18,11 @@
package android.view;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.os.ParcelFileDescriptor;
/**
* API back to a client window that the Window Manager uses to inform it of
* interesting things happening.
@@ -63,4 +63,7 @@ oneway interface IWindow {
* Called for wallpaper windows when their offsets change.
*/
void dispatchWallpaperOffsets(float x, float y, boolean sync);
void dispatchWallpaperCommand(String action, int x, int y,
int z, in Bundle extras, boolean sync);
}

View File

@@ -19,6 +19,7 @@ package android.view;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
import android.view.IWindow;
import android.view.MotionEvent;
import android.view.WindowManager;
@@ -116,4 +117,9 @@ interface IWindowSession {
void setWallpaperPosition(IBinder windowToken, float x, float y);
void wallpaperOffsetsComplete(IBinder window);
Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, in Bundle extras, boolean sync);
void wallpaperCommandComplete(IBinder window, in Bundle result);
}

View File

@@ -2903,6 +2903,16 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
}
public void dispatchWallpaperCommand(String action, int x, int y,
int z, Bundle extras, boolean sync) {
if (sync) {
try {
sWindowSession.wallpaperCommandComplete(asBinder(), null);
} catch (RemoteException e) {
}
}
}
}
/**

View File

@@ -1,6 +1,7 @@
package com.android.internal.view;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.view.IWindow;
@@ -101,4 +102,14 @@ public class BaseIWindow extends IWindow.Stub {
}
}
}
public void dispatchWallpaperCommand(String action, int x, int y,
int z, Bundle extras, boolean sync) {
if (sync) {
try {
mSession.wallpaperCommandComplete(asBinder(), null);
} catch (RemoteException e) {
}
}
}
}

View File

@@ -63,6 +63,7 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
@@ -432,8 +433,6 @@ public class WindowManagerService extends IWindowManager.Stub
int mWallpaperAnimLayerAdjustment;
float mLastWallpaperX = -1;
float mLastWallpaperY = -1;
// Lock for waiting for the wallpaper.
final Object mWaitingOnWallpaperLock = new Object();
// This is set when we are waiting for a wallpaper to tell us it is done
// changing its scroll position.
WindowState mWaitingOnWallpaper;
@@ -1604,34 +1603,30 @@ public class WindowManagerService extends IWindowManager.Stub
+ wallpaperWin + " x=" + wallpaperWin.mWallpaperX
+ " y=" + wallpaperWin.mWallpaperY);
if (sync) {
synchronized (mWaitingOnWallpaperLock) {
mWaitingOnWallpaper = wallpaperWin;
}
mWaitingOnWallpaper = wallpaperWin;
}
wallpaperWin.mClient.dispatchWallpaperOffsets(
wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY, sync);
if (sync) {
synchronized (mWaitingOnWallpaperLock) {
if (mWaitingOnWallpaper != null) {
long start = SystemClock.uptimeMillis();
if ((mLastWallpaperTimeoutTime+WALLPAPER_TIMEOUT_RECOVERY)
< start) {
try {
if (DEBUG_WALLPAPER) Log.v(TAG,
"Waiting for offset complete...");
mWaitingOnWallpaperLock.wait(WALLPAPER_TIMEOUT);
} catch (InterruptedException e) {
}
if (DEBUG_WALLPAPER) Log.v(TAG, "Offset complete!");
if ((start+WALLPAPER_TIMEOUT)
< SystemClock.uptimeMillis()) {
Log.i(TAG, "Timeout waiting for wallpaper to offset: "
+ wallpaperWin);
mLastWallpaperTimeoutTime = start;
}
if (mWaitingOnWallpaper != null) {
long start = SystemClock.uptimeMillis();
if ((mLastWallpaperTimeoutTime+WALLPAPER_TIMEOUT_RECOVERY)
< start) {
try {
if (DEBUG_WALLPAPER) Log.v(TAG,
"Waiting for offset complete...");
mWindowMap.wait(WALLPAPER_TIMEOUT);
} catch (InterruptedException e) {
}
if (DEBUG_WALLPAPER) Log.v(TAG, "Offset complete!");
if ((start+WALLPAPER_TIMEOUT)
< SystemClock.uptimeMillis()) {
Log.i(TAG, "Timeout waiting for wallpaper to offset: "
+ wallpaperWin);
mLastWallpaperTimeoutTime = start;
}
mWaitingOnWallpaper = null;
}
mWaitingOnWallpaper = null;
}
}
} catch (RemoteException e) {
@@ -1642,11 +1637,11 @@ public class WindowManagerService extends IWindowManager.Stub
}
void wallpaperOffsetsComplete(IBinder window) {
synchronized (mWaitingOnWallpaperLock) {
synchronized (mWindowMap) {
if (mWaitingOnWallpaper != null &&
mWaitingOnWallpaper.mClient.asBinder() == window) {
mWaitingOnWallpaper = null;
mWaitingOnWallpaperLock.notifyAll();
mWindowMap.notifyAll();
}
}
}
@@ -2196,6 +2191,47 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
void wallpaperCommandComplete(IBinder window, Bundle result) {
synchronized (mWindowMap) {
if (mWaitingOnWallpaper != null &&
mWaitingOnWallpaper.mClient.asBinder() == window) {
mWaitingOnWallpaper = null;
mWindowMap.notifyAll();
}
}
}
public Bundle sendWindowWallpaperCommandLocked(WindowState window,
String action, int x, int y, int z, Bundle extras, boolean sync) {
if (window == mWallpaperTarget || window == mLowerWallpaperTarget
|| window == mUpperWallpaperTarget) {
boolean doWait = sync;
int curTokenIndex = mWallpaperTokens.size();
while (curTokenIndex > 0) {
curTokenIndex--;
WindowToken token = mWallpaperTokens.get(curTokenIndex);
int curWallpaperIndex = token.windows.size();
while (curWallpaperIndex > 0) {
curWallpaperIndex--;
WindowState wallpaper = token.windows.get(curWallpaperIndex);
try {
wallpaper.mClient.dispatchWallpaperCommand(action,
x, y, z, extras, sync);
// We only want to be synchronous with one wallpaper.
sync = false;
} catch (RemoteException e) {
}
}
}
if (doWait) {
// XXX Need to wait for result.
}
}
return null;
}
public int relayoutWindow(Session session, IWindow client,
WindowManager.LayoutParams attrs, int requestedWidth,
int requestedHeight, int viewVisibility, boolean insetsPending,
@@ -6565,6 +6601,24 @@ public class WindowManagerService extends IWindowManager.Stub
WindowManagerService.this.wallpaperOffsetsComplete(window);
}
public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, Bundle extras, boolean sync) {
synchronized(mWindowMap) {
long ident = Binder.clearCallingIdentity();
try {
return sendWindowWallpaperCommandLocked(
windowForClientLocked(this, window),
action, x, y, z, extras, sync);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
public void wallpaperCommandComplete(IBinder window, Bundle result) {
WindowManagerService.this.wallpaperCommandComplete(window, result);
}
void windowAddedLocked() {
if (mSurfaceSession == null) {
if (localLOGV) Log.v(

View File

@@ -36,6 +36,7 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -1068,6 +1069,18 @@ public final class Bridge implements ILayoutBridge {
// pass for now.
}
@SuppressWarnings("unused")
public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, Bundle extras, boolean sync) {
// pass for now.
return null;
}
@SuppressWarnings("unused")
public void wallpaperCommandComplete(IBinder window, Bundle result) {
// pass for now.
}
@SuppressWarnings("unused")
public void closeSystemDialogs(String reason) {
// pass for now.
@@ -1131,6 +1144,12 @@ public final class Bridge implements ILayoutBridge {
// pass for now.
}
@SuppressWarnings("unused")
public void dispatchWallpaperCommand(String action, int x, int y,
int z, Bundle extras, boolean sync) {
// pass for now.
}
@SuppressWarnings("unused")
public void closeSystemDialogs(String reason) {
// pass for now.