Merge "Fix bug #10205316 CTS (KLP): android.graphics tests are failing" into klp-dev
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 97ea99d..4d48fd4 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -17,10 +17,17 @@
 package android.os;
 
 import android.util.Log;
+import android.util.Slog;
+
+import libcore.io.ErrnoException;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+import libcore.io.OsConstants;
 
 import java.io.BufferedInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -58,9 +65,84 @@
     /** Regular expression for safe filenames: no spaces or metacharacters */
     private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+");
 
-    public static native int setPermissions(String file, int mode, int uid, int gid);
+    /**
+     * Set owner and mode of of given {@link File}.
+     *
+     * @param mode to apply through {@code chmod}
+     * @param uid to apply through {@code chown}, or -1 to leave unchanged
+     * @param gid to apply through {@code chown}, or -1 to leave unchanged
+     * @return 0 on success, otherwise errno.
+     */
+    public static int setPermissions(File path, int mode, int uid, int gid) {
+        return setPermissions(path.getAbsolutePath(), mode, uid, gid);
+    }
 
-    public static native int getUid(String file);
+    /**
+     * Set owner and mode of of given path.
+     *
+     * @param mode to apply through {@code chmod}
+     * @param uid to apply through {@code chown}, or -1 to leave unchanged
+     * @param gid to apply through {@code chown}, or -1 to leave unchanged
+     * @return 0 on success, otherwise errno.
+     */
+    public static int setPermissions(String path, int mode, int uid, int gid) {
+        try {
+            Libcore.os.chmod(path, mode);
+        } catch (ErrnoException e) {
+            Slog.w(TAG, "Failed to chmod(" + path + "): " + e);
+            return e.errno;
+        }
+
+        if (uid >= 0 || gid >= 0) {
+            try {
+                Libcore.os.chown(path, uid, gid);
+            } catch (ErrnoException e) {
+                Slog.w(TAG, "Failed to chown(" + path + "): " + e);
+                return e.errno;
+            }
+        }
+
+        return 0;
+    }
+
+    /**
+     * Set owner and mode of of given {@link FileDescriptor}.
+     *
+     * @param mode to apply through {@code chmod}
+     * @param uid to apply through {@code chown}, or -1 to leave unchanged
+     * @param gid to apply through {@code chown}, or -1 to leave unchanged
+     * @return 0 on success, otherwise errno.
+     */
+    public static int setPermissions(FileDescriptor fd, int mode, int uid, int gid) {
+        try {
+            Libcore.os.fchmod(fd, mode);
+        } catch (ErrnoException e) {
+            Slog.w(TAG, "Failed to fchmod(): " + e);
+            return e.errno;
+        }
+
+        if (uid >= 0 || gid >= 0) {
+            try {
+                Libcore.os.fchown(fd, uid, gid);
+            } catch (ErrnoException e) {
+                Slog.w(TAG, "Failed to fchown(): " + e);
+                return e.errno;
+            }
+        }
+
+        return 0;
+    }
+
+    /**
+     * Return owning UID of given path, otherwise -1.
+     */
+    public static int getUid(String path) {
+        try {
+            return Libcore.os.stat(path).st_uid;
+        } catch (ErrnoException e) {
+            return -1;
+        }
+    }
 
     /** returns the FAT file system volume ID for the volume mounted 
      * at the given mount point, or -1 for failure
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index ab0543d..cf9ddb3 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -100,12 +100,6 @@
     public static final int DRM_UID = 1019;
 
     /**
-     * Defines the GID for the group that allows write access to the SD card.
-     * @hide
-     */
-    public static final int SDCARD_RW_GID = 1015;
-
-    /**
      * Defines the UID/GID for the group that controls VPN services.
      * @hide
      */
@@ -130,11 +124,18 @@
     public static final int MEDIA_RW_GID = 1023;
 
     /**
+     * Access to installed package details
+     * @hide
+     */
+    public static final int PACKAGE_INFO_GID = 1032;
+
+    /**
      * Defines the start of a range of UIDs (and GIDs), going from this
      * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
      * to applications.
      */
     public static final int FIRST_APPLICATION_UID = 10000;
