From 8df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bd Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 17 Aug 2009 15:15:18 -0700 Subject: [PATCH] Allow wallpapers to get touch events. --- api/current.xml | 13 +++ .../service/wallpaper/WallpaperService.java | 82 +++++++++++++++++-- core/java/android/view/IWindow.aidl | 4 +- core/java/android/view/MotionEvent.java | 38 +++++++++ core/java/android/view/SurfaceView.java | 6 +- core/java/android/view/ViewRoot.java | 41 +++++----- .../android/internal/os/HandlerCaller.java | 8 ++ .../service/wallpaper/ImageWallpaper.java | 8 ++ .../android/internal/view/BaseIWindow.java | 36 ++++++-- .../android/server/WindowManagerService.java | 63 ++++++++++++-- .../com/android/layoutlib/bridge/Bridge.java | 4 +- 11 files changed, 253 insertions(+), 50 deletions(-) diff --git a/api/current.xml b/api/current.xml index 461fc38a6275f..ca8d81f9524b5 100644 --- a/api/current.xml +++ b/api/current.xml @@ -144050,6 +144050,19 @@ + + + + = NP) { + System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, NP); + } else { + ev.mPointerIdentifiers = (int[])o.mPointerIdentifiers.clone(); + } + + final int ND = NP * NUM_SAMPLE_DATA; + if (ev.mDataSamples.length >= ND) { + System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND); + } else { + ev.mDataSamples = (float[])o.mDataSamples.clone(); + } + + return ev; + } + /** * Recycle the MotionEvent, to be re-used by a later caller. After calling * this function you must not ever touch the event again. diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 3b649450cc692..ea879ed943588 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -481,7 +481,8 @@ public class SurfaceView extends View { } } - public void dispatchPointer(MotionEvent event, long eventTime) { + public void dispatchPointer(MotionEvent event, long eventTime, + boolean callWhenDone) { Log.w("SurfaceView", "Unexpected pointer event in surface: " + event); //if (mSession != null && mSurface != null) { // try { @@ -491,7 +492,8 @@ public class SurfaceView extends View { //} } - public void dispatchTrackball(MotionEvent event, long eventTime) { + public void dispatchTrackball(MotionEvent event, long eventTime, + boolean callWhenDone) { Log.w("SurfaceView", "Unexpected trackball event in surface: " + event); //if (mSession != null && mSurface != null) { // try { diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 4623bb56a9865..3b780604d0dcc 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -1637,8 +1637,8 @@ public final class ViewRoot extends Handler implements ViewParent, break; case DISPATCH_POINTER: { MotionEvent event = (MotionEvent)msg.obj; - - boolean didFinish; + boolean callWhenDone = msg.arg1 != 0; + if (event == null) { try { long timeBeforeGettingEvents; @@ -1654,9 +1654,7 @@ public final class ViewRoot extends Handler implements ViewParent, } } catch (RemoteException e) { } - didFinish = true; - } else { - didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE; + callWhenDone = false; } if (event != null && mTranslator != null) { mTranslator.translateEventInScreenToAppWindow(event); @@ -1728,7 +1726,7 @@ public final class ViewRoot extends Handler implements ViewParent, } } } finally { - if (!didFinish) { + if (callWhenDone) { try { sWindowSession.finishKey(mWindow); } catch (RemoteException e) { @@ -1743,7 +1741,7 @@ public final class ViewRoot extends Handler implements ViewParent, } } break; case DISPATCH_TRACKBALL: - deliverTrackballEvent((MotionEvent)msg.obj); + deliverTrackballEvent((MotionEvent)msg.obj, msg.arg1 != 0); break; case DISPATCH_APP_VISIBILITY: handleAppVisibility(msg.arg1 != 0); @@ -1985,16 +1983,13 @@ public final class ViewRoot extends Handler implements ViewParent, } - private void deliverTrackballEvent(MotionEvent event) { - boolean didFinish; + private void deliverTrackballEvent(MotionEvent event, boolean callWhenDone) { if (event == null) { try { event = sWindowSession.getPendingTrackballMove(mWindow); } catch (RemoteException e) { } - didFinish = true; - } else { - didFinish = false; + callWhenDone = false; } if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event); @@ -2012,7 +2007,7 @@ public final class ViewRoot extends Handler implements ViewParent, } } finally { if (handled) { - if (!didFinish) { + if (callWhenDone) { try { sWindowSession.finishKey(mWindow); } catch (RemoteException e) { @@ -2128,7 +2123,7 @@ public final class ViewRoot extends Handler implements ViewParent, mLastTrackballTime = curTime; } } finally { - if (!didFinish) { + if (callWhenDone) { try { sWindowSession.finishKey(mWindow); } catch (RemoteException e) { @@ -2591,15 +2586,19 @@ public final class ViewRoot extends Handler implements ViewParent, sendMessageAtTime(msg, event.getEventTime()); } - public void dispatchPointer(MotionEvent event, long eventTime) { + public void dispatchPointer(MotionEvent event, long eventTime, + boolean callWhenDone) { Message msg = obtainMessage(DISPATCH_POINTER); msg.obj = event; + msg.arg1 = callWhenDone ? 1 : 0; sendMessageAtTime(msg, eventTime); } - public void dispatchTrackball(MotionEvent event, long eventTime) { + public void dispatchTrackball(MotionEvent event, long eventTime, + boolean callWhenDone) { Message msg = obtainMessage(DISPATCH_TRACKBALL); msg.obj = event; + msg.arg1 = callWhenDone ? 1 : 0; sendMessageAtTime(msg, eventTime); } @@ -2772,23 +2771,25 @@ public final class ViewRoot extends Handler implements ViewParent, } } - public void dispatchPointer(MotionEvent event, long eventTime) { + public void dispatchPointer(MotionEvent event, long eventTime, + boolean callWhenDone) { final ViewRoot viewRoot = mViewRoot.get(); if (viewRoot != null) { if (MEASURE_LATENCY) { // Note: eventTime is in milliseconds ViewRoot.lt.sample("* ViewRoot b4 dispatchPtr", System.nanoTime() - eventTime * 1000000); } - viewRoot.dispatchPointer(event, eventTime); + viewRoot.dispatchPointer(event, eventTime, callWhenDone); } else { new EventCompletion(mMainLooper, this, null, true, event); } } - public void dispatchTrackball(MotionEvent event, long eventTime) { + public void dispatchTrackball(MotionEvent event, long eventTime, + boolean callWhenDone) { final ViewRoot viewRoot = mViewRoot.get(); if (viewRoot != null) { - viewRoot.dispatchTrackball(event, eventTime); + viewRoot.dispatchTrackball(event, eventTime, callWhenDone); } else { new EventCompletion(mMainLooper, this, null, false, event); } diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java index e4c473d41059b..582502488bb40 100644 --- a/core/java/com/android/internal/os/HandlerCaller.java +++ b/core/java/com/android/internal/os/HandlerCaller.java @@ -97,6 +97,14 @@ public class HandlerCaller { return mH.hasMessages(what); } + public void removeMessages(int what) { + mH.removeMessages(what); + } + + public void removeMessages(int what, Object obj) { + mH.removeMessages(what, obj); + } + public void sendMessage(Message msg) { mH.sendMessage(msg); } diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java index 7147ac01ea516..3f2979fe67f0b 100644 --- a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java +++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java @@ -22,6 +22,7 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.service.wallpaper.WallpaperService; import android.util.Log; +import android.view.MotionEvent; import android.view.SurfaceHolder; import android.content.Context; import android.content.IntentFilter; @@ -75,6 +76,7 @@ public class ImageWallpaper extends WallpaperService { super.onCreate(surfaceHolder); updateWallpaper(); surfaceHolder.setSizeFromLayout(); + //setTouchEventsEnabled(true); } @Override @@ -82,6 +84,12 @@ public class ImageWallpaper extends WallpaperService { drawFrame(); } + @Override + public void onTouchEvent(MotionEvent event) { + super.onTouchEvent(event); + Log.i("foo", "Touch event: " + event); + } + @Override public void onOffsetsChanged(float xOffset, float yOffset, int xPixels, int yPixels) { diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java index a030db76e010d..f4f6297853867 100644 --- a/core/java/com/android/internal/view/BaseIWindow.java +++ b/core/java/com/android/internal/view/BaseIWindow.java @@ -32,23 +32,47 @@ public class BaseIWindow extends IWindow.Stub { } } - public void dispatchPointer(MotionEvent event, long eventTime) { + public boolean onDispatchPointer(MotionEvent event, long eventTime, + boolean callWhenDone) { + event.recycle(); + return false; + } + + public void dispatchPointer(MotionEvent event, long eventTime, + boolean callWhenDone) { try { if (event == null) { event = mSession.getPendingPointerMove(this); - } else if (event.getAction() != MotionEvent.ACTION_OUTSIDE) { - mSession.finishKey(this); + onDispatchPointer(event, eventTime, false); + } else if (callWhenDone) { + if (!onDispatchPointer(event, eventTime, true)) { + mSession.finishKey(this); + } + } else { + onDispatchPointer(event, eventTime, false); } } catch (RemoteException ex) { } } - public void dispatchTrackball(MotionEvent event, long eventTime) { + public boolean onDispatchTrackball(MotionEvent event, long eventTime, + boolean callWhenDone) { + event.recycle(); + return false; + } + + public void dispatchTrackball(MotionEvent event, long eventTime, + boolean callWhenDone) { try { if (event == null) { event = mSession.getPendingTrackballMove(this); - } else if (event.getAction() != MotionEvent.ACTION_OUTSIDE) { - mSession.finishKey(this); + onDispatchTrackball(event, eventTime, false); + } else if (callWhenDone) { + if (!onDispatchTrackball(event, eventTime, true)) { + mSession.finishKey(this); + } + } else { + onDispatchTrackball(event, eventTime, false); } } catch (RemoteException ex) { } diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 6af85db0a54a8..988c3d5ab8c3c 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -1247,7 +1247,8 @@ public class WindowManagerService extends IWindowManager.Stub WindowState wallpaper = token.windows.get(curWallpaperIndex); if (visible) { - updateWallpaperOffsetLocked(w, wallpaper, dw, dh); + updateWallpaperOffsetLocked(mWallpaperTarget, + wallpaper, dw, dh); } // First, make sure the client has the current visibility @@ -1389,6 +1390,32 @@ public class WindowManagerService extends IWindowManager.Stub return changed; } + void sendPointerToWallpaperLocked(WindowState srcWin, + MotionEvent pointer, long eventTime) { + 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); + if ((wallpaper.mAttrs.flags & + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) { + continue; + } + try { + MotionEvent ev = MotionEvent.obtainNoHistory(pointer); + ev.offsetLocation(srcWin.mFrame.left-wallpaper.mFrame.left, + srcWin.mFrame.top-wallpaper.mFrame.top); + wallpaper.mClient.dispatchPointer(ev, eventTime, false); + } catch (RemoteException e) { + Log.w(TAG, "Failure sending pointer to wallpaper", e); + } + } + } + } + public int addWindow(Session session, IWindow client, WindowManager.LayoutParams attrs, int viewVisibility, Rect outContentInsets) { @@ -1677,6 +1704,8 @@ public class WindowManagerService extends IWindowManager.Stub } private void removeWindowInnerLocked(Session session, WindowState win) { + mKeyWaiter.finishedKey(session, win.mClient, true, + KeyWaiter.RETURN_NOTHING); mKeyWaiter.releasePendingPointerLocked(win.mSession); mKeyWaiter.releasePendingTrackballLocked(win.mSession); @@ -4343,7 +4372,7 @@ public class WindowManagerService extends IWindowManager.Stub final Rect frame = out.mFrame; oev.offsetLocation(-(float)frame.left, -(float)frame.top); try { - out.mClient.dispatchPointer(oev, eventTime); + out.mClient.dispatchPointer(oev, eventTime, false); } catch (android.os.RemoteException e) { Log.i(TAG, "WINDOW DIED during outside motion dispatch: " + out); } @@ -4356,6 +4385,12 @@ public class WindowManagerService extends IWindowManager.Stub final Rect frame = target.mFrame; ev.offsetLocation(-(float)frame.left, -(float)frame.top); mKeyWaiter.bindTargetWindowLocked(target); + + // If we are on top of the wallpaper, then the wallpaper also + // gets to see this movement. + if (mWallpaperTarget == target) { + sendPointerToWallpaperLocked(target, ev, eventTime); + } } } @@ -4370,7 +4405,7 @@ public class WindowManagerService extends IWindowManager.Stub lt.sample("6 before svr->client ipc ", System.nanoTime() - eventTimeNano); } - target.mClient.dispatchPointer(ev, eventTime); + target.mClient.dispatchPointer(ev, eventTime, true); if (MEASURE_LATENCY) { lt.sample("7 after svr->client ipc ", System.nanoTime() - eventTimeNano); @@ -4446,7 +4481,7 @@ public class WindowManagerService extends IWindowManager.Stub } try { - focus.mClient.dispatchTrackball(ev, eventTime); + focus.mClient.dispatchTrackball(ev, eventTime, true); return INJECT_SUCCEEDED; } catch (android.os.RemoteException e) { Log.i(TAG, "WINDOW DIED during key dispatch: " + focus); @@ -5221,14 +5256,16 @@ public class WindowManagerService extends IWindowManager.Stub return null; } + MotionEvent res = null; + QueuedEvent qev = null; + WindowState win = null; + synchronized (this) { if (DEBUG_INPUT) Log.v( TAG, "finishedKey: client=" + client.asBinder() + ", force=" + force + ", last=" + mLastBinder + " (token=" + (mLastWin != null ? mLastWin.mToken : null) + ")"); - QueuedEvent qev = null; - WindowState win = null; if (returnWhat == RETURN_PENDING_POINTER) { qev = session.mPendingPointerMove; win = session.mPendingPointerWindow; @@ -5258,17 +5295,25 @@ public class WindowManagerService extends IWindowManager.Stub } if (qev != null) { - MotionEvent res = (MotionEvent)qev.event; + res = (MotionEvent)qev.event; if (DEBUG_INPUT) Log.v(TAG, "Returning pending motion: " + res); mQueue.recycleEvent(qev); if (win != null && returnWhat == RETURN_PENDING_POINTER) { res.offsetLocation(-win.mFrame.left, -win.mFrame.top); } - return res; } - return null; } + + if (res != null && returnWhat == RETURN_PENDING_POINTER) { + synchronized (mWindowMap) { + if (mWallpaperTarget == win) { + sendPointerToWallpaperLocked(win, res, res.getEventTime()); + } + } + } + + return res; } void tickle() { diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index 8d44ac08558ea..e941b7f8765a0 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -1021,12 +1021,12 @@ public final class Bridge implements ILayoutBridge { } @SuppressWarnings("unused") - public void dispatchPointer(MotionEvent arg0, long arg1) throws RemoteException { + public void dispatchPointer(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException { // pass for now. } @SuppressWarnings("unused") - public void dispatchTrackball(MotionEvent arg0, long arg1) throws RemoteException { + public void dispatchTrackball(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException { // pass for now. }