Enables or disables views consistency check. Even when this property is enabled, * view consistency checks happen only if {@link android.util.Config#DEBUG} is set diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 6c57e1ed79b49..e71a4d6c5cc03 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -36,7 +36,6 @@ import android.os.Parcelable; import android.os.SystemClock; import android.util.AttributeSet; import android.util.Log; -import android.util.Slog; import android.util.SparseArray; import android.view.accessibility.AccessibilityEvent; import android.view.animation.Animation; @@ -72,7 +71,6 @@ import java.util.ArrayList; public abstract class ViewGroup extends View implements ViewParent, ViewManager { private static final boolean DBG = false; - private static final String TAG = "ViewGroup"; /** * Views which have been hidden or removed which need to be animated on @@ -868,9 +866,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final float tx = event.mX; final float ty = event.mY; - // !!! BUGCHECK: If we have a ViewGroup, we must necessarily have a ViewRoot, - // so we don't need to check getRootView() for null here? - ViewRoot root = (ViewRoot)(getRootView().getParent()); + ViewRoot root = getViewRoot(); // Dispatch down the view hierarchy switch (event.mAction) { @@ -883,10 +879,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int count = mChildrenCount; final View[] children = mChildren; for (int i = 0; i < count; i++) { - final boolean handled = children[i].dispatchDragEvent(event); - children[i].mCanAcceptDrop = handled; - if (handled) { - mChildAcceptsDrag = true; + final View child = children[i]; + if (child.getVisibility() == VISIBLE) { + final boolean handled = children[i].dispatchDragEvent(event); + children[i].mCanAcceptDrop = handled; + if (handled) { + mChildAcceptsDrag = true; + } } } @@ -901,7 +900,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int count = mChildrenCount; final View[] children = mChildren; for (int i = 0; i < count; i++) { - children[i].dispatchDragEvent(event); + final View child = children[i]; + if (child.getVisibility() == VISIBLE) { + child.dispatchDragEvent(event); + } } // We consider drag-ended to have been handled if one of our children // had offered to handle the drag. @@ -921,7 +923,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager root.setDragFocus(event, target); mCurrentDragView = target; } - + // Dispatch the actual drag location notice, localized into its coordinates if (target != null) { event.mX = mLocalPoint.x; @@ -935,7 +937,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } break; case DragEvent.ACTION_DROP: { - if (View.DEBUG_DRAG) Slog.d(TAG, "Drop event: " + event); + if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event); View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint); if (target != null) { event.mX = mLocalPoint.x; @@ -957,8 +959,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // Find the frontmost child view that lies under the given point, and calculate // the position within its own local coordinate system. View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) { - final float scrolledX = x + mScrollX; - final float scrolledY = y + mScrollY; final int count = mChildrenCount; final View[] children = mChildren; for (int i = count - 1; i >= 0; i--) { @@ -967,20 +967,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager continue; } - float localX = scrolledX - child.mLeft; - float localY = scrolledY - child.mTop; - if (!child.hasIdentityMatrix() && mAttachInfo != null) { - // non-identity matrix: transform the point into the view's coordinates - final float[] localXY = mAttachInfo.mTmpTransformLocation; - localXY[0] = localX; - localXY[1] = localY; - child.getInverseMatrix().mapPoints(localXY); - localX = localXY[0]; - localY = localXY[1]; - } - if (localX >= 0 && localY >= 0 && localX < (child.mRight - child.mLeft) && - localY < (child.mBottom - child.mTop)) { - outLocalPoint.set(localX, localY); + if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) { return child; } } @@ -1108,7 +1095,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager continue; } - if (!isTransformedTouchPointInView(x, y, child)) { + if (!isTransformedTouchPointInView(x, y, child, null)) { // New pointer is out of child's bounds. continue; } @@ -1292,7 +1279,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /* Returns true if a child view contains the specified point when transformed * into its coordinate space. * Child must not be null. */ - private final boolean isTransformedTouchPointInView(float x, float y, View child) { + private final boolean isTransformedTouchPointInView(float x, float y, View child, + PointF outLocalPoint) { float localX = x + mScrollX - child.mLeft; float localY = y + mScrollY - child.mTop; if (! child.hasIdentityMatrix() && mAttachInfo != null) { @@ -1303,7 +1291,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager localX = localXY[0]; localY = localXY[1]; } - return child.pointInView(localX, localY); + final boolean isInView = child.pointInView(localX, localY); + if (isInView && outLocalPoint != null) { + outLocalPoint.set(localX, localY); + } + return isInView; } /* Transforms a motion event into the coordinate space of a particular child view, diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index c63f7d605b3c8..155122f92116e 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -24,6 +24,7 @@ import com.android.internal.view.RootViewSurfaceTaker; import android.graphics.Canvas; import android.graphics.PixelFormat; import android.graphics.PorterDuff; +import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; @@ -205,6 +206,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn ClipDescription mDragDescription; View mCurrentDragView; final PointF mDragPoint = new PointF(); + final PointF mLastTouchPoint = new PointF(); /** * see {@link #playSoundEffect(int)} @@ -2024,6 +2026,9 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn if (MEASURE_LATENCY) { lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano()); } + // cache for possible drag-initiation + mLastTouchPoint.x = event.getRawX(); + mLastTouchPoint.y = event.getRawY(); handled = mView.dispatchTouchEvent(event); if (MEASURE_LATENCY) { lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano()); @@ -2509,6 +2514,11 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn event.recycle(); } + public void getLastTouchPoint(Point outLocation) { + outLocation.x = (int) mLastTouchPoint.x; + outLocation.y = (int) mLastTouchPoint.y; + } + public void setDragFocus(DragEvent event, View newDragTarget) { final int action = event.mAction; // If we've dragged off of a view, send it the EXITED message diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java index a96009787a224..fe306b3193955 100644 --- a/services/java/com/android/server/InputManager.java +++ b/services/java/com/android/server/InputManager.java @@ -342,7 +342,6 @@ public class InputManager { if (toChannel == null) { throw new IllegalArgumentException("toChannel must not be null."); } - Slog.d(TAG, "transferring touch focus"); return nativeTransferTouchFocus(fromChannel, toChannel); } diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 0727a791aea48..ba3897d48a593 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -569,8 +569,10 @@ public class WindowManagerService extends IWindowManager.Stub DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED, 0, 0, mDataDescription, null); - for (WindowState ws : mWindows) { - sendDragStartedLw(ws, evt); + final int N = mWindows.size(); + for (int i = 0; i < N; i++) { + // sendDragStartedLw() clones evt for local-process dispatch + sendDragStartedLw(mWindows.get(i), evt); } evt.recycle(); } @@ -579,10 +581,17 @@ public class WindowManagerService extends IWindowManager.Stub * designated window is potentially a drop recipient. There are race situations * around DRAG_ENDED broadcast, so we make sure that once we've declared that * the drag has ended, we never send out another DRAG_STARTED for this drag action. + * + * This method clones the 'event' parameter if it's being delivered to the same + * process, so it's safe for the caller to call recycle() on the event afterwards. */ - private void sendDragStartedLw(WindowState newWin, final DragEvent event) { + private void sendDragStartedLw(WindowState newWin, DragEvent event) { if (!mDragEnded && newWin.isPotentialDragTarget()) { try { + // clone for local callees since dispatch will recycle the event + if (Process.myPid() == newWin.mSession.mPid) { + event = DragEvent.obtain(event); + } newWin.mClient.dispatchDragEvent(event); // track each window that we've notified that the drag is starting mNotifiedWindows.add(newWin); @@ -608,6 +617,7 @@ public class WindowManagerService extends IWindowManager.Stub } DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED, 0, 0, mDataDescription, null); + // sendDragStartedLw() clones 'event' if the window is process-local sendDragStartedLw(newWin, event); event.recycle(); } @@ -632,6 +642,14 @@ public class WindowManagerService extends IWindowManager.Stub } void notifyMoveLw(float x, float y) { + final int myPid = Process.myPid(); + + // Move the surface to the given touch + mSurface.openTransaction(); + mSurface.setPosition((int)(x - mThumbOffsetX), (int)(y - mThumbOffsetY)); + mSurface.closeTransaction(); + + // Tell the affected window WindowState touchedWin = getTouchedWinAtPointLw(x, y); try { // have we dragged over a new window? @@ -643,7 +661,9 @@ public class WindowManagerService extends IWindowManager.Stub DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_EXITED, 0, 0, null, null); mTargetWindow.mClient.dispatchDragEvent(evt); - evt.recycle(); + if (myPid != mTargetWindow.mSession.mPid) { + evt.recycle(); + } } if (touchedWin != null) { if (DEBUG_DRAG) { @@ -652,7 +672,9 @@ public class WindowManagerService extends IWindowManager.Stub DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_LOCATION, x, y, null, null); touchedWin.mClient.dispatchDragEvent(evt); - evt.recycle(); + if (myPid != touchedWin.mSession.mPid) { + evt.recycle(); + } } } catch (RemoteException e) { Slog.w(TAG, "can't send drag notification to windows"); @@ -667,13 +689,16 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_DRAG) { Slog.d(TAG, "sending DROP to " + touchedWin); } + final int myPid = Process.myPid(); DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DROP, x, y, null, mData); try { touchedWin.mClient.dispatchDragEvent(evt); } catch (RemoteException e) { Slog.w(TAG, "can't send drop notification to win " + touchedWin); } - evt.recycle(); + if (myPid != touchedWin.mSession.mPid) { + evt.recycle(); + } } } @@ -749,13 +774,7 @@ public class WindowManagerService extends IWindowManager.Stub case MotionEvent.ACTION_MOVE: { synchronized (mWindowMap) { - // move the surface to the latest touch point - mDragState.mSurface.openTransaction(); - mDragState.mSurface.setPosition((int)(newX - mDragState.mThumbOffsetX), - (int)(newY - mDragState.mThumbOffsetY)); - mDragState.mSurface.closeTransaction(); - - // tell the involved window(s) where we are + // move the surface and tell the involved window(s) where we are mDragState.notifyMoveLw(newX, newY); } } break; @@ -5403,7 +5422,6 @@ public class WindowManagerService extends IWindowManager.Stub mDragState.reset(); mDragState = null; } - } } } finally { @@ -5535,7 +5553,7 @@ public class WindowManagerService extends IWindowManager.Stub inputWindow.frameTop = 0; inputWindow.frameRight = mDisplay.getWidth(); inputWindow.frameBottom = mDisplay.getHeight(); - + inputWindow.visibleFrameLeft = inputWindow.frameLeft; inputWindow.visibleFrameTop = inputWindow.frameTop; inputWindow.visibleFrameRight = inputWindow.frameRight; @@ -6195,9 +6213,8 @@ public class WindowManagerService extends IWindowManager.Stub mH.removeMessages(H.DRAG_START_TIMEOUT, window.asBinder()); - // !!! TODO: call into the input monitor to sever the current touch event flow - // and redirect to the drag "window"; also extract the current touch (x, y) - // in screen coordinates + // !!! TODO: extract the current touch (x, y) in screen coordinates. That + // will let us eliminate the (touchX,touchY) parameters from the API. mDragState.register(); mInputMonitor.updateInputWindowsLw();