+
     /**
      * Last of application-specific UIDs starting at
      * {@link #FIRST_APPLICATION_UID}.
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index ccc0089..04351da 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -499,7 +499,7 @@
         String args[] = {
             "--setuid=1000",
             "--setgid=1000",
-            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007",
+            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
             "--capabilities=" + capabilities + "," + capabilities,
             "--runtime-init",
             "--nice-name=system_server",
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 3308064..6c4526e 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -35,8 +35,6 @@
 
 #include <utils/Log.h>
 
-#define TIME_DRAWx
-
 static uint32_t get_thread_msec() {
 #if defined(HAVE_POSIX_CLOCKS)
     struct timespec tm;
@@ -463,20 +461,6 @@
         canvas->drawPath(*path, *paint);
     }
  
-    static void drawPicture(JNIEnv* env, jobject, SkCanvas* canvas,
-                            SkPicture* picture) {
-        SkASSERT(canvas);
-        SkASSERT(picture);
-        
-#ifdef TIME_DRAW
-        SkMSec now = get_thread_msec(); //SkTime::GetMSecs();
-#endif
-        canvas->drawPicture(*picture);
-#ifdef TIME_DRAW
-        ALOGD("---- picture playback %d ms\n", get_thread_msec() - now);
-#endif
-    }
-
     static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas,
                                           SkCanvas* canvas, SkBitmap* bitmap,
                                           jfloat left, jfloat top,
@@ -1103,7 +1087,6 @@
         (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
     {"native_drawTextOnPath","(ILjava/lang/String;IFFII)V",
         (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
-    {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture},
 
     {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches},
 
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 2c482ea..bacfdf6 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -18,6 +18,9 @@
 
 #include <stdio.h>
 
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
 #include <gui/GLConsumer.h>
 #include <gui/Surface.h>
 
diff --git a/core/jni/android_os_FileUtils.cpp b/core/jni/android_os_FileUtils.cpp
index 0aaa2b1..d1245da 100644
--- a/core/jni/android_os_FileUtils.cpp
+++ b/core/jni/android_os_FileUtils.cpp
@@ -33,46 +33,6 @@
 
 namespace android {
 
-jint android_os_FileUtils_setPermissions(JNIEnv* env, jobject clazz,
-                                         jstring file, jint mode,
-                                         jint uid, jint gid)
-{
-    const jchar* str = env->GetStringCritical(file, 0);
-    String8 file8;
-    if (str) {
-        file8 = String8(str, env->GetStringLength(file));
-        env->ReleaseStringCritical(file, str);
-    }
-    if (file8.size() <= 0) {
-        return ENOENT;
-    }
-    if (uid >= 0 || gid >= 0) {
-        int res = chown(file8.string(), uid, gid);
-        if (res != 0) {
-            return errno;
-        }
-    }
-    return chmod(file8.string(), mode) == 0 ? 0 : errno;
-}
-
-jint android_os_FileUtils_getUid(JNIEnv* env, jobject clazz, jstring file)
-{
-    struct stat stats;
-    const jchar* str = env->GetStringCritical(file, 0);
-    String8 file8;
-    if (str) {
-        file8 = String8(str, env->GetStringLength(file));
-        env->ReleaseStringCritical(file, str);
-    }
-    if (file8.size() <= 0) {
-        return ENOENT;
-    }
-    if (stat(file8.string(), &stats) < 0) {
-        return -1;
-    }
-    return stats.st_uid;
-}
-
 jint android_os_FileUtils_getFatVolumeId(JNIEnv* env, jobject clazz, jstring path)
 {
     if (path == NULL) {
@@ -95,8 +55,6 @@
 }
 
 static const JNINativeMethod methods[] = {
-    {"setPermissions",  "(Ljava/lang/String;III)I", (void*)android_os_FileUtils_setPermissions},
-    {"getUid",          "(Ljava/lang/String;)I", (void*)android_os_FileUtils_getUid},
     {"getFatVolumeId",  "(Ljava/lang/String;)I", (void*)android_os_FileUtils_getFatVolumeId},
 };
 
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index fdec22b..0ea4074 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -114,9 +114,13 @@
      * canvas.
      */
     public Canvas() {
-        // 0 means no native bitmap
-        mNativeCanvas = initRaster(0);
-        mFinalizer = new CanvasFinalizer(mNativeCanvas);
+        if (!isHardwareAccelerated()) {
+            // 0 means no native bitmap
+            mNativeCanvas = initRaster(0);
+            mFinalizer = new CanvasFinalizer(mNativeCanvas);
+        } else {
+            mFinalizer = null;
+        }
     }
 
     /**
@@ -1646,7 +1650,9 @@
      */
     public void drawPicture(Picture picture) {
         picture.endRecording();
-        native_drawPicture(mNativeCanvas, picture.ni());
+        int restoreCount = save();
+        picture.draw(this);
+        restoreToCount(restoreCount);
     }
     
     /**
@@ -1831,7 +1837,5 @@
                                                      float hOffset, 
                                                      float vOffset, 
                                                      int flags, int paint);
-    private static native void native_drawPicture(int nativeCanvas,
-                                                  int nativePicture);
     private static native void finalizer(int nativeCanvas);
 }
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index d1bae1e..707f662 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1112,8 +1112,6 @@
     setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
 
     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
-
-    finishDrawTexture();
 }
 
 void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
@@ -1256,8 +1254,6 @@
                             GL_UNSIGNED_SHORT, NULL));
         }
 
-        finishDrawTexture();
-
 #if DEBUG_LAYERS_AS_REGIONS
         drawRegionRects(layer->region);
 #endif
@@ -2021,9 +2017,6 @@
     mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
 }
 
-void OpenGLRenderer::finishDrawTexture() {
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Drawing
 ///////////////////////////////////////////////////////////////////////////////
@@ -2308,8 +2301,6 @@
 
     glDrawArrays(GL_TRIANGLES, 0, count);
 
-    finishDrawTexture();
-
     int slot = mCaches.currentProgram->getAttrib("colors");
     if (slot >= 0) {
         glDisableVertexAttribArray(slot);
@@ -3134,8 +3125,6 @@
                 mesh += (drawCount / 6) * 4;
             }
 
-            finishDrawTexture();
-
 #if DEBUG_LAYERS_AS_REGIONS
             drawRegionRects(layer->region);
 #endif
@@ -3270,8 +3259,6 @@
     setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
 
     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
-
-    finishDrawTexture();
 }
 
 // Same values used by Skia
@@ -3488,8 +3475,6 @@
     setupDrawMesh(vertices, texCoords, vbo);
 
     glDrawArrays(drawMode, 0, elementsCount);
-
-    finishDrawTexture();
 }
 
 void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom,
@@ -3515,8 +3500,6 @@
     setupDrawMeshIndices(vertices, texCoords, vbo);
 
     glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, NULL);
-
-    finishDrawTexture();
 }
 
 void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
@@ -3546,8 +3529,6 @@
     setupDrawMesh(vertices, texCoords);
 
     glDrawArrays(drawMode, 0, elementsCount);
-
-    finishDrawTexture();
 }
 
 void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 2f8a2f0..1c3bfdc 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -1003,7 +1003,6 @@
     void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLvoid* colors);
     void setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords, GLuint vbo = 0);
     void setupDrawIndexedVertices(GLvoid* vertices);
-    void finishDrawTexture();
     void accountForClear(SkXfermode::Mode mode);
 
     bool updateLayer(Layer* layer, bool inFrame);
diff --git a/media/mca/filterfw/native/core/gl_env.cpp b/media/mca/filterfw/native/core/gl_env.cpp
index fdecda3..84dad8c 100644
--- a/media/mca/filterfw/native/core/gl_env.cpp
+++ b/media/mca/filterfw/native/core/gl_env.cpp
@@ -26,6 +26,8 @@
 #include <string>
 #include <EGL/eglext.h>
 
+#include <gui/GLConsumer.h>
+
 namespace android {
 namespace filterfw {
 
diff --git a/media/mca/filterfw/native/core/gl_env.h b/media/mca/filterfw/native/core/gl_env.h
index 81e1e9d..a709638 100644
--- a/media/mca/filterfw/native/core/gl_env.h
+++ b/media/mca/filterfw/native/core/gl_env.h
@@ -31,6 +31,9 @@
 #include <gui/Surface.h>
 
 namespace android {
+
+class GLConsumer;
+
 namespace filterfw {
 
 class ShaderProgram;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 8e7e087..a536acb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -72,7 +72,7 @@
     private final DisplayState mDisplayState = new DisplayState();
 
     /** Current user navigation stack; empty implies recents. */
-    private DocumentStack mStack;
+    private DocumentStack mStack = new DocumentStack();
     /** Currently active search, overriding any stack. */
     private String mCurrentSearch;
 
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index 18b46fb..8fb3998 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -41,6 +41,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * This class is a strategy for performing touch exploration. It
@@ -52,10 +53,8 @@
  *   <li>2. One finger moving fast around performs gestures.</li>
  *   <li>3. Two close fingers moving in the same direction perform a drag.</li>
  *   <li>4. Multi-finger gestures are delivered to view hierarchy.</li>
- *   <li>5. Pointers that have not moved more than a specified distance after they
- *          went down are considered inactive.</li>
- *   <li>6. Two fingers moving in different directions are considered a multi-finger gesture.</li>
- *   <li>7. Double tapping clicks on the on the last touch explored location of it was in
+ *   <li>5. Two fingers moving in different directions are considered a multi-finger gesture.</li>
+ *   <li>7. Double tapping clicks on the on the last touch explored location if it was in
  *          a window that does not take focus, otherwise the click is within the accessibility
  *          focused rectangle.</li>
  *   <li>7. Tapping and holding for a while performs a long press in a similar fashion
@@ -102,9 +101,6 @@
     // The timeout after which we are no longer trying to detect a gesture.
     private static final int EXIT_GESTURE_DETECTION_TIMEOUT = 2000;
 
-    // Temporary array for storing pointer IDs.
-    private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT];
-
     // Timeout before trying to decide what the user is trying to do.
     private final int mDetermineUserIntentTimeout;
 
@@ -129,11 +125,11 @@
     // Handler for performing asynchronous operations.
     private final Handler mHandler;
 
-    // Command for delayed sending of a hover enter event.
-    private final SendHoverDelayed mSendHoverEnterDelayed;
+    // Command for delayed sending of a hover enter and move event.
+    private final SendHoverEnterAndMoveDelayed mSendHoverEnterAndMoveDelayed;
 
     // Command for delayed sending of a hover exit event.
-    private final SendHoverDelayed mSendHoverExitDelayed;
+    private final SendHoverExitDelayed mSendHoverExitDelayed;
 
     // Command for delayed sending of touch exploration end events.
     private final SendAccessibilityEventDelayed mSendTouchExplorationEndDelayed;
@@ -220,7 +216,7 @@
     public TouchExplorer(Context context, AccessibilityManagerService service) {
         mContext = context;
         mAms = service;
-        mReceivedPointerTracker = new ReceivedPointerTracker(context);
+        mReceivedPointerTracker = new ReceivedPointerTracker();
         mInjectedPointerTracker = new InjectedPointerTracker();
         mTapTimeout = ViewConfiguration.getTapTimeout();
         mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout();
@@ -234,8 +230,8 @@
         mGestureLibrary.setOrientationStyle(8);
         mGestureLibrary.setSequenceType(GestureStore.SEQUENCE_SENSITIVE);
         mGestureLibrary.load();
-        mSendHoverEnterDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_ENTER, true);
-        mSendHoverExitDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_EXIT, false);
+        mSendHoverEnterAndMoveDelayed = new SendHoverEnterAndMoveDelayed();
+        mSendHoverExitDelayed = new SendHoverExitDelayed();
         mSendTouchExplorationEndDelayed = new SendAccessibilityEventDelayed(
                 AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END,
                 mDetermineUserIntentTimeout);
@@ -283,12 +279,12 @@
             } break;
         }
         // Remove all pending callbacks.
