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:
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user