-        mSendHoverEnterDelayed.remove();
-        mSendHoverExitDelayed.remove();
-        mPerformLongPressDelayed.remove();
-        mExitGestureDetectionModeDelayed.remove();
-        mSendTouchExplorationEndDelayed.remove();
-        mSendTouchInteractionEndDelayed.remove();
+        mSendHoverEnterAndMoveDelayed.cancel();
+        mSendHoverExitDelayed.cancel();
+        mPerformLongPressDelayed.cancel();
+        mExitGestureDetectionModeDelayed.cancel();
+        mSendTouchExplorationEndDelayed.cancel();
+        mSendTouchInteractionEndDelayed.cancel();
         // Reset the pointer trackers.
         mReceivedPointerTracker.clear();
         mInjectedPointerTracker.clear();
@@ -347,7 +343,7 @@
         // last hover exit event.
         if (mSendTouchExplorationEndDelayed.isPending()
                 && eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
-                    mSendTouchExplorationEndDelayed.remove();
+                    mSendTouchExplorationEndDelayed.cancel();
             sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END);
         }
 
@@ -355,7 +351,7 @@
         // last hover exit and the touch exploration gesture end events.
         if (mSendTouchInteractionEndDelayed.isPending()
                 && eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
-            mSendTouchInteractionEndDelayed.remove();
+            mSendTouchInteractionEndDelayed.cancel();
             sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
         }
 
@@ -390,95 +386,80 @@
     private void handleMotionEventStateTouchExploring(MotionEvent event, MotionEvent rawEvent,
             int policyFlags) {
         ReceivedPointerTracker receivedTracker = mReceivedPointerTracker;
-        final int activePointerCount = receivedTracker.getActivePointerCount();
 
         mVelocityTracker.addMovement(rawEvent);
 
         mDoubleTapDetector.onMotionEvent(event, policyFlags);
 
         switch (event.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN:
+            case MotionEvent.ACTION_DOWN: {
                 mAms.onTouchInteractionStart();
+
                 // Pre-feed the motion events to the gesture detector since we
                 // have a distance slop before getting into gesture detection
                 // mode and not using the points within this slop significantly
                 // decreases the quality of gesture recognition.
                 handleMotionEventGestureDetecting(rawEvent, policyFlags);
-                //$FALL-THROUGH$
-            case MotionEvent.ACTION_POINTER_DOWN: {
-                switch (activePointerCount) {
-                    case 0: {
-                        throw new IllegalStateException("The must always be one active pointer in"
-                                + "touch exploring state!");
-                    }
-                    case 1: {
-                        // If we still have not notified the user for the last
-                        // touch, we figure out what to do. If were waiting
-                        // we resent the delayed callback and wait again.
-                        if (mSendHoverEnterDelayed.isPending()) {
-                            mSendHoverEnterDelayed.remove();
-                            mSendHoverExitDelayed.remove();
-                        }
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
 
-                        if (mSendTouchExplorationEndDelayed.isPending()) {
-                            mSendTouchExplorationEndDelayed.forceSendAndRemove();
-                        }
+                // If we still have not notified the user for the last
+                // touch, we figure out what to do. If were waiting
+                // we resent the delayed callback and wait again.
+                mSendHoverEnterAndMoveDelayed.cancel();
+                mSendHoverExitDelayed.cancel();
+                mPerformLongPressDelayed.cancel();
 
-                        if (mSendTouchInteractionEndDelayed.isPending()) {
-                            mSendTouchInteractionEndDelayed.forceSendAndRemove();
-                        }
+                if (mSendTouchExplorationEndDelayed.isPending()) {
+                    mSendTouchExplorationEndDelayed.forceSendAndRemove();
+                }
 
-                        // Every pointer that goes down is active until it moves or
-                        // another one goes down. Hence, having more than one pointer
-                        // down we have already send the interaction start event.
-                        if (event.getPointerCount() == 1) {
-                            sendAccessibilityEvent(
-                                    AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
-                        }
+                if (mSendTouchInteractionEndDelayed.isPending()) {
+                    mSendTouchInteractionEndDelayed.forceSendAndRemove();
+                }
 
-                        mPerformLongPressDelayed.remove();
+                // Cache the event until we discern exploration from gesturing.
+                mSendHoverEnterAndMoveDelayed.addEvent(event);
 
-                        // If we have the first tap schedule a long press and break
-                        // since we do not want to schedule hover enter because
-                        // the delayed callback will kick in before the long click.
-                        // This would lead to a state transition resulting in long
-                        // pressing the item below the double taped area which is
-                        // not necessary where accessibility focus is.
-                        if (mDoubleTapDetector.firstTapDetected()) {
-                            // We got a tap now post a long press action.
-                            mPerformLongPressDelayed.post(event, policyFlags);
-                            break;
-                        }
-                        if (!mTouchExplorationInProgress) {
-                            // Deliver hover enter with a delay to have a chance
-                            // to detect what the user is trying to do.
-                            final int pointerId = receivedTracker.getPrimaryActivePointerId();
-                            final int pointerIdBits = (1 << pointerId);
-                            mSendHoverEnterDelayed.post(event, true, pointerIdBits, policyFlags);
-                        }
-                    } break;
-                    default: {
-                        /* do nothing - let the code for ACTION_MOVE decide what to do */
-                    } break;
+                // If we have the first tap, schedule a long press and break
+                // since we do not want to schedule hover enter because
+                // the delayed callback will kick in before the long click.
+                // This would lead to a state transition resulting in long
+                // pressing the item below the double taped area which is
+                // not necessary where accessibility focus is.
+                if (mDoubleTapDetector.firstTapDetected()) {
+                    // We got a tap now post a long press action.
+                    mPerformLongPressDelayed.post(event, policyFlags);
+                    break;
+                }
+                if (!mTouchExplorationInProgress) {
+                    // Deliver hover enter with a delay to have a chance
+                    // to detect what the user is trying to do.
+                    final int pointerId = receivedTracker.getPrimaryPointerId();
+                    final int pointerIdBits = (1 << pointerId);
+                    mSendHoverEnterAndMoveDelayed.post(event, true, pointerIdBits, policyFlags);
                 }
             } break;
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                /* do nothing - let the code for ACTION_MOVE decide what to do */
+            } break;
             case MotionEvent.ACTION_MOVE: {
-                final int pointerId = receivedTracker.getPrimaryActivePointerId();
+                final int pointerId = receivedTracker.getPrimaryPointerId();
                 final int pointerIndex = event.findPointerIndex(pointerId);
                 final int pointerIdBits = (1 << pointerId);
-                switch (activePointerCount) {
-                    case 0: {
-                        /* do nothing - no active pointers so we swallow the event */
-                    } break;
+                switch (event.getPointerCount()) {
                     case 1: {
                         // We have not started sending events since we try to
                         // figure out what the user is doing.
-                        if (mSendHoverEnterDelayed.isPending()) {
+                        if (mSendHoverEnterAndMoveDelayed.isPending()) {
                             // Pre-feed the motion events to the gesture detector since we
                             // have a distance slop before getting into gesture detection
                             // mode and not using the points within this slop significantly
                             // decreases the quality of gesture recognition.
                             handleMotionEventGestureDetecting(rawEvent, policyFlags);
+
+                            // Cache the event until we discern exploration from gesturing.
+                            mSendHoverEnterAndMoveDelayed.addEvent(event);
+
                             // It is *important* to use the distance traveled by the pointers
                             // on the screen which may or may not be magnified.
                             final float deltaX = receivedTracker.getReceivedPointerDownX(pointerId)
@@ -500,9 +481,9 @@
                                     // clear the current state and try to detect.
                                     mCurrentState = STATE_GESTURE_DETECTING;
                                     mVelocityTracker.clear();
-                                    mSendHoverEnterDelayed.remove();
-                                    mSendHoverExitDelayed.remove();
-                                    mPerformLongPressDelayed.remove();
+                                    mSendHoverEnterAndMoveDelayed.cancel();
+                                    mSendHoverExitDelayed.cancel();
+                                    mPerformLongPressDelayed.cancel();
                                     mExitGestureDetectionModeDelayed.post();
                                     // Send accessibility event to announce the start
                                     // of gesture recognition.
@@ -511,9 +492,9 @@
                                 } else {
                                     // We have just decided that the user is touch,
                                     // exploring so start sending events.
-                                    mSendHoverEnterDelayed.forceSendAndRemove();
-                                    mSendHoverExitDelayed.remove();
-                                    mPerformLongPressDelayed.remove();
+                                    mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
+                                    mSendHoverExitDelayed.cancel();
+                                    mPerformLongPressDelayed.cancel();
                                     sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE,
                                             pointerIdBits, policyFlags);
                                 }
@@ -532,11 +513,11 @@
                                 final double moveDelta = Math.hypot(deltaX, deltaY);
                                 // The user has moved enough for us to decide.
                                 if (moveDelta > mTouchSlop) {
-                                    mPerformLongPressDelayed.remove();
+                                    mPerformLongPressDelayed.cancel();
                                 }
                             }
-                            // The user is wither double tapping or performing long
-                            // press so do not send move events yet.
+                            // The user is either double tapping or performing a long
+                            // press, so do not send move events yet.
                             if (mDoubleTapDetector.firstTapDetected()) {
                                 break;
                             }
@@ -548,14 +529,14 @@
                     case 2: {
                         // More than one pointer so the user is not touch exploring
                         // and now we have to decide whether to delegate or drag.
-                        if (mSendHoverEnterDelayed.isPending()) {
+                        if (mSendHoverEnterAndMoveDelayed.isPending()) {
                             // We have not started sending events so cancel
                             // scheduled sending events.
-                            mSendHoverEnterDelayed.remove();
-                            mSendHoverExitDelayed.remove();
-                            mPerformLongPressDelayed.remove();
+                            mSendHoverEnterAndMoveDelayed.cancel();
+                            mSendHoverExitDelayed.cancel();
+                            mPerformLongPressDelayed.cancel();
                         } else {
-                            mPerformLongPressDelayed.remove();
+                            mPerformLongPressDelayed.cancel();
                             // If the user is touch exploring the second pointer may be
                             // performing a double tap to activate an item without need
                             // for the user to lift his exploring finger.
@@ -590,21 +571,21 @@
                         } else {
                             // Two pointers moving arbitrary are delegated to the view hierarchy.
                             mCurrentState = STATE_DELEGATING;
-                            sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+                            sendDownForAllNotInjectedPointers(event, policyFlags);
                         }
                         mVelocityTracker.clear();
                     } break;
                     default: {
                         // More than one pointer so the user is not touch exploring
                         // and now we have to decide whether to delegate or drag.
-                        if (mSendHoverEnterDelayed.isPending()) {
+                        if (mSendHoverEnterAndMoveDelayed.isPending()) {
                             // We have not started sending events so cancel
                             // scheduled sending events.
-                            mSendHoverEnterDelayed.remove();
-                            mSendHoverExitDelayed.remove();
-                            mPerformLongPressDelayed.remove();
+                            mSendHoverEnterAndMoveDelayed.cancel();
+                            mSendHoverExitDelayed.cancel();
+                            mPerformLongPressDelayed.cancel();
                         } else {
-                            mPerformLongPressDelayed.remove();
+                            mPerformLongPressDelayed.cancel();
                             // We are sending events so send exit and gesture
                             // end since we transition to another state.
                             sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
@@ -612,43 +593,34 @@
 
                         // More than two pointers are delegated to the view hierarchy.
                         mCurrentState = STATE_DELEGATING;
-                        sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+                        sendDownForAllNotInjectedPointers(event, policyFlags);
                         mVelocityTracker.clear();
                     }
                 }
             } break;
-            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_UP: {
                 mAms.onTouchInteractionEnd();
                 // We know that we do not need the pre-fed gesture points are not
                 // needed anymore since the last pointer just went up.
                 mStrokeBuffer.clear();
-                //$FALL-THROUGH$
-            case MotionEvent.ACTION_POINTER_UP: {
-                final int pointerId = receivedTracker.getLastReceivedUpPointerId();
+                final int pointerId = event.getPointerId(event.getActionIndex());
                 final int pointerIdBits = (1 << pointerId);
-                switch (activePointerCount) {
-                    case 0: {
-                        // If the pointer that went up was not active we have nothing to do.
-                        if (!receivedTracker.wasLastReceivedUpPointerActive()) {
-                            break;
-                        }
 
-                        mPerformLongPressDelayed.remove();
-
-                        // If we have not delivered the enter schedule exit.
-                        if (mSendHoverEnterDelayed.isPending()) {
-                            mSendHoverExitDelayed.post(event, false, pointerIdBits, policyFlags);
-                        } else {
-                            // The user is touch exploring so we send events for end.
-                            sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
-                        }
-
-                        if (!mSendTouchInteractionEndDelayed.isPending()) {
-                            mSendTouchInteractionEndDelayed.post();
-                        }
-                    } break;
-                }
+                mPerformLongPressDelayed.cancel();
                 mVelocityTracker.clear();
+
+                if (mSendHoverEnterAndMoveDelayed.isPending()) {
+                    // If we have not delivered the enter schedule an exit.
+                    mSendHoverExitDelayed.post(event, pointerIdBits, policyFlags);
+                } else {
+                    // The user is touch exploring so we send events for end.
+                    sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
+                }
+
+                if (!mSendTouchInteractionEndDelayed.isPending()) {
+                    mSendTouchInteractionEndDelayed.post();
+                }
+
             } break;
             case MotionEvent.ACTION_CANCEL: {
                 clear(event, policyFlags);
@@ -676,29 +648,19 @@
                 if (mDraggingPointerId != INVALID_POINTER_ID) {
                     sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
                 }
-                sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+                sendDownForAllNotInjectedPointers(event, policyFlags);
             } break;
             case MotionEvent.ACTION_MOVE: {
-                final int activePointerCount = mReceivedPointerTracker.getActivePointerCount();
-                switch (activePointerCount) {
+                switch (event.getPointerCount()) {
                     case 1: {
                         // do nothing
                     } break;
                     case 2: {
                         if (isDraggingGesture(event)) {
-                            // If the dragging pointer are closer that a given distance we
-                            // use the location of the primary one. Otherwise, we take the
-                            // middle between the pointers.
-                            int[] pointerIds = mTempPointerIds;
-                            mReceivedPointerTracker.populateActivePointerIds(pointerIds);
-
-                            final int firstPtrIndex = event.findPointerIndex(pointerIds[0]);
-                            final int secondPtrIndex = event.findPointerIndex(pointerIds[1]);
-
-                            final float firstPtrX = event.getX(firstPtrIndex);
-                            final float firstPtrY = event.getY(firstPtrIndex);
-                            final float secondPtrX = event.getX(secondPtrIndex);
-                            final float secondPtrY = event.getY(secondPtrIndex);
+                            final float firstPtrX = event.getX(0);
+                            final float firstPtrY = event.getY(0);
+                            final float secondPtrX = event.getX(1);
+                            final float secondPtrY = event.getY(1);
 
                             final float deltaX = firstPtrX - secondPtrX;
                             final float deltaY = firstPtrY - secondPtrY;
@@ -718,8 +680,8 @@
                             // Send an event to the end of the drag gesture.
                             sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits,
                                     policyFlags);
-                            // Deliver all active pointers to the view hierarchy.
-                            sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+                            // Deliver all pointers to the view hierarchy.
+                            sendDownForAllNotInjectedPointers(event, policyFlags);
                         }
                     } break;
                     default: {
@@ -727,8 +689,8 @@
                         // Send an event to the end of the drag gesture.
                         sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits,
                                 policyFlags);
-                        // Deliver all active pointers to the view hierarchy.
-                        sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+                        // Deliver all pointers to the view hierarchy.
+                        sendDownForAllNotInjectedPointers(event, policyFlags);
                     }
                 }
             } break;
@@ -771,37 +733,21 @@
                 throw new IllegalStateException("Delegating state can only be reached if "
                         + "there is at least one pointer down!");
             }
-            case MotionEvent.ACTION_MOVE: {
-                // Check  whether some other pointer became active because they have moved
-                // a given distance and if such exist send them to the view hierarchy
-                final int notInjectedCount = getNotInjectedActivePointerCount(
-                        mReceivedPointerTracker, mInjectedPointerTracker);
-                if (notInjectedCount > 0) {
-                    MotionEvent prototype = MotionEvent.obtain(event);
-                    sendDownForAllActiveNotInjectedPointers(prototype, policyFlags);
-                }
-            } break;
-            case MotionEvent.ACTION_UP:
-                // Announce the end of a new touch interaction.
-                sendAccessibilityEvent(
-                        AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
-                //$FALL-THROUGH$
-            case MotionEvent.ACTION_POINTER_UP: {
+            case MotionEvent.ACTION_UP: {
+                // Announce the end of a the touch interaction.
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
                 mAms.onTouchInteractionEnd();
                 mLongPressingPointerId = -1;
                 mLongPressingPointerDeltaX = 0;
                 mLongPressingPointerDeltaY = 0;
-                // No active pointers => go to initial state.
-                if (mReceivedPointerTracker.getActivePointerCount() == 0) {
-                    mCurrentState = STATE_TOUCH_EXPLORING;
-                }
+                mCurrentState = STATE_TOUCH_EXPLORING;
             } break;
             case MotionEvent.ACTION_CANCEL: {
                 clear(event, policyFlags);
             } break;
         }
-        // Deliver the event striping out inactive pointers.
-        sendMotionEventStripInactivePointers(event, policyFlags);
+        // Deliver the event.
+        sendMotionEvent(event, event.getAction(), ALL_POINTER_ID_BITS, policyFlags);
     }
 
     private void handleMotionEventGestureDetecting(MotionEvent event, int policyFlags) {
@@ -826,12 +772,10 @@
             } break;
             case MotionEvent.ACTION_UP: {
                 mAms.onTouchInteractionEnd();
-                // Announce the end of gesture recognition.
-                sendAccessibilityEvent(
-                        AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
-                // Announce the end of a new touch interaction.
-                sendAccessibilityEvent(
-                        AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
+                // Announce the end of the gesture recognition.
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
+                // Announce the end of a the touch interaction.
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
 
                 float x = event.getX();
                 float y = event.getY();
@@ -858,7 +802,7 @@
                 }
 
                 mStrokeBuffer.clear();
-                mExitGestureDetectionModeDelayed.remove();
+                mExitGestureDetectionModeDelayed.cancel();
                 mCurrentState = STATE_TOUCH_EXPLORING;
             } break;
             case MotionEvent.ACTION_CANCEL: {
@@ -889,40 +833,26 @@
     }
 
     /**
-     * Sends down events to the view hierarchy for all active pointers which are
+     * Sends down events to the view hierarchy for all pointers which are
      * not already being delivered i.e. pointers that are not yet injected.
      *
      * @param prototype The prototype from which to create the injected events.
      * @param policyFlags The policy flags associated with the event.
      */
-    private void sendDownForAllActiveNotInjectedPointers(MotionEvent prototype, int policyFlags) {
-        ReceivedPointerTracker receivedPointers = mReceivedPointerTracker;
+    private void sendDownForAllNotInjectedPointers(MotionEvent prototype, int policyFlags) {
         InjectedPointerTracker injectedPointers = mInjectedPointerTracker;
+
+        // Inject the injected pointers.
         int pointerIdBits = 0;
         final int pointerCount = prototype.getPointerCount();
-
-        // Find which pointers are already injected.
         for (int i = 0; i < pointerCount; i++) {
             final int pointerId = prototype.getPointerId(i);
-            if (injectedPointers.isInjectedPointerDown(pointerId)) {
-                pointerIdBits |= (1 << pointerId);
-            }
-        }
-
-        // Inject the active and not injected pointers.
-        for (int i = 0; i < pointerCount; i++) {
-            final int pointerId = prototype.getPointerId(i);
-            // Skip inactive pointers.
-            if (!receivedPointers.isActivePointer(pointerId)) {
-                continue;
-            }
             // Do not send event for already delivered pointers.
-            if (injectedPointers.isInjectedPointerDown(pointerId)) {
-                continue;
+            if (!injectedPointers.isInjectedPointerDown(pointerId)) {
+                pointerIdBits |= (1 << pointerId);
+                final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i);
+                sendMotionEvent(prototype, action, pointerIdBits, policyFlags);
             }
-            pointerIdBits |= (1 << pointerId);
-            final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i);
-            sendMotionEvent(prototype, action, pointerIdBits, policyFlags);
         }
     }
 
@@ -959,7 +889,7 @@
     }
 
     /**
-     * Sends up events to the view hierarchy for all active pointers which are
+     * Sends up events to the view hierarchy for all pointers which are
      * already being delivered i.e. pointers that are injected.
      *
      * @param prototype The prototype from which to create the injected events.
@@ -982,58 +912,13 @@
     }
 
     /**
-     * Sends a motion event by first stripping the inactive pointers.
-     *
-     * @param prototype The prototype from which to create the injected event.
-     * @param policyFlags The policy flags associated with the event.
-     */
-    private void sendMotionEventStripInactivePointers(MotionEvent prototype, int policyFlags) {
-        ReceivedPointerTracker receivedTracker = mReceivedPointerTracker;
-
-        // All pointers active therefore we just inject the event as is.
-        if (prototype.getPointerCount() == receivedTracker.getActivePointerCount()) {
-            sendMotionEvent(prototype, prototype.getAction(), ALL_POINTER_ID_BITS, policyFlags);
-            return;
-        }
-
-        // No active pointers and the one that just went up was not
-        // active, therefore we have nothing to do.
-        if (receivedTracker.getActivePointerCount() == 0
-                && !receivedTracker.wasLastReceivedUpPointerActive()) {
-            return;
-        }
-
-        // If the action pointer going up/down is not active we have nothing to do.
-        // However, for moves we keep going to report moves of active pointers.
-        final int actionMasked = prototype.getActionMasked();
-        final int actionPointerId = prototype.getPointerId(prototype.getActionIndex());
-        if (actionMasked != MotionEvent.ACTION_MOVE) {
-            if (!receivedTracker.isActiveOrWasLastActiveUpPointer(actionPointerId)) {
-                return;
-            }
-        }
-
-        // If the pointer is active or the pointer that just went up
-        // was active we keep the pointer data in the event.
-        int pointerIdBits = 0;
-        final int pointerCount = prototype.getPointerCount();
-        for (int pointerIndex = 0; pointerIndex < pointerCount; pointerIndex++) {
-            final int pointerId = prototype.getPointerId(pointerIndex);
-            if (receivedTracker.isActiveOrWasLastActiveUpPointer(pointerId)) {
-                pointerIdBits |= (1 << pointerId);
-            }
-        }
-        sendMotionEvent(prototype, prototype.getAction(), pointerIdBits, policyFlags);
-    }
-
-    /**
      * Sends an up and down events.
      *
      * @param prototype The prototype from which to create the injected events.
      * @param policyFlags The policy flags associated with the event.
      */
     private void sendActionDownAndUp(MotionEvent prototype, int policyFlags) {
-        // Tap with the pointer that last explored - we may have inactive pointers.
+        // Tap with the pointer that last explored.
         final int pointerId = prototype.getPointerId(prototype.getActionIndex());
         final int pointerIdBits = (1 << pointerId);
         sendMotionEvent(prototype, MotionEvent.ACTION_DOWN, pointerIdBits, policyFlags);
@@ -1215,9 +1100,9 @@
             }
 
             // Remove pending event deliveries.
-            mSendHoverEnterDelayed.remove();
-            mSendHoverExitDelayed.remove();
-            mPerformLongPressDelayed.remove();
+            mSendHoverEnterAndMoveDelayed.cancel();
+            mSendHoverExitDelayed.cancel();
+            mPerformLongPressDelayed.cancel();
 
             if (mSendTouchExplorationEndDelayed.isPending()) {
                 mSendTouchExplorationEndDelayed.forceSendAndRemove();
@@ -1307,21 +1192,16 @@
      */
     private boolean isDraggingGesture(MotionEvent event) {
         ReceivedPointerTracker receivedTracker = mReceivedPointerTracker;
-        int[] pointerIds = mTempPointerIds;
-        receivedTracker.populateActivePointerIds(pointerIds);
 
-        final int firstPtrIndex = event.findPointerIndex(pointerIds[0]);
-        final int secondPtrIndex = event.findPointerIndex(pointerIds[1]);
+        final float firstPtrX = event.getX(0);
+        final float firstPtrY = event.getY(0);
+        final float secondPtrX = event.getX(1);
+        final float secondPtrY = event.getY(1);
 
-        final float firstPtrX = event.getX(firstPtrIndex);
-        final float firstPtrY = event.getY(firstPtrIndex);
-        final float secondPtrX = event.getX(secondPtrIndex);
-        final float secondPtrY = event.getY(secondPtrIndex);
-
-        final float firstPtrDownX = receivedTracker.getReceivedPointerDownX(firstPtrIndex);
-        final float firstPtrDownY = receivedTracker.getReceivedPointerDownY(firstPtrIndex);
-        final float secondPtrDownX = receivedTracker.getReceivedPointerDownX(secondPtrIndex);
-        final float secondPtrDownY = receivedTracker.getReceivedPointerDownY(secondPtrIndex);
+        final float firstPtrDownX = receivedTracker.getReceivedPointerDownX(0);
+        final float firstPtrDownY = receivedTracker.getReceivedPointerDownY(0);
+        final float secondPtrDownX = receivedTracker.getReceivedPointerDownX(1);
+        final float secondPtrDownY = receivedTracker.getReceivedPointerDownY(1);
 
         return GestureUtils.isDraggingGesture(firstPtrDownX, firstPtrDownY, secondPtrDownX,
                 secondPtrDownY, firstPtrX, firstPtrY, secondPtrX, secondPtrY,
@@ -1350,16 +1230,6 @@
     }
 
     /**
-     * @return The number of non injected active pointers.
-     */
-    private int getNotInjectedActivePointerCount(ReceivedPointerTracker receivedTracker,
-            InjectedPointerTracker injectedTracker) {
-        final int pointerState = receivedTracker.getActivePointers()
-                & ~injectedTracker.getInjectedPointersDown();
-        return Integer.bitCount(pointerState);
-    }
-
-    /**
      * Class for delayed exiting from gesture detecting mode.
      */
     private final class ExitGestureDetectionModeDelayed implements Runnable {
@@ -1368,7 +1238,7 @@
             mHandler.postDelayed(this, EXIT_GESTURE_DETECTION_TIMEOUT);
         }
 
-        public void remove() {
+        public void cancel() {
             mHandler.removeCallbacks(this);
         }
 
@@ -1396,21 +1266,21 @@
             mHandler.postDelayed(this, ViewConfiguration.getLongPressTimeout());
         }
 
-        public void remove() {
-            if (isPending()) {
+        public void cancel() {
+            if (mEvent != null) {
                 mHandler.removeCallbacks(this);
                 clear();
             }
         }
 
-        public boolean isPending() {
-            return (mEvent != null);
+        private boolean isPending() {
+            return mHandler.hasCallbacks(this);
         }
 
         @Override
         public void run() {
-            // Active pointers should not be zero when running this command.
-            if (mReceivedPointerTracker.getActivePointerCount() == 0) {
+            // Pointers should not be zero when running this command.
+            if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) {
                 return;
             }
 
@@ -1461,14 +1331,11 @@
             sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags);
 
             mCurrentState = STATE_DELEGATING;
-            sendDownForAllActiveNotInjectedPointers(mEvent, mPolicyFlags);
+            sendDownForAllNotInjectedPointers(mEvent, mPolicyFlags);
             clear();
         }
 
         private void clear() {
-            if (!isPending()) {
-                return;
-            }
             mEvent.recycle();
             mEvent = null;
             mPolicyFlags = 0;
@@ -1476,59 +1343,114 @@
     }
 
     /**
-     * Class for delayed sending of hover events.
+     * Class for delayed sending of hover enter and move events.
      */
-    class SendHoverDelayed implements Runnable {
-        private final String LOG_TAG_SEND_HOVER_DELAYED = SendHoverDelayed.class.getName();
+    class SendHoverEnterAndMoveDelayed implements Runnable {
+        private final String LOG_TAG_SEND_HOVER_DELAYED = "SendHoverEnterAndMoveDelayed";
 
-        private final int mHoverAction;
-        private final boolean mGestureStarted;
+        private final List<MotionEvent> mEvents = new ArrayList<MotionEvent>();
+
+        private int mPointerIdBits;
+        private int mPolicyFlags;
+
+        public void post(MotionEvent event, boolean touchExplorationInProgress,
+                int pointerIdBits, int policyFlags) {
+            cancel();
+            addEvent(event);
+            mPointerIdBits = pointerIdBits;
+            mPolicyFlags = policyFlags;
+            mHandler.postDelayed(this, mDetermineUserIntentTimeout);
+        }
+
+        public void addEvent(MotionEvent event) {
+            mEvents.add(MotionEvent.obtain(event));
+        }
+
+        public void cancel() {
+            if (isPending()) {
+                mHandler.removeCallbacks(this);
+                clear();
+            }
+        }
+
+        private boolean isPending() {
+            return mHandler.hasCallbacks(this);
+        }
+
+        private void clear() {
+            mPointerIdBits = -1;
+            mPolicyFlags = 0;
+            final int eventCount = mEvents.size();
+            for (int i = eventCount - 1; i >= 0; i--) {
+                mEvents.remove(i).recycle();
+            }
+        }
+
+        public void forceSendAndRemove() {
+            if (isPending()) {
+                run();
+                cancel();
+            }
+        }
+
+        public void run() {
+            // Send an accessibility event to announce the touch exploration start.
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
+
+            if (!mEvents.isEmpty()) {
+                // Deliver a down event.
+                sendMotionEvent(mEvents.get(0), MotionEvent.ACTION_HOVER_ENTER,
+                        mPointerIdBits, mPolicyFlags);
+                if (DEBUG) {
+                    Slog.d(LOG_TAG_SEND_HOVER_DELAYED,
+                            "Injecting motion event: ACTION_HOVER_ENTER");
+                }
+
+                // Deliver move events.
+                final int eventCount = mEvents.size();
+                for (int i = 1; i < eventCount; i++) {
+                    sendMotionEvent(mEvents.get(i), MotionEvent.ACTION_HOVER_MOVE,
+                            mPointerIdBits, mPolicyFlags);
+                    if (DEBUG) {
+                        Slog.d(LOG_TAG_SEND_HOVER_DELAYED,
+                                "Injecting motion event: ACTION_HOVER_MOVE");
+                    }
+                }
+            }
+            clear();
+        }
+    }
+
+    /**
+     * Class for delayed sending of hover exit events.
+     */
+    class SendHoverExitDelayed implements Runnable {
+        private final String LOG_TAG_SEND_HOVER_DELAYED = "SendHoverExitDelayed";
 
         private MotionEvent mPrototype;
         private int mPointerIdBits;
         private int mPolicyFlags;
 
-        public SendHoverDelayed(int hoverAction, boolean gestureStarted) {
-            mHoverAction = hoverAction;
-            mGestureStarted = gestureStarted;
-        }
-
-        public void post(MotionEvent prototype, boolean touchExplorationInProgress,
-                int pointerIdBits, int policyFlags) {
-            remove();
+        public void post(MotionEvent prototype, int pointerIdBits, int policyFlags) {
+            cancel();
             mPrototype = MotionEvent.obtain(prototype);
             mPointerIdBits = pointerIdBits;
             mPolicyFlags = policyFlags;
             mHandler.postDelayed(this, mDetermineUserIntentTimeout);
         }
 
-        public float getX() {
+        public void cancel() {
             if (isPending()) {
-                return mPrototype.getX();
+                mHandler.removeCallbacks(this);
+                clear();
             }
-            return 0;
-        }
-
-        public float getY() {
-            if (isPending()) {
-                return mPrototype.getY();
-            }
-            return 0;
-        }
-
-        public void remove() {
-            mHandler.removeCallbacks(this);
-            clear();
         }
 
         private boolean isPending() {
-            return (mPrototype != null);
+            return mHandler.hasCallbacks(this);
         }
 
         private void clear() {
-            if (!isPending()) {
-                return;
-            }
             mPrototype.recycle();
             mPrototype = null;
             mPointerIdBits = -1;
@@ -1538,29 +1460,25 @@
         public void forceSendAndRemove() {
             if (isPending()) {
                 run();
-                remove();
+                cancel();
             }
         }
 
         public void run() {
             if (DEBUG) {
-                Slog.d(LOG_TAG_SEND_HOVER_DELAYED, "Injecting motion event: "
-                        + MotionEvent.actionToString(mHoverAction));
-                Slog.d(LOG_TAG_SEND_HOVER_DELAYED, mGestureStarted ?
-                        "touchExplorationGestureStarted" : "touchExplorationGestureEnded");
+                Slog.d(LOG_TAG_SEND_HOVER_DELAYED, "Injecting motion event:"
+                        + " ACTION_HOVER_EXIT");
             }
-            if (mGestureStarted) {
-                sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
-            } else {
-                if (!mSendTouchExplorationEndDelayed.isPending()) {
-                    mSendTouchExplorationEndDelayed.post();
-                }
-                if (mSendTouchInteractionEndDelayed.isPending()) {
-                    mSendTouchInteractionEndDelayed.remove();
-                    mSendTouchInteractionEndDelayed.post();
-                }
+            sendMotionEvent(mPrototype, MotionEvent.ACTION_HOVER_EXIT,
+                    mPointerIdBits, mPolicyFlags);
+            if (!mSendTouchExplorationEndDelayed.isPending()) {
+                mSendTouchExplorationEndDelayed.cancel();
+                mSendTouchExplorationEndDelayed.post();
             }
-            sendMotionEvent(mPrototype, mHoverAction, mPointerIdBits, mPolicyFlags);
+            if (mSendTouchInteractionEndDelayed.isPending()) {
+                  mSendTouchInteractionEndDelayed.cancel();
+                mSendTouchInteractionEndDelayed.post();
+            }
             clear();
         }
     }
@@ -1574,7 +1492,7 @@
             mDelay = delay;
         }
 
-        public void remove() {
+        public void cancel() {
             mHandler.removeCallbacks(this);
         }
 
@@ -1589,7 +1507,7 @@
         public void forceSendAndRemove() {
             if (isPending()) {
                 run();
-                remove();
+                cancel();
             }
         }
 
@@ -1736,15 +1654,6 @@
     class ReceivedPointerTracker {
         private static final String LOG_TAG_RECEIVED_POINTER_TRACKER = "ReceivedPointerTracker";
 
-        // The coefficient by which to multiply
-        // ViewConfiguration.#getScaledTouchSlop()
-        // to compute #mThresholdActivePointer.
-        private static final int COEFFICIENT_ACTIVE_POINTER = 2;
-
-        // Pointers that moved less than mThresholdActivePointer
-        // are considered active i.e. are ignored.
-        private final double mThresholdActivePointer;
-
         // Keep track of where and when a pointer went down.
         private final float[] mReceivedPointerDownX = new float[MAX_POINTER_COUNT];
         private final float[] mReceivedPointerDownY = new float[MAX_POINTER_COUNT];
@@ -1756,36 +1665,19 @@
         // The edge flags of the last received down event.
         private int mLastReceivedDownEdgeFlags;
 
-        // Which down pointers are active.
-        private int mActivePointers;
-
-        // Primary active pointer which is either the first that went down
-        // or if it goes up the next active that most recently went down.
-        private int mPrimaryActivePointerId;
-
-        // Flag indicating that there is at least one active pointer moving.
-        private boolean mHasMovingActivePointer;
+        // Primary pointer which is either the first that went down
+        // or if it goes up the next one that most recently went down.
+        private int mPrimaryPointerId;
 
         // Keep track of the last up pointer data.
         private long mLastReceivedUpPointerDownTime;
         private int mLastReceivedUpPointerId;
-        private boolean mLastReceivedUpPointerActive;
         private float mLastReceivedUpPointerDownX;
         private float mLastReceivedUpPointerDownY;
 
         private MotionEvent mLastReceivedEvent;
 
         /**
-         * Creates a new instance.
-         *
-         * @param context Context for looking up resources.
-         */
-        public ReceivedPointerTracker(Context context) {
-            mThresholdActivePointer =
-                ViewConfiguration.get(context).getScaledTouchSlop() * COEFFICIENT_ACTIVE_POINTER;
-        }
-
-        /**
          * Clears the internals state.
          */
         public void clear() {
@@ -1793,12 +1685,9 @@
             Arrays.fill(mReceivedPointerDownY, 0);
             Arrays.fill(mReceivedPointerDownTime, 0);
             mReceivedPointersDown = 0;
-            mActivePointers = 0;
-            mPrimaryActivePointerId = 0;
-            mHasMovingActivePointer = false;
+            mPrimaryPointerId = 0;
             mLastReceivedUpPointerDownTime = 0;
             mLastReceivedUpPointerId = 0;
-            mLastReceivedUpPointerActive = false;
             mLastReceivedUpPointerDownX = 0;
             mLastReceivedUpPointerDownY = 0;
         }
@@ -1822,9 +1711,6 @@
                 case MotionEvent.ACTION_POINTER_DOWN: {
                     handleReceivedPointerDown(event.getActionIndex(), event);
                 } break;
-                case MotionEvent.ACTION_MOVE: {
-                    handleReceivedPointerMove(event);
-                } break;
                 case MotionEvent.ACTION_UP: {
                     handleReceivedPointerUp(event.getActionIndex(), event);
                 } break;
@@ -1852,20 +1738,6 @@
         }
 
         /**
-         * @return The bits of the pointers that are active.
-         */
-        public int getActivePointers() {
-            return mActivePointers;
-        }
-
-        /**
-         * @return The number of down input  pointers that are active.
-         */
-        public int getActivePointerCount() {
-            return Integer.bitCount(mActivePointers);
-        }
-
-        /**
          * Whether an received pointer is down.
          *
          * @param pointerId The unique pointer id.
@@ -1877,17 +1749,6 @@
         }
 
         /**
-         * Whether an input pointer is active.
-         *
-         * @param pointerId The unique pointer id.
-         * @return True if the pointer is active.
-         */
-        public boolean isActivePointer(int pointerId) {
-            final int pointerFlag = (1 << pointerId);
-            return (mActivePointers & pointerFlag) != 0;
-        }
-
-        /**
          * @param pointerId The unique pointer id.
          * @return The X coordinate where the pointer went down.
          */
@@ -1914,11 +1775,11 @@
         /**
          * @return The id of the primary pointer.
          */
-        public int getPrimaryActivePointerId() {
-            if (mPrimaryActivePointerId == INVALID_POINTER_ID) {
-                mPrimaryActivePointerId = findPrimaryActivePointer();
+        public int getPrimaryPointerId() {
+            if (mPrimaryPointerId == INVALID_POINTER_ID) {
+                mPrimaryPointerId = findPrimaryPointer();
             }
-            return mPrimaryActivePointerId;
+            return mPrimaryPointerId;
         }
 
         /**
@@ -1929,14 +1790,6 @@
         }
 
         /**
-         * @return The id of the last received pointer that went up.
-         */
-        public int getLastReceivedUpPointerId() {
-            return mLastReceivedUpPointerId;
-        }
-
-
-        /**
          * @return The down X of the last received pointer that went up.
          */
         public float getLastReceivedUpPointerDownX() {
@@ -1958,39 +1811,6 @@
         }
 
         /**
-         * @return Whether the last received pointer that went up was active.
-         */
-        public boolean wasLastReceivedUpPointerActive() {
-            return mLastReceivedUpPointerActive;
-        }
-        /**
-         * Populates the active pointer IDs to the given array.
-         * <p>
-         * Note: The client is responsible for providing large enough array.
-         *
-         * @param outPointerIds The array to which to write the active pointers.
-         */
-        public void populateActivePointerIds(int[] outPointerIds) {
-            int index = 0;
-            for (int idBits = mActivePointers; idBits != 0; ) {
-                final int id = Integer.numberOfTrailingZeros(idBits);
-                idBits &= ~(1 << id);
-                outPointerIds[index] = id;
-                index++;
-            }
-        }
-
-        /**
-         * @param pointerId The unique pointer id.
-         * @return Whether the pointer is active or was the last active than went up.
-         */
-        public boolean isActiveOrWasLastActiveUpPointer(int pointerId) {
-            return (isActivePointer(pointerId)
-                    || (mLastReceivedUpPointerId == pointerId
-                            && mLastReceivedUpPointerActive));
-        }
-
-        /**
          * Handles a received pointer down event.
          *
          * @param pointerIndex The index of the pointer that has changed.
@@ -2002,7 +1822,6 @@
 
             mLastReceivedUpPointerId = 0;
             mLastReceivedUpPointerDownTime = 0;
-            mLastReceivedUpPointerActive = false;
             mLastReceivedUpPointerDownX = 0;
             mLastReceivedUpPointerDownX = 0;
 
@@ -2013,25 +1832,7 @@
             mReceivedPointerDownY[pointerId] = event.getY(pointerIndex);
             mReceivedPointerDownTime[pointerId] = event.getEventTime();
 
-            if (!mHasMovingActivePointer) {
-                // If still no moving active pointers every
-                // down pointer is the only active one.
-                mActivePointers = pointerFlag;
-                mPrimaryActivePointerId = pointerId;
-            } else {
-                // If at least one moving active pointer every
-                // subsequent down pointer is active.
-                mActivePointers |= pointerFlag;
-            }
-        }
-
-        /**
-         * Handles a received pointer move event.
-         *
-         * @param event The event to be handled.
-         */
-        private void handleReceivedPointerMove(MotionEvent event) {
-            detectActivePointers(event);
+            mPrimaryPointerId = pointerId;
         }
 
         /**
@@ -2046,80 +1847,34 @@
 
             mLastReceivedUpPointerId = pointerId;
             mLastReceivedUpPointerDownTime = getReceivedPointerDownTime(pointerId);
-            mLastReceivedUpPointerActive = isActivePointer(pointerId);
             mLastReceivedUpPointerDownX = mReceivedPointerDownX[pointerId];
             mLastReceivedUpPointerDownY = mReceivedPointerDownY[pointerId];
 
             mReceivedPointersDown &= ~pointerFlag;
-            mActivePointers &= ~pointerFlag;
             mReceivedPointerDownX[pointerId] = 0;
             mReceivedPointerDownY[pointerId] = 0;
             mReceivedPointerDownTime[pointerId] = 0;
 
-            if (mActivePointers == 0) {
-                mHasMovingActivePointer = false;
-            }
-            if (mPrimaryActivePointerId == pointerId) {
-                mPrimaryActivePointerId = INVALID_POINTER_ID;
+            if (mPrimaryPointerId == pointerId) {
+                mPrimaryPointerId = INVALID_POINTER_ID;
             }
         }
 
         /**
-         * Detects the active pointers in an event.
-         *
-         * @param event The event to examine.
+         * @return The primary pointer.
          */
-        private void detectActivePointers(MotionEvent event) {
-            for (int i = 0, count = event.getPointerCount(); i < count; i++) {
-                final int pointerId = event.getPointerId(i);
-                if (mHasMovingActivePointer) {
-                    // If already active => nothing to do.
-                    if (isActivePointer(pointerId)) {
-                        continue;
-                    }
-                }
-                // Active pointers are ones that moved more than a given threshold.
-                final float pointerDeltaMove = computePointerDeltaMove(i, event);
-                if (pointerDeltaMove > mThresholdActivePointer) {
-                    final int pointerFlag = (1 << pointerId);
-                    mActivePointers |= pointerFlag;
-                    mHasMovingActivePointer = true;
-                }
-            }
-        }
-
-        /**
-         * @return The primary active pointer.
-         */
-        private int findPrimaryActivePointer() {
-            int primaryActivePointerId = INVALID_POINTER_ID;
+        private int findPrimaryPointer() {
+            int primaryPointerId = INVALID_POINTER_ID;
             long minDownTime = Long.MAX_VALUE;
-            // Find the active pointer that went down first.
+            // Find the pointer that went down first.
             for (int i = 0, count = mReceivedPointerDownTime.length; i < count; i++) {
-                if (isActivePointer(i)) {
-                    final long downPointerTime = mReceivedPointerDownTime[i];
-                    if (downPointerTime < minDownTime) {
-                        minDownTime = downPointerTime;
-                        primaryActivePointerId = i;
-                    }
+                final long downPointerTime = mReceivedPointerDownTime[i];
+                if (downPointerTime < minDownTime) {
+                    minDownTime = downPointerTime;
+                    primaryPointerId = i;
                 }
             }
-            return primaryActivePointerId;
-        }
-
-        /**
-         * Computes the move for a given action pointer index since the
-         * corresponding pointer went down.
-         *
-         * @param pointerIndex The action pointer index.
-         * @param event The event to examine.
-         * @return The distance the pointer has moved.
-         */
-        private float computePointerDeltaMove(int pointerIndex, MotionEvent event) {
-            final int pointerId = event.getPointerId(pointerIndex);
-            final float deltaX = event.getX(pointerIndex) - mReceivedPointerDownX[pointerId];
-            final float deltaY = event.getY(pointerIndex) - mReceivedPointerDownY[pointerId];
-            return (float) Math.hypot(deltaX, deltaY);
+            return primaryPointerId;
         }
 
         @Override
@@ -2136,18 +1891,8 @@
                 }
             }
             builder.append("]");
-            builder.append("\nActive pointers #");
-            builder.append(getActivePointerCount());
-            builder.append(" [ ");
-            for (int i = 0; i < MAX_POINTER_COUNT; i++) {
-                if (isActivePointer(i)) {
-                    builder.append(i);
-                    builder.append(" ");
-                }
-            }
-            builder.append("]");
-            builder.append("\nPrimary active pointer id [ ");
-            builder.append(getPrimaryActivePointerId());
+            builder.append("\nPrimary pointer id [ ");
+            builder.append(getPrimaryPointerId());
             builder.append(" ]");
             builder.append("\n=========================");
             return builder.toString();
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 163536a..e78362b 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -22,6 +22,8 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.os.Process.SYSTEM_UID;
+import static android.os.Process.PACKAGE_INFO_GID;
 
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
@@ -117,6 +119,7 @@
     private final File mPackageListFilename;
     private final File mStoppedPackagesFilename;
     private final File mBackupStoppedPackagesFilename;
+
     final HashMap<String, PackageSetting> mPackages =
             new HashMap<String, PackageSetting>();
     // List of replaced system applications
@@ -201,6 +204,8 @@
         mSettingsFilename = new File(mSystemDir, "packages.xml");
         mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
         mPackageListFilename = new File(mSystemDir, "packages.list");
+        FileUtils.setPermissions(mPackageListFilename, 0660, SYSTEM_UID, PACKAGE_INFO_GID);
+
         // Deprecated: Needed for migration
         mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
         mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
@@ -1369,13 +1374,15 @@
                     -1, -1);
 
             // Write package list file now, use a JournaledFile.
-            //
-            File tempFile = new File(mPackageListFilename.toString() + ".tmp");
+            File tempFile = new File(mPackageListFilename.getAbsolutePath() + ".tmp");
             JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
 
-            fstr = new FileOutputStream(journal.chooseForWrite());
+            final File writeTarget = journal.chooseForWrite();
+            fstr = new FileOutputStream(writeTarget);
             str = new BufferedOutputStream(fstr);
             try {
+                FileUtils.setPermissions(fstr.getFD(), 0660, SYSTEM_UID, PACKAGE_INFO_GID);
+
                 StringBuilder sb = new StringBuilder();
                 for (final PackageSetting pkg : mPackages.values()) {
                     ApplicationInfo ai = pkg.pkg.applicationInfo;
@@ -1400,6 +1407,7 @@
                     // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
                     // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
                     //   system/core/run-as/run-as.c
+                    //   system/core/sdcard/sdcard.c
                     //
                     sb.setLength(0);
                     sb.append(ai.packageName);
@@ -1421,11 +1429,6 @@
                 journal.rollback();
             }
 
-            FileUtils.setPermissions(mPackageListFilename.toString(),
-                    FileUtils.S_IRUSR|FileUtils.S_IWUSR
-                    |FileUtils.S_IRGRP|FileUtils.S_IWGRP,
-                    -1, -1);
-
             writeAllUsersPackageRestrictionsLPr();
             return;
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 4171bb5..361f5d7 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -1148,14 +1148,6 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawPicture(int nativeCanvas,
-                                                  int nativePicture) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawPicture is not supported.", null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
     /*package*/ static void finalizer(int nativeCanvas) {
         // get the delegate from the native int so that it can be disposed.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);