Merge "Batch ACTION_MOVE events to vsync boundries when resizing task"
diff --git a/api/current.txt b/api/current.txt
index c9e9f9a..758851c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -45349,7 +45349,10 @@
   }
 
   public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
+    method public boolean equals(java.lang.Object);
     method public A getAnnotation(java.lang.Class<A>);
+    method public java.lang.annotation.Annotation[] getAnnotations();
+    method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public java.lang.Class<T> getDeclaringClass();
     method public java.lang.Class<?>[] getExceptionTypes();
     method public java.lang.reflect.Type[] getGenericExceptionTypes();
@@ -45359,6 +45362,7 @@
     method public java.lang.annotation.Annotation[][] getParameterAnnotations();
     method public java.lang.Class<?>[] getParameterTypes();
     method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters();
+    method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
     method public boolean isSynthetic();
     method public boolean isVarArgs();
     method public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
@@ -45432,7 +45436,10 @@
   }
 
   public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
+    method public boolean equals(java.lang.Object);
     method public A getAnnotation(java.lang.Class<A>);
+    method public java.lang.annotation.Annotation[] getAnnotations();
+    method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public java.lang.Class<?> getDeclaringClass();
     method public java.lang.Object getDefaultValue();
     method public java.lang.Class<?>[] getExceptionTypes();
@@ -45446,6 +45453,7 @@
     method public java.lang.Class<?> getReturnType();
     method public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters();
     method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
+    method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
     method public boolean isBridge();
     method public boolean isSynthetic();
     method public boolean isVarArgs();
diff --git a/api/system-current.txt b/api/system-current.txt
index f39dc9a..2568240 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -47957,7 +47957,10 @@
   }
 
   public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
+    method public boolean equals(java.lang.Object);
     method public A getAnnotation(java.lang.Class<A>);
+    method public java.lang.annotation.Annotation[] getAnnotations();
+    method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public java.lang.Class<T> getDeclaringClass();
     method public java.lang.Class<?>[] getExceptionTypes();
     method public java.lang.reflect.Type[] getGenericExceptionTypes();
@@ -47967,6 +47970,7 @@
     method public java.lang.annotation.Annotation[][] getParameterAnnotations();
     method public java.lang.Class<?>[] getParameterTypes();
     method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters();
+    method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
     method public boolean isSynthetic();
     method public boolean isVarArgs();
     method public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
@@ -48040,7 +48044,10 @@
   }
 
   public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
+    method public boolean equals(java.lang.Object);
     method public A getAnnotation(java.lang.Class<A>);
+    method public java.lang.annotation.Annotation[] getAnnotations();
+    method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public java.lang.Class<?> getDeclaringClass();
     method public java.lang.Object getDefaultValue();
     method public java.lang.Class<?>[] getExceptionTypes();
@@ -48054,6 +48061,7 @@
     method public java.lang.Class<?> getReturnType();
     method public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters();
     method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
+    method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
     method public boolean isBridge();
     method public boolean isSynthetic();
     method public boolean isVarArgs();
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 20ac8d8..5c9fd51 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -163,6 +163,7 @@
                 "       am task drag-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" +
                 "       am task size-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" +
                 "       am get-config\n" +
+                "       am suppress-resize-config-changes <true|false>\n" +
                 "       am set-inactive [--user <USER_ID>] <PACKAGE> true|false\n" +
                 "       am get-inactive [--user <USER_ID>] <PACKAGE>\n" +
                 "       am send-trim-memory [--user <USER_ID>] <PROCESS>\n" +
@@ -326,6 +327,8 @@
                 "\n" +
                 "am get-config: retrieve the configuration and any recent configurations\n" +
                 "  of the device.\n" +
+                "am suppress-resize-config-changes: suppresses configuration changes due to\n" +
+                "  user resizing an activity/task.\n" +
                 "\n" +
                 "am set-inactive: sets the inactive state of an app.\n" +
                 "\n" +
@@ -453,6 +456,8 @@
             runTask();
         } else if (op.equals("get-config")) {
             runGetConfig();
+        } else if (op.equals("suppress-resize-config-changes")) {
+            runSuppressResizeConfigChanges();
         } else if (op.equals("set-inactive")) {
             runSetInactive();
         } else if (op.equals("get-inactive")) {
@@ -2606,6 +2611,16 @@
         }
     }
 
+    private void runSuppressResizeConfigChanges() throws Exception {
+        boolean suppress = Boolean.valueOf(nextArgRequired());
+
+        try {
+            mAm.suppressResizeConfigChanges(suppress);
+        } catch (RemoteException e) {
+            System.err.println("Error suppressing resize config changes: " + e);
+        }
+    }
+
     private void runSetInactive() throws Exception {
         int userId = UserHandle.USER_CURRENT;
 
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 3864a4bb..cb1a89f 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2682,6 +2682,13 @@
             reportSizeConfigurations(token, horizontal, vertical);
             return true;
         }
+        case SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final boolean suppress = data.readInt() == 1;
+            suppressResizeConfigChanges(suppress);
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -6216,5 +6223,17 @@
         reply.recycle();
     }
 
+    @Override
+    public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(suppress ? 1 : 0);
+        mRemote.transact(SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 2180bcc..478fdd1 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -535,6 +535,8 @@
     public int getActivityStackId(IBinder token) throws RemoteException;
     public void moveActivityToStack(IBinder token, int stackId) throws RemoteException;
 
+    public void suppressResizeConfigChanges(boolean suppress) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -891,4 +893,5 @@
     int MOVE_ACTIVITY_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 344;
     int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345;
     int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346;
+    int SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347;
 }
diff --git a/core/java/android/widget/MenuPopupWindow.java b/core/java/android/widget/MenuPopupWindow.java
index ba77b1b..eac3a0b 100644
--- a/core/java/android/widget/MenuPopupWindow.java
+++ b/core/java/android/widget/MenuPopupWindow.java
@@ -124,8 +124,8 @@
                 }
                 return true;
             } else if (selectedItem != null && keyCode == mRetreatKey) {
-                setSelectedPositionInt(-1);
-                setNextSelectedPositionInt(-1);
+                setSelectedPositionInt(INVALID_POSITION);
+                setNextSelectedPositionInt(INVALID_POSITION);
 
                 ((MenuAdapter) getAdapter()).getAdapterMenu().close();
                 return true;
@@ -159,6 +159,4 @@
             return superVal;
         }
     }
-
-
 }
\ No newline at end of file
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 44df0ce..b44baa2 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -35,7 +35,7 @@
 public class FloatingActionMode extends ActionMode {
 
     private static final int MAX_HIDE_DURATION = 3000;
-    private static final int MOVING_HIDE_DELAY = 300;
+    private static final int MOVING_HIDE_DELAY = 50;
 
     private final Context mContext;
     private final ActionMode.Callback2 mCallback;
@@ -181,7 +181,6 @@
                 // Content rect is moving.
                 mOriginatingView.removeCallbacks(mMovingOff);
                 mFloatingToolbarVisibilityHelper.setMoving(true);
-                mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
                 mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY);
 
                 mFloatingToolbar.setContentRect(mContentRectOnScreen);
@@ -189,9 +188,9 @@
             }
         } else {
             mFloatingToolbarVisibilityHelper.setOutOfBounds(true);
-            mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
             mContentRectOnScreen.setEmpty();
         }
+        mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
 
         mPreviousContentRectOnScreen.set(mContentRectOnScreen);
     }
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index 415f325..aa7b34b 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -153,8 +153,6 @@
                         (MenuDropDownListView) mListViews.get(menuIndex + 1);
                 final MenuAdapter nextAdapter = (MenuAdapter) nextView.getAdapter();
 
-                view.clearSelection();
-
                 mSubMenuHoverHandler.removeCallbacksAndMessages(null);
                 mSubMenuHoverHandler.postDelayed(new Runnable() {
                     @Override
@@ -162,9 +160,14 @@
                         // Make sure the menu wasn't already closed by something else and that
                         // it wasn't re-hovered by the user since this was scheduled.
                         int nextMenuIndex = mListViews.indexOf(nextView);
+
                         if (nextMenuIndex != -1 && nextView.getSelectedView() == null) {
                             // Disable exit animation, to prevent overlapping fading out submenus.
-                            mPopupWindows.get(nextMenuIndex).setExitTransition(null);
+                            for (int i = nextMenuIndex; i < mPopupWindows.size(); i++) {
+                                final MenuPopupWindow popupWindow = mPopupWindows.get(i);
+                                popupWindow.setExitTransition(null);
+                                popupWindow.setAnimationStyle(0);
+                            }
                             nextAdapter.getAdapterMenu().close();
                         }
                     }
@@ -178,8 +181,9 @@
     private View mShownAnchorView;
     private List<DropDownListView> mListViews;
     private List<MenuPopupWindow> mPopupWindows;
+    private int mLastPosition;
+    private List<Integer> mPositions;
     private List<int[]> mOffsets;
-    private int mPreferredPosition;
     private boolean mForceShowIcon;
     private Callback mPresenterCallback;
     private ViewTreeObserver mTreeObserver;
@@ -203,14 +207,14 @@
         final Resources res = context.getResources();
         final Configuration config = res.getConfiguration();
         mLayoutDirection = config.getLayoutDirection();
-        mPreferredPosition = mLayoutDirection == View.LAYOUT_DIRECTION_RTL ? HORIZ_POSITION_LEFT :
-                HORIZ_POSITION_RIGHT;
+        mLastPosition = getInitialMenuPosition();
         mMenuMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
                 res.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth));
 
         mPopupWindows = new ArrayList<MenuPopupWindow>();
         mListViews = new ArrayList<DropDownListView>();
         mOffsets = new ArrayList<int[]>();
+        mPositions = new ArrayList<Integer>();
         mSubMenuHoverHandler = new Handler();
     }
 
@@ -286,6 +290,16 @@
     }
 
     /**
+     * Determines the proper initial menu position for the current LTR/RTL configuration.
+     * @return The initial position.
+     */
+    @HorizPosition
+    private int getInitialMenuPosition() {
+        return mLayoutDirection == View.LAYOUT_DIRECTION_RTL ? HORIZ_POSITION_LEFT :
+                HORIZ_POSITION_RIGHT;
+    }
+
+    /**
      * Determines whether the next submenu (of the given width) should display on the right or on
      * the left of the most recent menu.
      *
@@ -302,7 +316,7 @@
         final Rect displayFrame = new Rect();
         mShownAnchorView.getWindowVisibleDisplayFrame(displayFrame);
 
-        if (mPreferredPosition == HORIZ_POSITION_RIGHT) {
+        if (mLastPosition == HORIZ_POSITION_RIGHT) {
             final int right = screenLocation[0] + lastListView.getWidth() + nextMenuWidth;
             if (right > displayFrame.right) {
                 return HORIZ_POSITION_LEFT;
@@ -342,7 +356,7 @@
             ListView lastListView = mListViews.get(mListViews.size() - 1);
             @HorizPosition int nextMenuPosition = getNextMenuPosition(menuWidth);
             boolean showOnRight = nextMenuPosition == HORIZ_POSITION_RIGHT;
-            mPreferredPosition = nextMenuPosition;
+            mLastPosition = nextMenuPosition;
 
             int[] lastLocation = new int[2];
             lastListView.getLocationOnScreen(lastLocation);
@@ -384,6 +398,7 @@
 
         int[] offsets = {x, y};
         mOffsets.add(offsets);
+        mPositions.add(mLastPosition);
     }
 
     /**
@@ -479,9 +494,11 @@
             mListViews.subList(menuIndex, mListViews.size()).clear();
             mOffsets.subList(menuIndex, mOffsets.size()).clear();
 
-            // If there's still a menu open, refocus the new leaf [sub]menu.
-            if (mListViews.size() > 0) {
-                mListViews.get(mListViews.size() - 1).requestFocus();
+            mPositions.subList(menuIndex, mPositions.size()).clear();
+            if (mPositions.size() > 0) {
+                mLastPosition = mPositions.get(mPositions.size() - 1);
+            } else {
+                mLastPosition = getInitialMenuPosition();
             }
         }
 
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index ca6fe61..2a25db6 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -1488,10 +1488,9 @@
     private static AnimatorSet createEnterAnimation(View view) {
         AnimatorSet animation =  new AnimatorSet();
         animation.playTogether(
-                ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(200),
+                ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(150),
                 // Make sure that view.x is always fixed throughout the duration of this animation.
                 ObjectAnimator.ofFloat(view, View.X, view.getX(), view.getX()));
-        animation.setStartDelay(50);
         return animation;
     }
 
@@ -1506,7 +1505,7 @@
             View view, int startDelay, Animator.AnimatorListener listener) {
         AnimatorSet animation =  new AnimatorSet();
         animation.playTogether(
-                ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(200));
+                ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(100));
         animation.setStartDelay(startDelay);
         animation.addListener(listener);
         return animation;
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index e4bc800..ffc69a9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -217,7 +217,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nativeFinishInit", "()V",
         (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
     { "nativeZygoteInit", "()V",
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index fbe3ece..e6c7c2b 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1348,7 +1348,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gBitmapMethods[] = {
+static const JNINativeMethod gBitmapMethods[] = {
     {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",
         (void*)Bitmap_creator },
     {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 20a54e5..28bc7fe 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -542,7 +542,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {   "nativeDecodeStream",
         "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeStream
@@ -569,7 +569,7 @@
     },
 };
 
-static JNINativeMethod gOptionsMethods[] = {
+static const JNINativeMethod gOptionsMethods[] = {
     {   "requestCancel", "()V", (void*)nativeRequestCancel }
 };
 
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 1bbbb089..2df3a46 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -261,7 +261,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gBitmapRegionDecoderMethods[] = {
+static const JNINativeMethod gBitmapRegionDecoderMethods[] = {
     {   "nativeDecodeRegion",
         "(JIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeRegion},
diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp
index 036ece1..6fcf689 100644
--- a/core/jni/android/graphics/Camera.cpp
+++ b/core/jni/android/graphics/Camera.cpp
@@ -115,7 +115,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gCameraMethods[] = {
+static const JNINativeMethod gCameraMethods[] = {
     /* name, signature, funcPtr */
 
     { "nativeConstructor",   "()V",    (void*)Camera_constructor   },
diff --git a/core/jni/android/graphics/CanvasProperty.cpp b/core/jni/android/graphics/CanvasProperty.cpp
index deb4971..728bc1c 100644
--- a/core/jni/android/graphics/CanvasProperty.cpp
+++ b/core/jni/android/graphics/CanvasProperty.cpp
@@ -39,7 +39,7 @@
 // JNI Glue
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nCreateFloat", "(F)J", (void*) createFloat },
     { "nCreatePaint", "(J)J", (void*) createPaint },
 };
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index d03bcf0..83fd073 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -57,19 +57,19 @@
     }
 };
 
-static JNINativeMethod colorfilter_methods[] = {
+static const JNINativeMethod colorfilter_methods[] = {
     {"destroyFilter", "(J)V", (void*) SkColorFilterGlue::finalizer}
 };
 
-static JNINativeMethod porterduff_methods[] = {
+static const JNINativeMethod porterduff_methods[] = {
     { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter   },
 };
 
-static JNINativeMethod lighting_methods[] = {
+static const JNINativeMethod lighting_methods[] = {
     { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter   },
 };
 
-static JNINativeMethod colormatrix_methods[] = {
+static const JNINativeMethod colormatrix_methods[] = {
     { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter   },
 };
 
diff --git a/core/jni/android/graphics/DrawFilter.cpp b/core/jni/android/graphics/DrawFilter.cpp
index 90ef6c0..c1dc0dd 100644
--- a/core/jni/android/graphics/DrawFilter.cpp
+++ b/core/jni/android/graphics/DrawFilter.cpp
@@ -97,11 +97,11 @@
     }
 };
 
-static JNINativeMethod drawfilter_methods[] = {
+static const JNINativeMethod drawfilter_methods[] = {
     {"nativeDestructor", "(J)V", (void*) SkDrawFilterGlue::finalizer}
 };
 
-static JNINativeMethod paintflags_methods[] = {
+static const JNINativeMethod paintflags_methods[] = {
     {"nativeConstructor","(II)J", (void*) SkDrawFilterGlue::CreatePaintFlagsDF}
 };
 
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 38db76b..dac6d96 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -124,7 +124,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gFontFamilyMethods[] = {
+static const JNINativeMethod gFontFamilyMethods[] = {
     { "nCreateFamily",         "(Ljava/lang/String;I)J", (void*)FontFamily_create },
     { "nUnrefFamily",          "(J)V", (void*)FontFamily_unref },
     { "nAddFont",              "(JLjava/lang/String;)Z", (void*)FontFamily_addFont },
diff --git a/core/jni/android/graphics/Interpolator.cpp b/core/jni/android/graphics/Interpolator.cpp
index 3593d1a..fa28359 100644
--- a/core/jni/android/graphics/Interpolator.cpp
+++ b/core/jni/android/graphics/Interpolator.cpp
@@ -71,7 +71,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gInterpolatorMethods[] = {
+static const JNINativeMethod gInterpolatorMethods[] = {
     { "nativeConstructor",      "(II)J",        (void*)Interpolator_constructor     },
     { "nativeDestructor",       "(J)V",         (void*)Interpolator_destructor      },
     { "nativeReset",            "(JII)V",       (void*)Interpolator_reset           },
diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp
index d658643..2b4a1ab 100644
--- a/core/jni/android/graphics/MaskFilter.cpp
+++ b/core/jni/android/graphics/MaskFilter.cpp
@@ -61,19 +61,19 @@
     }
 };
 
-static JNINativeMethod gMaskFilterMethods[] = {
+static const JNINativeMethod gMaskFilterMethods[] = {
     { "nativeDestructor",   "(J)V",     (void*)SkMaskFilterGlue::destructor      }
 };
 
-static JNINativeMethod gBlurMaskFilterMethods[] = {
+static const JNINativeMethod gBlurMaskFilterMethods[] = {
     { "nativeConstructor",  "(FI)J",    (void*)SkMaskFilterGlue::createBlur      }
 };
 
-static JNINativeMethod gEmbossMaskFilterMethods[] = {
+static const JNINativeMethod gEmbossMaskFilterMethods[] = {
     { "nativeConstructor",  "([FFFF)J", (void*)SkMaskFilterGlue::createEmboss    }
 };
 
-static JNINativeMethod gTableMaskFilterMethods[] = {
+static const JNINativeMethod gTableMaskFilterMethods[] = {
     { "nativeNewTable", "([B)J", (void*)SkMaskFilterGlue::createTable    },
     { "nativeNewClip",  "(II)J", (void*)SkMaskFilterGlue::createClipTable    },
     { "nativeNewGamma", "(F)J", (void*)SkMaskFilterGlue::createGammaTable    }
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index 101e2ba..b0f3bb4 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -302,7 +302,7 @@
     }
  };
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
     {"finalizer", "(J)V", (void*) SkMatrixGlue::finalizer},
     {"native_create","(J)J", (void*) SkMatrixGlue::create},
 
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index d67ed10..498c590 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -135,7 +135,7 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {   "width",    "()I",  (void*)movie_width  },
     {   "height",   "()I",  (void*)movie_height  },
     {   "isOpaque", "()Z",  (void*)movie_isOpaque  },
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index 1c28262..3ccbb35 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -108,7 +108,7 @@
 
 /////////////////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gNinePatchMethods[] = {
+static const JNINativeMethod gNinePatchMethods[] = {
     { "isNinePatchChunk", "([B)Z", (void*) SkNinePatchGlue::isNinePatchChunk },
     { "validateNinePatchChunk", "([B)J",
             (void*) SkNinePatchGlue::validateNinePatchChunk },
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 988d13a..520dc4f 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -1095,7 +1095,7 @@
 
 };
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
     {"finalizer", "(J)V", (void*) PaintGlue::finalizer},
     {"native_init","()J", (void*) PaintGlue::init},
     {"native_initWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index dbd7c89..2998c99 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -475,7 +475,7 @@
     }
 };
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
     {"finalizer", "(J)V", (void*) SkPathGlue::finalizer},
     {"init1","()J", (void*) SkPathGlue::init1},
     {"init2","(J)J", (void*) SkPathGlue::init2},
diff --git a/core/jni/android/graphics/PathEffect.cpp b/core/jni/android/graphics/PathEffect.cpp
index 265944e..b289b21 100644
--- a/core/jni/android/graphics/PathEffect.cpp
+++ b/core/jni/android/graphics/PathEffect.cpp
@@ -69,31 +69,31 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gPathEffectMethods[] = {
+static const JNINativeMethod gPathEffectMethods[] = {
     { "nativeDestructor", "(J)V", (void*)SkPathEffectGlue::destructor }
 };
 
-static JNINativeMethod gComposePathEffectMethods[] = {
+static const JNINativeMethod gComposePathEffectMethods[] = {
     { "nativeCreate", "(JJ)J", (void*)SkPathEffectGlue::Compose_constructor }
 };
 
-static JNINativeMethod gSumPathEffectMethods[] = {
+static const JNINativeMethod gSumPathEffectMethods[] = {
     { "nativeCreate", "(JJ)J", (void*)SkPathEffectGlue::Sum_constructor }
 };
 
-static JNINativeMethod gDashPathEffectMethods[] = {
+static const JNINativeMethod gDashPathEffectMethods[] = {
     { "nativeCreate", "([FF)J", (void*)SkPathEffectGlue::Dash_constructor }
 };
 
-static JNINativeMethod gPathDashPathEffectMethods[] = {
+static const JNINativeMethod gPathDashPathEffectMethods[] = {
     { "nativeCreate", "(JFFI)J", (void*)SkPathEffectGlue::OneD_constructor }
 };
 
-static JNINativeMethod gCornerPathEffectMethods[] = {
+static const JNINativeMethod gCornerPathEffectMethods[] = {
     { "nativeCreate", "(F)J", (void*)SkPathEffectGlue::Corner_constructor }
 };
 
-static JNINativeMethod gDiscretePathEffectMethods[] = {
+static const JNINativeMethod gDiscretePathEffectMethods[] = {
     { "nativeCreate", "(FF)J", (void*)SkPathEffectGlue::Discrete_constructor }
 };
 
diff --git a/core/jni/android/graphics/PathMeasure.cpp b/core/jni/android/graphics/PathMeasure.cpp
index fec5d9d..70e528d 100644
--- a/core/jni/android/graphics/PathMeasure.cpp
+++ b/core/jni/android/graphics/PathMeasure.cpp
@@ -143,7 +143,7 @@
     } 
 };
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
     {"native_create",       "(JZ)J",        (void*) SkPathMeasureGlue::create      },
     {"native_setPath",      "(JJZ)V",       (void*) SkPathMeasureGlue::setPath     },
     {"native_getLength",    "(J)F",         (void*) SkPathMeasureGlue::getLength   },
diff --git a/core/jni/android/graphics/PorterDuff.cpp b/core/jni/android/graphics/PorterDuff.cpp
index fed90a5..dfc3c9d 100644
--- a/core/jni/android/graphics/PorterDuff.cpp
+++ b/core/jni/android/graphics/PorterDuff.cpp
@@ -58,7 +58,7 @@
 
 };
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
     {"nativeCreateXfermode","(I)J", (void*) SkPorterDuffGlue::CreateXfermode},
 };
 
diff --git a/core/jni/android/graphics/Rasterizer.cpp b/core/jni/android/graphics/Rasterizer.cpp
index cfc23ac8..a106ecf 100644
--- a/core/jni/android/graphics/Rasterizer.cpp
+++ b/core/jni/android/graphics/Rasterizer.cpp
@@ -61,7 +61,7 @@
     }
 };
 
-static JNINativeMethod gRasterizerMethods[] = {
+static const JNINativeMethod gRasterizerMethods[] = {
     {"finalizer", "(J)V", (void*) SkRasterizerGlue::finalizer}
 };
 
@@ -85,7 +85,7 @@
     }
 };
 
-static JNINativeMethod gLayerRasterizerMethods[] = {
+static const JNINativeMethod gLayerRasterizerMethods[] = {
     { "nativeConstructor",  "()J",      (void*)SkLayerRasterizerGlue::create    },
     { "nativeAddLayer",     "(JJFF)V",  (void*)SkLayerRasterizerGlue::addLayer  }
 };
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index e99bdfc..bcd0b60 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -306,13 +306,13 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gRegionIterMethods[] = {
+static const JNINativeMethod gRegionIterMethods[] = {
     { "nativeConstructor",  "(J)J",                         (void*)RegionIter_constructor   },
     { "nativeDestructor",   "(J)V",                         (void*)RegionIter_destructor    },
     { "nativeNext",         "(JLandroid/graphics/Rect;)Z",  (void*)RegionIter_next          }
 };
 
-static JNINativeMethod gRegionMethods[] = {
+static const JNINativeMethod gRegionMethods[] = {
     // these are static methods
     { "nativeConstructor",      "()J",                              (void*)Region_constructor       },
     { "nativeDestructor",       "(J)V",                             (void*)Region_destructor        },
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 49c377e..799ed83 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -240,36 +240,36 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gColorMethods[] = {
+static const JNINativeMethod gColorMethods[] = {
     { "nativeRGBToHSV",     "(III[F)V", (void*)Color_RGBToHSV   },
     { "nativeHSVToColor",   "(I[F)I",   (void*)Color_HSVToColor }
 };
 
-static JNINativeMethod gShaderMethods[] = {
+static const JNINativeMethod gShaderMethods[] = {
     { "nativeDestructor",        "(J)V",    (void*)Shader_destructor        },
     { "nativeSetLocalMatrix",    "(JJ)J",   (void*)Shader_setLocalMatrix    }
 };
 
-static JNINativeMethod gBitmapShaderMethods[] = {
+static const JNINativeMethod gBitmapShaderMethods[] = {
     { "nativeCreate",     "(Landroid/graphics/Bitmap;II)J",  (void*)BitmapShader_constructor },
 };
 
-static JNINativeMethod gLinearGradientMethods[] = {
+static const JNINativeMethod gLinearGradientMethods[] = {
     { "nativeCreate1",     "(FFFF[I[FI)J",  (void*)LinearGradient_create1     },
     { "nativeCreate2",     "(FFFFIII)J",    (void*)LinearGradient_create2     },
 };
 
-static JNINativeMethod gRadialGradientMethods[] = {
+static const JNINativeMethod gRadialGradientMethods[] = {
     { "nativeCreate1",     "(FFF[I[FI)J",  (void*)RadialGradient_create1     },
     { "nativeCreate2",     "(FFFIII)J",    (void*)RadialGradient_create2     },
 };
 
-static JNINativeMethod gSweepGradientMethods[] = {
+static const JNINativeMethod gSweepGradientMethods[] = {
     { "nativeCreate1",     "(FF[I[F)J",  (void*)SweepGradient_create1     },
     { "nativeCreate2",     "(FFII)J",    (void*)SweepGradient_create2     },
 };
 
-static JNINativeMethod gComposeShaderMethods[] = {
+static const JNINativeMethod gComposeShaderMethods[] = {
     { "nativeCreate1",      "(JJJ)J",   (void*)ComposeShader_create1     },
     { "nativeCreate2",      "(JJI)J",   (void*)ComposeShader_create2     },
 };
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 80de526..61dc6e4 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -359,7 +359,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gSurfaceTextureMethods[] = {
+static const JNINativeMethod gSurfaceTextureMethods[] = {
     {"nativeClassInit",            "()V",   (void*)SurfaceTexture_classInit },
     {"nativeInit",                 "(ZIZLjava/lang/ref/WeakReference;)V", (void*)SurfaceTexture_init },
     {"nativeFinalize",             "()V",   (void*)SurfaceTexture_finalize },
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index e0cbc9e..e97b768d 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -68,7 +68,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gTypefaceMethods[] = {
+static const JNINativeMethod gTypefaceMethods[] = {
     { "nativeCreateFromTypeface", "(JI)J", (void*)Typeface_createFromTypeface },
     { "nativeCreateWeightAlias",  "(JI)J", (void*)Typeface_createWeightAlias },
     { "nativeUnref",              "(J)V",  (void*)Typeface_unref },
diff --git a/core/jni/android/graphics/Xfermode.cpp b/core/jni/android/graphics/Xfermode.cpp
index 4a424ae..7441acc 100644
--- a/core/jni/android/graphics/Xfermode.cpp
+++ b/core/jni/android/graphics/Xfermode.cpp
@@ -47,15 +47,15 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gXfermodeMethods[] = {
+static const JNINativeMethod gXfermodeMethods[] = {
     {"finalizer", "(J)V", (void*) SkXfermodeGlue::finalizer}
 };
 
-static JNINativeMethod gAvoidMethods[] = {
+static const JNINativeMethod gAvoidMethods[] = {
     {"nativeCreate", "(III)J", (void*) SkXfermodeGlue::avoid_create}
 };
 
-static JNINativeMethod gPixelXorMethods[] = {
+static const JNINativeMethod gPixelXorMethods[] = {
     {"nativeCreate", "(I)J", (void*) SkXfermodeGlue::pixelxor_create}
 };
 
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
index 5eede2a..7d0c39c 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -243,7 +243,7 @@
 }
 ///////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gYuvImageMethods[] = {
+static const JNINativeMethod gYuvImageMethods[] = {
     {   "nativeCompressToJpeg",  "([BIII[I[IILjava/io/OutputStream;[B)Z",
         (void*)YuvImage_compressToJpeg }
 };
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index a91b15b..7a13fe4 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -150,7 +150,7 @@
     document->close();
 }
 
-static JNINativeMethod gPdfDocument_Methods[] = {
+static const JNINativeMethod gPdfDocument_Methods[] = {
     {"nativeCreateDocument", "()J", (void*) nativeCreateDocument},
     {"nativeStartPage", "(JIIIIII)J", (void*) nativeStartPage},
     {"nativeFinishPage", "(J)V", (void*) nativeFinishPage},
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
index 52b69e0..0177635 100644
--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -343,7 +343,7 @@
     nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP, mediaBox);
 }
 
-static JNINativeMethod gPdfEditor_Methods[] = {
+static const JNINativeMethod gPdfEditor_Methods[] = {
     {"nativeOpen", "(IJ)J", (void*) nativeOpen},
     {"nativeClose", "(J)V", (void*) nativeClose},
     {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index 006eef8..6ddfacf 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -283,7 +283,7 @@
     skBitmap.notifyPixelsChanged();
 }
 
-static JNINativeMethod gPdfRenderer_Methods[] = {
+static const JNINativeMethod gPdfRenderer_Methods[] = {
     {"nativeCreate", "(IJ)J", (void*) nativeCreate},
     {"nativeClose", "(J)V", (void*) nativeClose},
     {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 40029bb..e045f5f 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -1087,18 +1087,18 @@
  * JNI registration
  */
 
-static JNINativeMethod gMatrixMethods[] = {
+static const JNINativeMethod gMatrixMethods[] = {
     { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
     { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
 };
 
-static JNINativeMethod gVisibilityMethods[] = {
+static const JNINativeMethod gVisibilityMethods[] = {
     { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
     { "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres },
     { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
 };
 
-static JNINativeMethod gUtilsMethods[] = {
+static const JNINativeMethod gUtilsMethods[] = {
     { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
     { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
     { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
@@ -1106,7 +1106,7 @@
     { "setTracingLevel", "(I)V",                        (void*)setTracingLevel },
 };
 
-static JNINativeMethod gEtc1Methods[] = {
+static const JNINativeMethod gEtc1Methods[] = {
     { "encodeBlock", "(Ljava/nio/Buffer;ILjava/nio/Buffer;)V", (void*) etc1_encodeBlock },
     { "decodeBlock", "(Ljava/nio/Buffer;Ljava/nio/Buffer;)V", (void*) etc1_decodeBlock },
     { "getEncodedDataSize", "(II)I", (void*) etc1_getEncodedDataSize },
@@ -1120,11 +1120,11 @@
 
 typedef struct _ClassRegistrationInfo {
     const char* classPath;
-    JNINativeMethod* methods;
+    const JNINativeMethod* methods;
     size_t methodCount;
 } ClassRegistrationInfo;
 
-static ClassRegistrationInfo gClasses[] = {
+static const ClassRegistrationInfo gClasses[] = {
     {"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)},
     {"android/opengl/Visibility", gVisibilityMethods, NELEM(gVisibilityMethods)},
     {"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)},
@@ -1136,7 +1136,7 @@
     nativeClassInitBuffer(env);
     int result = 0;
     for (int i = 0; i < NELEM(gClasses); i++) {
-        ClassRegistrationInfo* cri = &gClasses[i];
+        const ClassRegistrationInfo* cri = &gClasses[i];
         result = RegisterMethodsOrDie(env, cri->classPath, cri->methods, cri->methodCount);
     }
     return result;
diff --git a/core/jni/android_animation_PropertyValuesHolder.cpp b/core/jni/android_animation_PropertyValuesHolder.cpp
index d1177418..6065c24 100644
--- a/core/jni/android_animation_PropertyValuesHolder.cpp
+++ b/core/jni/android_animation_PropertyValuesHolder.cpp
@@ -139,7 +139,7 @@
     env->ReleaseIntArrayElements(arg, intValues, JNI_ABORT);
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {   "nGetIntMethod", "(Ljava/lang/Class;Ljava/lang/String;)J",
             (void*)android_animation_PropertyValuesHolder_getIntMethod },
     {   "nGetFloatMethod", "(Ljava/lang/Class;Ljava/lang/String;)J",
diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp
index ef17db6..36d78cf 100644
--- a/core/jni/android_content_res_ObbScanner.cpp
+++ b/core/jni/android_content_res_ObbScanner.cpp
@@ -76,7 +76,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "getObbInfo_native", "(Ljava/lang/String;Landroid/content/res/ObbInfo;)V",
             (void*) android_content_res_ObbScanner_getObbInfo },
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 580ac02..bb09d00 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -477,7 +477,7 @@
     return true;
 }
 
-static JNINativeMethod sMethods[] =
+static const JNINativeMethod sMethods[] =
 {
     /* name, signature, funcPtr */
     { "nativeCreate", "(Ljava/lang/String;I)J",
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index 7a3cdf6..bcc3bb0 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -786,7 +786,7 @@
 }
 
 
-static JNINativeMethod sMethods[] =
+static const JNINativeMethod sMethods[] =
 {
     /* name, signature, funcPtr */
     { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZ)J",
diff --git a/core/jni/android_database_SQLiteDebug.cpp b/core/jni/android_database_SQLiteDebug.cpp
index 26e13cf..4e4c36c 100644
--- a/core/jni/android_database_SQLiteDebug.cpp
+++ b/core/jni/android_database_SQLiteDebug.cpp
@@ -58,7 +58,7 @@
  * JNI registration.
  */
 
-static JNINativeMethod gMethods[] =
+static const JNINativeMethod gMethods[] =
 {
     { "nativeGetPagerStats", "(Landroid/database/sqlite/SQLiteDebug$PagerStats;)V",
             (void*) nativeGetPagerStats },
diff --git a/core/jni/android_database_SQLiteGlobal.cpp b/core/jni/android_database_SQLiteGlobal.cpp
index 0a1c9f7..03e2387 100644
--- a/core/jni/android_database_SQLiteGlobal.cpp
+++ b/core/jni/android_database_SQLiteGlobal.cpp
@@ -75,7 +75,7 @@
     return sqlite3_release_memory(SOFT_HEAP_LIMIT);
 }
 
-static JNINativeMethod sMethods[] =
+static const JNINativeMethod sMethods[] =
 {
     /* name, signature, funcPtr */
     { "nativeReleaseMemory", "()I", (void*)nativeReleaseMemory },
diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
index ae96936..3e7a04e 100644
--- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp
+++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
@@ -105,7 +105,7 @@
     return array;
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "getLeakInfo", "()[B", (void*) DdmHandleNativeHeap_getLeakInfo },
 };
 
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 5ddf235..32a877a 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -746,7 +746,7 @@
 
 }; // namespace CanvasJNI
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"finalizer", "(J)V", (void*) CanvasJNI::finalizer},
     {"initRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
     {"native_setBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
diff --git a/core/jni/android_graphics_Picture.cpp b/core/jni/android_graphics_Picture.cpp
index fd42ddb..03fcdef 100644
--- a/core/jni/android_graphics_Picture.cpp
+++ b/core/jni/android_graphics_Picture.cpp
@@ -91,7 +91,7 @@
     pict->endRecording();
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"nativeGetWidth", "(J)I", (void*) android_graphics_Picture_getWidth},
     {"nativeGetHeight", "(J)I", (void*) android_graphics_Picture_getHeight},
     {"nativeConstructor", "(J)J", (void*) android_graphics_Picture_newPicture},
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 4f44c262..414eba7 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -949,7 +949,7 @@
 
 //-------------------------------------------------
 
-static JNINativeMethod camMethods[] = {
+static const JNINativeMethod camMethods[] = {
   { "getNumberOfCameras",
     "()I",
     (void *)android_hardware_Camera_getNumberOfCameras },
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 7d0afdc..2e5cda0 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -343,7 +343,7 @@
 }
 //----------------------------------------------------------------------------
 
-static JNINativeMethod gSystemSensorManagerMethods[] = {
+static const JNINativeMethod gSystemSensorManagerMethods[] = {
     {"nativeClassInit",
             "()V",
             (void*)nativeClassInit },
@@ -360,7 +360,7 @@
             (void*)nativeIsDataInjectionEnabled},
 };
 
-static JNINativeMethod gBaseEventQueueMethods[] = {
+static const JNINativeMethod gBaseEventQueueMethods[] = {
     {"nativeInitBaseEventQueue",
              "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;ILjava/lang/String;)J",
              (void*)nativeInitSensorEventQueue },
diff --git a/core/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp
index 2d2ff4d..393dc7b 100644
--- a/core/jni/android_hardware_SerialPort.cpp
+++ b/core/jni/android_hardware_SerialPort.cpp
@@ -243,7 +243,7 @@
     tcsendbreak(fd, 0);
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     {"native_open",             "(Ljava/io/FileDescriptor;I)V",
                                         (void *)android_hardware_SerialPort_open},
     {"native_close",            "()V",  (void *)android_hardware_SerialPort_close},
diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp
index 1c4c9ec..048b3c7 100644
--- a/core/jni/android_hardware_SoundTrigger.cpp
+++ b/core/jni/android_hardware_SoundTrigger.cpp
@@ -768,14 +768,14 @@
     return status;
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"listModules",
         "(Ljava/util/ArrayList;)I",
         (void *)android_hardware_SoundTrigger_listModules},
 };
 
 
-static JNINativeMethod gModuleMethods[] = {
+static const JNINativeMethod gModuleMethods[] = {
     {"native_setup",
         "(Ljava/lang/Object;)V",
         (void *)android_hardware_SoundTrigger_setup},
diff --git a/core/jni/android_hardware_UsbDevice.cpp b/core/jni/android_hardware_UsbDevice.cpp
index ef3b646..89d33e2 100644
--- a/core/jni/android_hardware_UsbDevice.cpp
+++ b/core/jni/android_hardware_UsbDevice.cpp
@@ -44,7 +44,7 @@
     return result;
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     // static methods
     { "native_get_device_id", "(Ljava/lang/String;)I",
                                         (void*)android_hardware_UsbDevice_get_device_id },
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index e0cae6f..1ba9fc5 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -246,7 +246,7 @@
     return result;
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     {"native_open",             "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z",
                                         (void *)android_hardware_UsbDeviceConnection_open},
     {"native_close",            "()V",  (void *)android_hardware_UsbDeviceConnection_close},
diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp
index ce99e15..399e7b1 100644
--- a/core/jni/android_hardware_UsbRequest.cpp
+++ b/core/jni/android_hardware_UsbRequest.cpp
@@ -190,7 +190,7 @@
     return (usb_request_cancel(request) == 0);
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     {"native_init",             "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z",
                                             (void *)android_hardware_UsbRequest_init},
     {"native_close",            "()V",      (void *)android_hardware_UsbRequest_close},
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index fb22689..7930027 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -529,7 +529,7 @@
 
 //-------------------------------------------------
 
-static JNINativeMethod gCameraMetadataMethods[] = {
+static const JNINativeMethod gCameraMetadataMethods[] = {
 // static methods
   { "nativeClassInit",
     "()V",
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 8b69bbd..738a62a 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -2280,7 +2280,7 @@
 
 } /*extern "C" */
 
-static JNINativeMethod gDngCreatorMethods[] = {
+static const JNINativeMethod gDngCreatorMethods[] = {
     {"nativeClassInit",        "()V", (void*) DngCreator_nativeClassInit},
     {"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;"
             "Landroid/hardware/camera2/impl/CameraMetadataNative;Ljava/lang/String;)V",
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index 63915ed..f1ea7ec 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -730,7 +730,7 @@
 
 } // extern "C"
 
-static JNINativeMethod gCameraDeviceMethods[] = {
+static const JNINativeMethod gCameraDeviceMethods[] = {
     { "nativeDetectSurfaceType",
     "(Landroid/view/Surface;)I",
     (void *)LegacyCameraDevice_nativeDetectSurfaceType },
diff --git a/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp b/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp
index 7257597..f042058 100644
--- a/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp
+++ b/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp
@@ -302,7 +302,7 @@
 
 } // extern "C"
 
-static JNINativeMethod gPerfMeasurementMethods[] = {
+static const JNINativeMethod gPerfMeasurementMethods[] = {
     { "nativeCreateContext",
       "(I)J",
       (jlong *)PerfMeasurement_nativeCreateContext },
diff --git a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
index 470c5ba..4b279f63 100644
--- a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
+++ b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
@@ -275,7 +275,7 @@
 }
 
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
     // {"name", "signature", (void*) functionPointer },
     { "nativeClassInit", "()V", (void*) class_init },
     { "nativeInitialize", "()V", (void*) initialize },
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 6c2bbd4..b977e37 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -682,7 +682,7 @@
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     // name,               signature,  funcPtr
     {"native_start",         "(II)I",    (void *)android_media_AudioRecord_start},
     {"native_stop",          "()V",    (void *)android_media_AudioRecord_stop},
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 91b3278..6d3c7d7 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1616,7 +1616,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"setParameters",        "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
     {"getParameters",        "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
     {"muteMicrophone",      "(Z)I",     (void *)android_media_AudioSystem_muteMicrophone},
@@ -1663,7 +1663,7 @@
 };
 
 
-static JNINativeMethod gEventHandlerMethods[] = {
+static const JNINativeMethod gEventHandlerMethods[] = {
     {"native_setup",
         "(Ljava/lang/Object;)V",
         (void *)android_media_AudioSystem_eventHandlerSetup},
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 5faa150..7860b74 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -1052,7 +1052,7 @@
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     // name,              signature,     funcPtr
     {"native_start",         "()V",      (void *)android_media_AudioTrack_start},
     {"native_stop",          "()V",      (void *)android_media_AudioTrack_stop},
diff --git a/core/jni/android_media_JetPlayer.cpp b/core/jni/android_media_JetPlayer.cpp
index d441f10..873c3f2 100644
--- a/core/jni/android_media_JetPlayer.cpp
+++ b/core/jni/android_media_JetPlayer.cpp
@@ -488,7 +488,7 @@
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     // name,               signature,               funcPtr
     {"native_setup",       "(Ljava/lang/Object;II)Z", (void *)android_media_JetPlayer_setup},
     {"native_finalize",    "()V",                   (void *)android_media_JetPlayer_finalize},
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
index 9bc223b..bd1a6ec 100644
--- a/core/jni/android_media_RemoteDisplay.cpp
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -177,7 +177,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"nativeListen", "(Ljava/lang/String;Ljava/lang/String;)J",
             (void*)nativeListen },
     {"nativeDispose", "(J)V",
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
index 243f040..aec6263 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -123,7 +123,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "startTone", "(II)Z", (void *)android_media_ToneGenerator_startTone },
     { "stopTone", "()V", (void *)android_media_ToneGenerator_stopTone },
     { "getAudioSessionId", "()I", (void *)android_media_ToneGenerator_getAudioSessionId},
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index c137b17..d6d4310 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -495,7 +495,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
      /* name, signature, funcPtr */
     {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
                                                 (void*)socket_connect_local},
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index fada7ac2..ba0876d 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -302,7 +302,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gNetworkUtilMethods[] = {
+static const JNINativeMethod gNetworkUtilMethods[] = {
     /* name, signature, funcPtr */
     { "resetConnections", "(Ljava/lang/String;I)I",  (void *)android_net_utils_resetConnections },
     { "startDhcp", "(Ljava/lang/String;)Z",  (void *)android_net_utils_startDhcp },
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index 7354417..7b7d0cf 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -185,7 +185,7 @@
     }
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"nativeGetTotalStat", "(I)J", (void*) getTotalStat},
     {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*) getIfaceStat},
     {"nativeGetUidStat", "(II)J", (void*) getUidStat},
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 9f5b3bc..568473c 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -1231,7 +1231,7 @@
 
 static const char *classPathName = "android/opengl/EGL14";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"eglGetError", "()I", (void *) android_eglGetError },
 {"eglGetDisplay", "(I)Landroid/opengl/EGLDisplay;", (void *) android_eglGetDisplayInt },
diff --git a/core/jni/android_opengl_EGLExt.cpp b/core/jni/android_opengl_EGLExt.cpp
index 60a3bf6..62ccad4 100644
--- a/core/jni/android_opengl_EGLExt.cpp
+++ b/core/jni/android_opengl_EGLExt.cpp
@@ -149,7 +149,7 @@
 
 static const char *classPathName = "android/opengl/EGLExt";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"eglPresentationTimeANDROID", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSurface;J)Z", (void *) android_eglPresentationTimeANDROID },
 };
diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp
index dac98de..f4135c2 100644
--- a/core/jni/android_opengl_GLES10.cpp
+++ b/core/jni/android_opengl_GLES10.cpp
@@ -3184,7 +3184,7 @@
 
 static const char *classPathName = "android/opengl/GLES10";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I },
 {"glAlphaFunc", "(IF)V", (void *) android_glAlphaFunc__IF },
diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp
index 95be11b..4dc4233 100644
--- a/core/jni/android_opengl_GLES10Ext.cpp
+++ b/core/jni/android_opengl_GLES10Ext.cpp
@@ -582,7 +582,7 @@
 
 static const char *classPathName = "android/opengl/GLES10Ext";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glQueryMatrixxOES", "([II[II)I", (void *) android_glQueryMatrixxOES___3II_3II },
 {"glQueryMatrixxOES", "(Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;)I", (void *) android_glQueryMatrixxOES__Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 },
diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index 6970a3c..2625e03 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -3065,7 +3065,7 @@
 
 static const char *classPathName = "android/opengl/GLES11";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glBindBuffer", "(II)V", (void *) android_glBindBuffer__II },
 {"glBufferData", "(IILjava/nio/Buffer;I)V", (void *) android_glBufferData__IILjava_nio_Buffer_2I },
diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp
index 6422ff2..fb85cb0 100644
--- a/core/jni/android_opengl_GLES11Ext.cpp
+++ b/core/jni/android_opengl_GLES11Ext.cpp
@@ -3573,7 +3573,7 @@
 
 static const char *classPathName = "android/opengl/GLES11Ext";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glBlendEquationSeparateOES", "(II)V", (void *) android_glBlendEquationSeparateOES__II },
 {"glBlendFuncSeparateOES", "(IIII)V", (void *) android_glBlendFuncSeparateOES__IIII },
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index f9a0dfe..b9f61a9 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -6152,7 +6152,7 @@
 
 static const char *classPathName = "android/opengl/GLES20";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I },
 {"glAttachShader", "(II)V", (void *) android_glAttachShader__II },
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index 1d92cd4..8eb5044 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -5167,7 +5167,7 @@
 
 static const char *classPathName = "android/opengl/GLES30";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glReadBuffer", "(I)V", (void *) android_glReadBuffer__I },
 {"glDrawRangeElements", "(IIIIILjava/nio/Buffer;)V", (void *) android_glDrawRangeElements__IIIIILjava_nio_Buffer_2 },
diff --git a/core/jni/android_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp
index 92ecbe0..e427388 100644
--- a/core/jni/android_opengl_GLES31.cpp
+++ b/core/jni/android_opengl_GLES31.cpp
@@ -3175,7 +3175,7 @@
 
 static const char *classPathName = "android/opengl/GLES31";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glDispatchCompute", "(III)V", (void *) android_glDispatchCompute__III },
 {"glDispatchComputeIndirect", "(J)V", (void *) android_glDispatchComputeIndirect },
diff --git a/core/jni/android_opengl_GLES31Ext.cpp b/core/jni/android_opengl_GLES31Ext.cpp
index 2856308..180c693 100644
--- a/core/jni/android_opengl_GLES31Ext.cpp
+++ b/core/jni/android_opengl_GLES31Ext.cpp
@@ -1443,7 +1443,7 @@
 
 static const char *classPathName = "android/opengl/GLES31Ext";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glBlendBarrierKHR", "()V", (void *) android_glBlendBarrierKHR__ },
 {"glDebugMessageControlKHR", "(IIII[IIZ)V", (void *) android_glDebugMessageControlKHR__IIII_3IIZ },
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index b969477..097bbac 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -973,7 +973,7 @@
  * JNI registration.
  */
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "getNativeHeapSize",      "()J",
             (void*) android_os_Debug_getNativeHeapSize },
     { "getNativeHeapAllocatedSize", "()J",
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index d2db3c9..e57a719 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -209,7 +209,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMessageQueueMethods[] = {
+static const JNINativeMethod gMessageQueueMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit },
     { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy },
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index 762b88f..8ba77ae 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -320,7 +320,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     /* name,                     signature,                    funcPtr */
     { "checkSELinuxAccess"       , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess },
     { "getContext"               , "()Ljava/lang/String;"                         , (void*)getCon           },
diff --git a/core/jni/android_os_SystemClock.cpp b/core/jni/android_os_SystemClock.cpp
index dfe024e..d98407d 100644
--- a/core/jni/android_os_SystemClock.cpp
+++ b/core/jni/android_os_SystemClock.cpp
@@ -104,7 +104,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "uptimeMillis",      "()J",
             (void*) android_os_SystemClock_uptimeMillis },
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index 554d304..5dace6b 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -220,7 +220,7 @@
     }
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
       (void*) SystemProperties_getS },
     { "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index 3fd3b3c..30fc47b 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -105,7 +105,7 @@
     atrace_set_tracing_enabled(enabled);
 }
 
-static JNINativeMethod gTraceMethods[] = {
+static const JNINativeMethod gTraceMethods[] = {
     /* name, signature, funcPtr */
     { "nativeGetEnabledTags",
             "()J",
diff --git a/core/jni/android_os_UEventObserver.cpp b/core/jni/android_os_UEventObserver.cpp
index eb36f85..30d40a2 100644
--- a/core/jni/android_os_UEventObserver.cpp
+++ b/core/jni/android_os_UEventObserver.cpp
@@ -103,7 +103,7 @@
     }
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nativeSetup", "()V",
             (void *)nativeSetup },
     { "nativeWaitForNextEvent", "()Ljava/lang/String;",
diff --git a/core/jni/android_server_NetworkManagementSocketTagger.cpp b/core/jni/android_server_NetworkManagementSocketTagger.cpp
index ca21fd7..818bf53 100644
--- a/core/jni/android_server_NetworkManagementSocketTagger.cpp
+++ b/core/jni/android_server_NetworkManagementSocketTagger.cpp
@@ -83,7 +83,7 @@
   return (jint)res;
 }
 
-static JNINativeMethod gQTagUidMethods[] = {
+static const JNINativeMethod gQTagUidMethods[] = {
   { "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*)QTagUid_tagSocketFd},
   { "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*)QTagUid_untagSocketFd},
   { "native_setCounterSet", "(II)I", (void*)QTagUid_setCounterSet},
diff --git a/core/jni/android_text_AndroidBidi.cpp b/core/jni/android_text_AndroidBidi.cpp
index 3285429..2a3f036 100644
--- a/core/jni/android_text_AndroidBidi.cpp
+++ b/core/jni/android_text_AndroidBidi.cpp
@@ -56,7 +56,7 @@
     return result;
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
         { "runBidi", "(I[C[BIZ)I", (void*) runBidi }
 };
 
diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp
index 9258248..474a74e 100644
--- a/core/jni/android_text_AndroidCharacter.cpp
+++ b/core/jni/android_text_AndroidCharacter.cpp
@@ -178,7 +178,7 @@
     return u_charMirror(c);
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
 	{ "getDirectionalities", "([C[BI)V",
         (void*) getDirectionalities },
 	{ "getEastAsianWidth", "(C)I",
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 90e4bb6..a151e00 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -172,7 +172,7 @@
     env->SetFloatArrayRegion(widths, 0, b->size(), b->charWidths());
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     // TODO performance: many of these are candidates for fast jni, awaiting guidance
     {"nNewBuilder", "()J", (void*) nNewBuilder},
     {"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 7ca0654..614e82f 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -2112,7 +2112,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gAssetManagerMethods[] = {
+static const JNINativeMethod gAssetManagerMethods[] = {
     /* name, signature, funcPtr */
 
     // Basic asset stuff.
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 05bc125..4f8a2cb 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -249,7 +249,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gRegisterMethods[] = {
+static const JNINativeMethod gRegisterMethods[] = {
     /* name, signature, funcPtr */
     { "writeEvent", "(II)I", (void*) android_util_EventLog_writeEvent_Integer },
     { "writeEvent", "(IJ)I", (void*) android_util_EventLog_writeEvent_Long },
diff --git a/core/jni/android_util_FileObserver.cpp b/core/jni/android_util_FileObserver.cpp
index 067d298..2b93b6d 100644
--- a/core/jni/android_util_FileObserver.cpp
+++ b/core/jni/android_util_FileObserver.cpp
@@ -127,7 +127,7 @@
 #endif
 }
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     { "init", "()I", (void*)android_os_fileobserver_init },
     { "observe", "(I)V", (void*)android_os_fileobserver_observe },
diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp
index 2b1067b..2d23cda 100644
--- a/core/jni/android_util_Log.cpp
+++ b/core/jni/android_util_Log.cpp
@@ -111,7 +111,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "isLoggable",      "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
     { "println_native",  "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp
index f83eaec..b396afe 100644
--- a/core/jni/android_util_StringBlock.cpp
+++ b/core/jni/android_util_StringBlock.cpp
@@ -155,7 +155,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gStringBlockMethods[] = {
+static const JNINativeMethod gStringBlockMethods[] = {
     /* name, signature, funcPtr */
     { "nativeCreate",      "([BII)J",
             (void*) android_content_StringBlock_nativeCreate },
diff --git a/core/jni/android_util_XmlBlock.cpp b/core/jni/android_util_XmlBlock.cpp
index 375710e..7ae51c8 100644
--- a/core/jni/android_util_XmlBlock.cpp
+++ b/core/jni/android_util_XmlBlock.cpp
@@ -364,7 +364,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gXmlBlockMethods[] = {
+static const JNINativeMethod gXmlBlockMethods[] = {
     /* name, signature, funcPtr */
     { "nativeCreate",               "([BII)J",
             (void*) android_content_XmlBlock_nativeCreate },
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 0e2ec6b..437bd19 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -259,7 +259,7 @@
 }
 
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
             "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;)J",
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index 17d2a5e..7682dd6 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -268,7 +268,7 @@
 
 const char* const kClassPathName = "android/view/GraphicBuffer";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nCreateGraphicBuffer",  "(IIII)J", (void*) android_view_GraphiceBuffer_create },
     { "nDestroyGraphicBuffer", "(J)V",    (void*) android_view_GraphiceBuffer_destroy },
 
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 36ba892..3a0ddc9 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -85,7 +85,7 @@
 
 const char* const kClassPathName = "android/view/HardwareLayer";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nPrepare",                "(JIIZ)Z",    (void*) android_view_HardwareLayer_prepare },
     { "nSetLayerPaint",          "(JJ)V",      (void*) android_view_HardwareLayer_setLayerPaint },
     { "nSetTransform",           "(JJ)V",      (void*) android_view_HardwareLayer_setTransform },
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index 4b42ab5..092ac27 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -259,7 +259,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gInputChannelMethods[] = {
+static const JNINativeMethod gInputChannelMethods[] = {
     /* name, signature, funcPtr */
     { "nativeOpenInputChannelPair", "(Ljava/lang/String;)[Landroid/view/InputChannel;",
             (void*)android_view_InputChannel_nativeOpenInputChannelPair },
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 43b8471..8293cd8 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -395,7 +395,7 @@
 }
 
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
             "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J",
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index d61dee7..3bd6917 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -289,7 +289,7 @@
 }
 
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
             "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J",
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index 7653f58..e5519a7 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -203,7 +203,7 @@
  * JNI registration.
  */
 
-static JNINativeMethod g_methods[] = {
+static const JNINativeMethod g_methods[] = {
     /* name, signature, funcPtr */
     { "nativeReadFromParcel", "(Landroid/os/Parcel;)J",
             (void*)nativeReadFromParcel },
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 98c17c0..81d46c3 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -752,7 +752,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMotionEventMethods[] = {
+static const JNINativeMethod gMotionEventMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInitialize",
             "(JIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index a3b3700..388d365 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -467,7 +467,7 @@
 
 const char* const kClassPathName = "android/view/RenderNode";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nCreate",               "(Ljava/lang/String;)J",    (void*) android_view_RenderNode_create },
     { "nDestroyRenderNode",   "(J)V",   (void*) android_view_RenderNode_destroyRenderNode },
     { "nSetDisplayListData",   "(JJ)V", (void*) android_view_RenderNode_setDisplayListData },
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index 4177ee2..0926e9b 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -193,7 +193,7 @@
 
 const char* const kClassPathName = "android/view/RenderNodeAnimator";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nCreateAnimator", "(IF)J", (void*) createAnimator },
     { "nCreateCanvasPropertyFloatAnimator", "(JF)J", (void*) createCanvasPropertyFloatAnimator },
     { "nCreateCanvasPropertyPaintAnimator", "(JIF)J", (void*) createCanvasPropertyPaintAnimator },
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 4a311d31..24055e7 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -514,7 +514,7 @@
 
 namespace hwui = android::uirenderer;
 
-static JNINativeMethod gSurfaceMethods[] = {
+static const JNINativeMethod gSurfaceMethods[] = {
     {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)J",
             (void*)nativeCreateFromSurfaceTexture },
     {"nativeRelease", "(J)V",
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index d1acb59..65ebb663 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -572,7 +572,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod sSurfaceControlMethods[] = {
+static const JNINativeMethod sSurfaceControlMethods[] = {
     {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)J",
             (void*)nativeCreate },
     {"nativeRelease", "(J)V",
diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp
index 609c565..dad6958 100644
--- a/core/jni/android_view_SurfaceSession.cpp
+++ b/core/jni/android_view_SurfaceSession.cpp
@@ -56,7 +56,7 @@
 }
 
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "nativeCreate", "()J",
             (void*)nativeCreate },
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index beb83b1..b736a17 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -197,7 +197,7 @@
 
 const char* const kClassPathName = "android/view/TextureView";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {   "nCreateNativeWindow", "(Landroid/graphics/SurfaceTexture;)V",
             (void*) android_view_TextureView_createNativeWindow },
     {   "nDestroyNativeWindow", "()V",
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 9a2703b..c79f833 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -484,7 +484,7 @@
 
 const char* const kClassPathName = "android/view/ThreadedRenderer";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V",   (void*) android_view_ThreadedRenderer_setAtlas },
     { "nSetProcessStatsBuffer", "(JI)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer },
     { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp
index ddd5fc8..04ec705 100644
--- a/core/jni/android_view_VelocityTracker.cpp
+++ b/core/jni/android_view_VelocityTracker.cpp
@@ -215,7 +215,7 @@
 
 // --- JNI Registration ---
 
-static JNINativeMethod gVelocityTrackerMethods[] = {
+static const JNINativeMethod gVelocityTrackerMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInitialize",
             "(Ljava/lang/String;)J",
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index daa6f82..364ac44 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -561,7 +561,7 @@
     delete reinterpret_cast<ZipFileRO*>(apkHandle);
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"nativeOpenApk",
             "(Ljava/lang/String;)J",
             (void *)com_android_internal_content_NativeLibraryHelper_openApk},
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 6c0b756..70134ab 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -284,7 +284,7 @@
     return 0;
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
         { "nativeReadNetworkStatsDetail",
                 "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;I)I",
                 (void*) readNetworkStatsDetail }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index aef70be..3f1be456 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -647,7 +647,7 @@
   return pid;
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nativeForkAndSpecialize",
       "(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
       (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
diff --git a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
index 7a18c2d..d20bae2 100644
--- a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
+++ b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
@@ -36,7 +36,7 @@
 
 const char* const kClassPathName = "com/android/internal/util/VirtualRefBasePtr";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nIncStrong", "(J)V", (void*) incStrong },
     { "nDecStrong", "(J)V", (void*) decStrong },
 };
diff --git a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
index 2c65d62..6781e13 100644
--- a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
+++ b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
@@ -78,7 +78,7 @@
 
 const char* const kClassPathName = "com/android/internal/view/animation/NativeInterpolatorFactoryHelper";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "createAccelerateDecelerateInterpolator", "()J", (void*) createAccelerateDecelerateInterpolator },
     { "createAccelerateInterpolator", "(F)J", (void*) createAccelerateInterpolator },
     { "createAnticipateInterpolator", "(F)J", (void*) createAnticipateInterpolator },
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index baeb7dd..3d63b01 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -532,7 +532,7 @@
 #define OBJECT  "Ljava/lang/Object;"
 #define STRING  "Ljava/lang/String;"
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit","()V", (void*)nativeClassInit },
 {"eglWaitGL",       "()Z", (void*)jni_eglWaitGL },
 {"eglInitialize",   "(" DISPLAY "[I)Z", (void*)jni_eglInitialize },
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index f15f957..ad7d744 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -8490,7 +8490,7 @@
 
 static const char *classPathName = "com/google/android/gles_jni/GLImpl";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I },
 {"glAlphaFunc", "(IF)V", (void *) android_glAlphaFunc__IF },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 664e621..28dac39 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -188,7 +188,7 @@
     <protected-broadcast android:name="android.hardware.usb.action.USB_STATE" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_PORT_CHANGED" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
-    <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+    <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_DETACHED" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
 
diff --git a/core/res/res/color/btn_colored_material.xml b/core/res/res/color/btn_colored_background_material.xml
similarity index 87%
rename from core/res/res/color/btn_colored_material.xml
rename to core/res/res/color/btn_colored_background_material.xml
index b45f824..b7f0ef5 100644
--- a/core/res/res/color/btn_colored_material.xml
+++ b/core/res/res/color/btn_colored_background_material.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
      limitations under the License.
 -->
 
+<!-- Used for tha background of a bordered colored button. -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?attr/disabledAlpha"
diff --git a/core/res/res/color/btn_colored_material.xml b/core/res/res/color/btn_colored_borderless_text_material.xml
similarity index 78%
copy from core/res/res/color/btn_colored_material.xml
copy to core/res/res/color/btn_colored_borderless_text_material.xml
index b45f824..ee5a90c 100644
--- a/core/res/res/color/btn_colored_material.xml
+++ b/core/res/res/color/btn_colored_borderless_text_material.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,9 +14,10 @@
      limitations under the License.
 -->
 
+<!-- Used for the text of a borderless colored button. -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?attr/disabledAlpha"
-          android:color="?attr/colorButtonNormal" />
-    <item android:color="?attr/colorAccent" />
+          android:color="?attr/textColorSecondary" />
+    <item android:color="?attr/colorAccent"/>
 </selector>
diff --git a/core/res/res/color/btn_colored_text_material.xml b/core/res/res/color/btn_colored_text_material.xml
index 950d04a..23d05a9 100644
--- a/core/res/res/color/btn_colored_text_material.xml
+++ b/core/res/res/color/btn_colored_text_material.xml
@@ -14,9 +14,10 @@
      limitations under the License.
 -->
 
+<!-- Used for the text of a bordered colored button. -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?attr/disabledAlpha"
           android:color="?attr/textColorSecondary" />
-    <item android:color="?attr/colorAccent"/>
+    <item android:color="?attr/textColorSecondaryInverse" />
 </selector>
diff --git a/core/res/res/drawable/btn_colored_material.xml b/core/res/res/drawable/btn_colored_material.xml
index 81cbe39..c3c5760 100644
--- a/core/res/res/drawable/btn_colored_material.xml
+++ b/core/res/res/drawable/btn_colored_material.xml
@@ -22,7 +22,7 @@
     <ripple android:color="?attr/colorControlHighlight">
         <item>
             <shape android:shape="rectangle"
-                   android:tint="@color/btn_colored_material">
+                   android:tint="@color/btn_colored_background_material">
                 <corners android:radius="@dimen/control_corner_material" />
                 <solid android:color="@color/white" />
                 <padding android:left="@dimen/button_padding_horizontal_material"
diff --git a/core/res/res/layout/number_picker_material.xml b/core/res/res/layout/number_picker_material.xml
index 47edec4..b045585 100644
--- a/core/res/res/layout/number_picker_material.xml
+++ b/core/res/res/layout/number_picker_material.xml
@@ -22,4 +22,4 @@
       android:gravity="center"
       android:singleLine="true"
       android:background="@null"
-      android:textAppearance="@style/TextAppearance.Material.Caption" />
+      android:textAppearance="@style/TextAppearance.Material.Body1" />
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 5dc14e3..611b171 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -471,6 +471,7 @@
     <style name="Widget.Material.Button.Colored">
         <item name="background">@drawable/btn_colored_material</item>
         <item name="textAppearance">@style/TextAppearance.Material.Widget.Button.Inverse</item>
+        <item name="textColor">@color/btn_colored_text_material</item>
     </style>
 
     <!-- Small bordered ink button -->
@@ -487,7 +488,7 @@
 
     <!-- Colored borderless ink button -->
     <style name="Widget.Material.Button.Borderless.Colored">
-        <item name="textColor">@color/btn_colored_text_material</item>
+        <item name="textColor">@color/btn_colored_borderless_text_material</item>
     </style>
 
     <!-- Alert dialog button bar button -->
diff --git a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
index e0b616c..3e83010 100644
--- a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
+++ b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
@@ -22,7 +22,7 @@
     return 1;
 }
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
     { "checkFunction", "()I", (void*) checkFunction },
 };
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index b37688f..ce9ae02 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -17,6 +17,9 @@
 package android.widget;
 
 import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
+import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
+import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
+import static android.widget.espresso.TextViewAssertions.hasSelection;
 import static android.support.test.espresso.Espresso.onView;
 import static android.support.test.espresso.action.ViewActions.click;
 import static android.support.test.espresso.action.ViewActions.pressKey;
@@ -63,4 +66,28 @@
         onView(withId(R.id.textview)).perform(pressKey(KeyEvent.KEYCODE_FORWARD_DEL));
         onView(withId(R.id.textview)).check(matches(withText("Hello orld!")));
     }
+
+    @SmallTest
+    public void testLongPressAndDragToSelect() throws Exception {
+        getActivity();
+
+        final String helloWorld = "Hello little handsome boy!";
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(
+                longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!")));
+
+        onView(withId(R.id.textview)).check(hasSelection("little handsome"));
+    }
+
+    @SmallTest
+    public void testDoubleTapAndDragToSelect() throws Exception {
+        getActivity();
+
+        final String helloWorld = "Hello young beautiful girl!";
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(
+                doubleTapAndDragOnText(helloWorld.indexOf("young"), helloWorld.indexOf(" girl!")));
+
+        onView(withId(R.id.textview)).check(hasSelection("young beautiful"));
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java b/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java
new file mode 100644
index 0000000..a0cd848
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.widget.espresso;
+
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static org.hamcrest.Matchers.allOf;
+
+import android.annotation.Nullable;
+import android.os.SystemClock;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.PerformException;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.CoordinatesProvider;
+import android.support.test.espresso.action.GeneralClickAction;
+import android.support.test.espresso.action.MotionEvents;
+import android.support.test.espresso.action.PrecisionDescriber;
+import android.support.test.espresso.action.Press;
+import android.support.test.espresso.action.Swiper;
+import android.support.test.espresso.action.Tap;
+import android.support.test.espresso.util.HumanReadables;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.TextView;
+import org.hamcrest.Matcher;
+
+
+/**
+ * Drags on text in a TextView using touch events.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView displayed on screen
+ * <ul>
+ */
+public final class DragOnTextViewActions implements ViewAction {
+
+    /**
+     * Executes different "drag on text" types to given positions.
+     */
+    public enum Drag implements Swiper {
+
+        /**
+         * Starts a drag with a long-press.
+         */
+        LONG_PRESS {
+            private DownMotionPerformer downMotion = new DownMotionPerformer() {
+                @Override
+                public MotionEvent perform(
+                        UiController uiController, float[] coordinates, float[] precision) {
+                    MotionEvent downEvent = MotionEvents.sendDown(
+                            uiController, coordinates, precision)
+                            .down;
+                    // Duration before a press turns into a long press.
+                    // Factor 1.5 is needed, otherwise a long press is not safely detected.
+                    // See android.test.TouchUtils longClickView
+                    long longPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f);
+                    uiController.loopMainThreadForAtLeast(longPressTimeout);
+                    return downEvent;
+                }
+            };
+
+            @Override
+            public Status sendSwipe(
+                    UiController uiController,
+                    float[] startCoordinates, float[] endCoordinates, float[] precision) {
+                return sendLinearDrag(
+                        uiController, downMotion, startCoordinates, endCoordinates, precision);
+            }
+
+            @Override
+            public String toString() {
+                return "long press and drag to select";
+            }
+        },
+
+        /**
+         * Starts a drag with a double-tap.
+         */
+        DOUBLE_TAP {
+            private DownMotionPerformer downMotion = new DownMotionPerformer() {
+                @Override
+                @Nullable
+                public MotionEvent perform(
+                        UiController uiController,  float[] coordinates, float[] precision) {
+                    MotionEvent downEvent = MotionEvents.sendDown(
+                            uiController, coordinates, precision)
+                            .down;
+                    try {
+                        if (!MotionEvents.sendUp(uiController, downEvent)) {
+                            String logMessage = "Injection of up event as part of the double tap " +
+                                    "failed. Sending cancel event.";
+                            Log.d(TAG, logMessage);
+                            MotionEvents.sendCancel(uiController, downEvent);
+                            return null;
+                        }
+
+                        long doubleTapMinimumTimeout = ViewConfiguration.getDoubleTapMinTime();
+                        uiController.loopMainThreadForAtLeast(doubleTapMinimumTimeout);
+
+                        return MotionEvents.sendDown(uiController, coordinates, precision).down;
+                    } finally {
+                        downEvent.recycle();
+                    }
+                }
+            };
+
+            @Override
+            public Status sendSwipe(
+                    UiController uiController,
+                    float[] startCoordinates, float[] endCoordinates, float[] precision) {
+                return sendLinearDrag(
+                        uiController, downMotion, startCoordinates, endCoordinates, precision);
+            }
+
+            @Override
+            public String toString() {
+                return "double-tap and drag to select";
+            }
+        };
+
+        private static final String TAG = Drag.class.getSimpleName();
+
+        /** The number of move events to send for each drag. */
+        private static final int DRAG_STEP_COUNT = 10;
+
+        /** Length of time a drag should last for, in milliseconds. */
+        private static final int DRAG_DURATION = 1500;
+
+        private static Status sendLinearDrag(
+                UiController uiController, DownMotionPerformer downMotion,
+                float[] startCoordinates, float[] endCoordinates, float[] precision) {
+            float[][] steps = interpolate(startCoordinates, endCoordinates);
+            final int delayBetweenMovements = DRAG_DURATION / steps.length;
+
+            MotionEvent downEvent = downMotion.perform(uiController, startCoordinates, precision);
+            if (downEvent == null) {
+                return Status.FAILURE;
+            }
+
+            try {
+                for (int i = 0; i < steps.length; i++) {
+                    if (!MotionEvents.sendMovement(uiController, downEvent, steps[i])) {
+                        String logMessage = "Injection of move event as part of the drag failed. " +
+                                "Sending cancel event.";
+                        Log.e(TAG, logMessage);
+                        MotionEvents.sendCancel(uiController, downEvent);
+                        return Status.FAILURE;
+                    }
+
+                    long desiredTime = downEvent.getDownTime() + delayBetweenMovements * i;
+                    long timeUntilDesired = desiredTime - SystemClock.uptimeMillis();
+                    if (timeUntilDesired > 10) {
+                        // If the wait time until the next event isn't long enough, skip the wait
+                        // and execute the next event.
+                        uiController.loopMainThreadForAtLeast(timeUntilDesired);
+                    }
+                }
+
+                if (!MotionEvents.sendUp(uiController, downEvent, endCoordinates)) {
+                    String logMessage = "Injection of up event as part of the drag failed. " +
+                            "Sending cancel event.";
+                    Log.e(TAG, logMessage);
+                    MotionEvents.sendCancel(uiController, downEvent);
+                    return Status.FAILURE;
+                }
+            } finally {
+                downEvent.recycle();
+            }
+            return Status.SUCCESS;
+        }
+
+        private static float[][] interpolate(float[] start, float[] end) {
+            float[][] res = new float[DRAG_STEP_COUNT][2];
+
+            for (int i = 1; i < DRAG_STEP_COUNT + 1; i++) {
+                res[i - 1][0] = start[0] + (end[0] - start[0]) * i / (DRAG_STEP_COUNT + 2f);
+                res[i - 1][1] = start[1] + (end[1] - start[1]) * i / (DRAG_STEP_COUNT + 2f);
+            }
+
+            return res;
+        }
+    }
+
+    /**
+     * Interface to implement different "down motion" types.
+     */
+    private interface DownMotionPerformer {
+        /**
+         * Performs and returns a down motion.
+         *
+         * @param uiController a UiController to use to send MotionEvents to the screen.
+         * @param coordinates a float[] with x and y values of center of the tap.
+         * @param precision  a float[] with x and y values of precision of the tap.
+         * @return the down motion event or null if the down motion event failed.
+         */
+        @Nullable
+        MotionEvent perform(UiController uiController, float[] coordinates, float[] precision);
+    }
+
+    private final Swiper mDragger;
+    private final CoordinatesProvider mStartCoordinatesProvider;
+    private final CoordinatesProvider mEndCoordinatesProvider;
+    private final PrecisionDescriber mPrecisionDescriber;
+
+    public DragOnTextViewActions(
+            Swiper dragger,
+            CoordinatesProvider startCoordinatesProvider,
+            CoordinatesProvider endCoordinatesProvider,
+            PrecisionDescriber precisionDescriber) {
+        mDragger = checkNotNull(dragger);
+        mStartCoordinatesProvider = checkNotNull(startCoordinatesProvider);
+        mEndCoordinatesProvider = checkNotNull(endCoordinatesProvider);
+        mPrecisionDescriber = checkNotNull(precisionDescriber);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Matcher<View> getConstraints() {
+        return allOf(isCompletelyDisplayed(), isAssignableFrom(TextView.class));
+    }
+
+    @Override
+    public void perform(UiController uiController, View view) {
+        checkNotNull(uiController);
+        checkNotNull(view);
+
+        float[] startCoordinates = mStartCoordinatesProvider.calculateCoordinates(view);
+        float[] endCoordinates = mEndCoordinatesProvider.calculateCoordinates(view);
+        float[] precision = mPrecisionDescriber.describePrecision();
+
+        Swiper.Status status;
+
+        try {
+            status = mDragger.sendSwipe(
+                    uiController, startCoordinates, endCoordinates, precision);
+        } catch (RuntimeException re) {
+            throw new PerformException.Builder()
+                    .withActionDescription(this.getDescription())
+                    .withViewDescription(HumanReadables.describe(view))
+                    .withCause(re)
+                    .build();
+        }
+
+        int duration = ViewConfiguration.getPressedStateDuration();
+        // ensures that all work enqueued to process the swipe has been run.
+        if (duration > 0) {
+            uiController.loopMainThreadForAtLeast(duration);
+        }
+
+        if (status == Swiper.Status.FAILURE) {
+            throw new PerformException.Builder()
+                    .withActionDescription(getDescription())
+                    .withViewDescription(HumanReadables.describe(view))
+                    .withCause(new RuntimeException(getDescription() + " failed"))
+                    .build();
+        }
+    }
+
+    @Override
+    public String getDescription() {
+        return mDragger.toString();
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 425dccd..7e4735b 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -18,7 +18,6 @@
 
 import static android.support.test.espresso.action.ViewActions.actionWithAssertions;
 
-import android.content.res.Resources;
 import android.support.test.espresso.PerformException;
 import android.support.test.espresso.ViewAction;
 import android.support.test.espresso.action.CoordinatesProvider;
@@ -27,8 +26,6 @@
 import android.support.test.espresso.action.Tap;
 import android.support.test.espresso.util.HumanReadables;
 import android.text.Layout;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
 import android.view.View;
 import android.widget.TextView;
 
@@ -40,12 +37,14 @@
     private TextViewActions() {}
 
     /**
-     * Returns an action that clicks on text at an index on the text view.<br>
+     * Returns an action that clicks on text at an index on the TextView.<br>
      * <br>
      * View constraints:
      * <ul>
-     * <li>must be a text view displayed on screen
+     * <li>must be a TextView displayed on screen
      * <ul>
+     *
+     * @param index The index of the TextView's text to click on.
      */
     public static ViewAction clickOnTextAtIndex(int index) {
         return actionWithAssertions(
@@ -53,6 +52,48 @@
     }
 
     /**
+     * Returns an action that long presses then drags on text from startIndex to endIndex on the
+     * TextView.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a TextView displayed on screen
+     * <ul>
+     *
+     * @param startIndex The index of the TextView's text to start a drag from
+     * @param endIndex The index of the TextView's text to end the drag at
+     */
+    public static ViewAction longPressAndDragOnText(int startIndex, int endIndex) {
+        return actionWithAssertions(
+                new DragOnTextViewActions(
+                        DragOnTextViewActions.Drag.LONG_PRESS,
+                        new TextCoordinates(startIndex),
+                        new TextCoordinates(endIndex),
+                        Press.FINGER));
+    }
+
+    /**
+     * Returns an action that double taps then drags on text from startIndex to endIndex on the
+     * TextView.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a TextView displayed on screen
+     * <ul>
+     *
+     * @param startIndex The index of the TextView's text to start a drag from
+     * @param endIndex The index of the TextView's text to end the drag at
+     */
+    public static ViewAction doubleTapAndDragOnText(int startIndex, int endIndex) {
+        return actionWithAssertions(
+                new DragOnTextViewActions(
+                        DragOnTextViewActions.Drag.DOUBLE_TAP,
+                        new TextCoordinates(startIndex),
+                        new TextCoordinates(endIndex),
+                        Press.FINGER));
+    }
+
+    /**
      * A provider of the x, y coordinates of the text at the specified index in a text view.
      */
     private static final class TextCoordinates implements CoordinatesProvider {
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
new file mode 100644
index 0000000..dce3182
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.widget.espresso;
+
+import static android.support.test.espresso.matcher.ViewMatchers.assertThat;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static org.hamcrest.Matchers.is;
+
+import android.support.test.espresso.NoMatchingViewException;
+import android.support.test.espresso.ViewAssertion;
+import android.view.View;
+import android.widget.TextView;
+
+import junit.framework.AssertionFailedError;
+import org.hamcrest.Matcher;
+
+/**
+ * A collection of assertions on a {@link android.widget.TextView}.
+ */
+public final class TextViewAssertions {
+
+    private TextViewAssertions() {}
+
+    /**
+     * Returns a {@link ViewAssertion} that asserts that the text view has a specified
+     * selection.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a text view displayed on screen
+     * <ul>
+     *
+     * @param selection  The expected selection.
+     */
+    public static ViewAssertion hasSelection(String selection) {
+        return new TextSelectionAssertion(is(selection));
+    }
+
+    /**
+     * Returns a {@link ViewAssertion} that asserts that the text view has a specified
+     * selection.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a text view displayed on screen
+     * <ul>
+     *
+     * @param selection  A matcher representing the expected selection.
+     */
+    public static ViewAssertion hasSelection(Matcher<String> selection) {
+        return new TextSelectionAssertion(selection);
+    }
+
+    /**
+     * A {@link ViewAssertion} to check the selected text in a {@link TextView}.
+     */
+    private static final class TextSelectionAssertion implements ViewAssertion {
+
+        private final Matcher<String> mSelection;
+
+        public TextSelectionAssertion(Matcher<String> selection) {
+            mSelection = checkNotNull(selection);
+        }
+
+        @Override
+        public void check(View view, NoMatchingViewException exception) {
+            if (view instanceof TextView) {
+                TextView textView = (TextView) view;
+                int selectionStart = textView.getSelectionStart();
+                int selectionEnd = textView.getSelectionEnd();
+                try {
+                    String selectedText = textView.getText()
+                            .subSequence(selectionStart, selectionEnd)
+                            .toString();
+                    assertThat(selectedText, mSelection);
+                } catch (IndexOutOfBoundsException e) {
+                    throw new AssertionFailedError(e.getMessage());
+                }
+            } else {
+                throw new AssertionFailedError("TextView not found");
+            }
+        }
+    }
+}
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
index 4c16154..67b12d7 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
@@ -30,7 +30,7 @@
 
 static const char *classPathName = "com/framework/shareduid/bit32/Native";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
   {"add", "(II)I", (void*)add },
 };
 
@@ -38,7 +38,7 @@
  * Register several native methods for one class.
  */
 static int registerNativeMethods(JNIEnv* env, const char* className,
-    JNINativeMethod* gMethods, int numMethods)
+    const JNINativeMethod* gMethods, int numMethods)
 {
     jclass clazz;
 
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
index c2f9f529..342b3bc 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
@@ -30,7 +30,7 @@
 
 static const char *classPathName = "com/framework/shareduid/bit64/Native";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
   {"add", "(II)I", (void*)add },
 };
 
@@ -38,7 +38,7 @@
  * Register several native methods for one class.
  */
 static int registerNativeMethods(JNIEnv* env, const char* className,
-    JNINativeMethod* gMethods, int numMethods)
+    const JNINativeMethod* gMethods, int numMethods)
 {
     jclass clazz;
 
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
index 5d3ca06..9b38e3e 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
@@ -30,7 +30,7 @@
 
 static const char *classPathName = "com/framework/shareduid/dual/Native";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
   {"add", "(II)I", (void*)add },
 };
 
@@ -38,7 +38,7 @@
  * Register several native methods for one class.
  */
 static int registerNativeMethods(JNIEnv* env, const char* className,
-    JNINativeMethod* gMethods, int numMethods)
+    const JNINativeMethod* gMethods, int numMethods)
 {
     jclass clazz;
 
diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp
index 52597e1..63fe8ac 100644
--- a/drm/jni/android_drm_DrmManagerClient.cpp
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -702,7 +702,7 @@
     return status;
 }
 
-static JNINativeMethod nativeMethods[] = {
+static const JNINativeMethod nativeMethods[] = {
 
     {"_initialize", "()I",
                                     (void*)android_drm_DrmManagerClient_initialize},
diff --git a/media/jni/android_media_AmrInputStream.cpp b/media/jni/android_media_AmrInputStream.cpp
index afb5d5c..b56a364 100644
--- a/media/jni/android_media_AmrInputStream.cpp
+++ b/media/jni/android_media_AmrInputStream.cpp
@@ -119,7 +119,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"GsmAmrEncoderNew",        "()J",        (void*)android_media_AmrInputStream_GsmAmrEncoderNew},
     {"GsmAmrEncoderInitialize", "(J)V",       (void*)android_media_AmrInputStream_GsmAmrEncoderInitialize},
     {"GsmAmrEncoderEncode",     "(J[BI[BI)I", (void*)android_media_AmrInputStream_GsmAmrEncoderEncode},
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 0034b07..3ffdb17 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -1253,7 +1253,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gImageReaderMethods[] = {
+static const JNINativeMethod gImageReaderMethods[] = {
     {"nativeClassInit",        "()V",                        (void*)ImageReader_classInit },
     {"nativeInit",             "(Ljava/lang/Object;IIII)V",  (void*)ImageReader_init },
     {"nativeClose",            "()V",                        (void*)ImageReader_close },
@@ -1263,7 +1263,7 @@
     {"nativeDetachImage",      "(Landroid/media/Image;)I",   (void*)ImageReader_detachImage },
 };
 
-static JNINativeMethod gImageMethods[] = {
+static const JNINativeMethod gImageMethods[] = {
     {"nativeImageGetBuffer",   "(II)Ljava/nio/ByteBuffer;",   (void*)Image_getByteBuffer },
     {"nativeCreatePlane",      "(II)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
                                                               (void*)Image_createSurfacePlane },
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 93a4426..e8f680f 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -1798,7 +1798,7 @@
     android_media_MediaCodec_release(env, thiz);
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "native_release", "()V", (void *)android_media_MediaCodec_release },
 
     { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 82dd48d..de9bf1f 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -286,7 +286,7 @@
 static void android_media_MediaCodecList_native_init(JNIEnv* /* env */) {
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "native_getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount },
     { "getCodecName", "(I)Ljava/lang/String;",
       (void *)android_media_MediaCodecList_getCodecName },
diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp
index d7968d2..e414f48 100644
--- a/media/jni/android_media_MediaCrypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -316,7 +316,7 @@
     }
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "release", "()V", (void *)android_media_MediaCrypto_release },
     { "native_init", "()V", (void *)android_media_MediaCrypto_native_init },
 
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 9ec0312..275de1ad 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -1455,7 +1455,7 @@
 }
 
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "release", "()V", (void *)android_media_MediaDrm_release },
     { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
 
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 4e9b726..96c12dd 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -769,7 +769,7 @@
     android_media_MediaExtractor_release(env, thiz);
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "release", "()V", (void *)android_media_MediaExtractor_release },
 
     { "getTrackCount", "()I", (void *)android_media_MediaExtractor_getTrackCount },
diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp
index 393003d..fa0b43f 100644
--- a/media/jni/android_media_MediaHTTPConnection.cpp
+++ b/media/jni/android_media_MediaHTTPConnection.cpp
@@ -154,7 +154,7 @@
     return n;
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "native_getIMemory", "()Landroid/os/IBinder;",
       (void *)android_media_MediaHTTPConnection_native_getIMemory },
 
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 59fb6d6..f4e940d 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -467,7 +467,7 @@
 }
 
 // JNI mapping between Java methods and native methods
-static JNINativeMethod nativeMethods[] = {
+static const JNINativeMethod nativeMethods[] = {
         {
             "_setDataSource",
             "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index ecb2ac8..216624e 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -219,7 +219,7 @@
     }
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
 
     { "nativeAddTrack", "(J[Ljava/lang/String;[Ljava/lang/Object;)I",
         (void *)android_media_MediaMuxer_addTrack },
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index d8041f4..be36729 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1033,7 +1033,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {
         "nativeSetDataSource",
         "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp
index ca9db91..5800043 100644
--- a/media/jni/android_media_MediaProfiles.cpp
+++ b/media/jni/android_media_MediaProfiles.cpp
@@ -301,7 +301,7 @@
     }
     return static_cast<jint>(levels[index]);
 }
-static JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = {
+static const JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = {
     {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},
     {"native_get_num_file_formats",            "()I",                    (void *)android_media_MediaProfiles_native_get_num_file_formats},
     {"native_get_file_format",                 "(I)I",                   (void *)android_media_MediaProfiles_native_get_file_format},
@@ -315,7 +315,7 @@
                                                                          (void *)android_media_MediaProfiles_native_get_audio_encoder_cap},
 };
 
-static JNINativeMethod gMethodsForCamcorderProfileClass[] = {
+static const JNINativeMethod gMethodsForCamcorderProfileClass[] = {
     {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},
     {"native_get_camcorder_profile",           "(II)Landroid/media/CamcorderProfile;",
                                                                          (void *)android_media_MediaProfiles_native_get_camcorder_profile},
@@ -323,7 +323,7 @@
                                                                          (void *)android_media_MediaProfiles_native_has_camcorder_profile},
 };
 
-static JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = {
+static const JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = {
     {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},
     {"native_get_num_video_decoders",          "()I",                    (void *)android_media_MediaProfiles_native_get_num_video_decoders},
     {"native_get_num_audio_decoders",          "()I",                    (void *)android_media_MediaProfiles_native_get_num_audio_decoders},
@@ -331,7 +331,7 @@
     {"native_get_audio_decoder_type",          "(I)I",                   (void *)android_media_MediaProfiles_native_get_audio_decoder_type},
 };
 
-static JNINativeMethod gMethodsForCameraProfileClass[] = {
+static const JNINativeMethod gMethodsForCameraProfileClass[] = {
     {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},
     {"native_get_num_image_encoding_quality_levels",
                                                "(I)I",                   (void *)android_media_MediaProfiles_native_get_num_image_encoding_quality_levels},
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index f60af63..e05b348 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -510,7 +510,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"setCamera",            "(Landroid/hardware/Camera;)V",    (void *)android_media_MediaRecorder_setCamera},
     {"setVideoSource",       "(I)V",                            (void *)android_media_MediaRecorder_setVideoSource},
     {"setAudioSource",       "(I)V",                            (void *)android_media_MediaRecorder_setAudioSource},
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 1a9384e..0f3c61f 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -412,7 +412,7 @@
     setNativeScanner_l(env, thiz, 0);
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {
         "processDirectory",
         "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
diff --git a/media/jni/android_media_ResampleInputStream.cpp b/media/jni/android_media_ResampleInputStream.cpp
index 1549a30..d06baa5 100644
--- a/media/jni/android_media_ResampleInputStream.cpp
+++ b/media/jni/android_media_ResampleInputStream.cpp
@@ -107,7 +107,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"fir21", "([BI[BII)V", (void*)android_media_ResampleInputStream_fir21},
 };
 
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 713f28c..ec2f98a 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -1173,12 +1173,12 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMtpDatabaseMethods[] = {
+static const JNINativeMethod gMtpDatabaseMethods[] = {
     {"native_setup",            "()V",  (void *)android_mtp_MtpDatabase_setup},
     {"native_finalize",         "()V",  (void *)android_mtp_MtpDatabase_finalize},
 };
 
-static JNINativeMethod gMtpPropertyGroupMethods[] = {
+static const JNINativeMethod gMtpPropertyGroupMethods[] = {
     {"format_date_time",        "(J)Ljava/lang/String;",
                                         (void *)android_mtp_MtpPropertyGroup_format_date_time},
 };
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 2a46ee7..f11329c 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -490,7 +490,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"native_open",             "(Ljava/lang/String;I)Z",
                                         (void *)android_mtp_MtpDevice_open},
     {"native_close",            "()V",  (void *)android_mtp_MtpDevice_close},
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index 2ce2a90..d13187c 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -179,7 +179,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"native_setup",                "(Landroid/mtp/MtpDatabase;Z)V",
                                             (void *)android_mtp_MtpServer_setup},
     {"native_run",                  "()V",  (void *)android_mtp_MtpServer_run},
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index aba4bbe..fa69135 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -879,7 +879,7 @@
 // ----------------------------------------------------------------------------
 
 // Dalvik VM type signatures
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"native_init",          "()V",      (void *)android_media_AudioEffect_native_init},
     {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;Ljava/lang/String;)I",
                                          (void *)android_media_AudioEffect_native_setup},
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 0557019..3d3adba 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -677,7 +677,7 @@
 // ----------------------------------------------------------------------------
 
 // Dalvik VM type signatures
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"native_init",            "()V",     (void *)android_media_visualizer_native_init},
     {"native_setup",           "(Ljava/lang/Object;I[ILjava/lang/String;)I",
                                           (void *)android_media_visualizer_native_setup},
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index b02349a..45cb34d 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -17,61 +17,70 @@
 <com.android.documentsui.DirectoryView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@color/material_grey_50">
+    android:background="@color/material_grey_50"
+    android:orientation="vertical"
+    android:animateLayoutChanges="true">
 
-    <TextView
-        android:id="@android:id/empty"
+    <ProgressBar
+        android:id="@+id/progressbar"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:gravity="center"
-        android:text="@string/empty"
-        android:visibility="gone"
-        style="@android:style/TextAppearance.Material.Subhead" />
+        android:layout_height="wrap_content"
+        android:indeterminate="true"
+        style="@style/TrimmedHorizontalProgressBar"
+        android:visibility="gone"/>
+  
+    <FrameLayout
+        android:id="@+id/container_message_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:elevation="8dp"
+        android:background="@color/material_grey_50"
+        android:visibility="gone"/>
 
+    <!-- The empty directory view -->
     <LinearLayout
-        android:id="@+id/content"
+        android:id="@android:id/empty"
+        android:gravity="center"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="vertical"
-        android:animateLayoutChanges="true">
-
-        <ProgressBar
-            android:id="@+id/progressbar"
-            android:layout_width="match_parent"
+        android:visibility="gone">
+        
+        <TextView
+            android:id="@+id/message"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:indeterminate="true"
-            style="@style/TrimmedHorizontalProgressBar"
-            android:visibility="gone"/>
+            android:text="@string/empty"
+            style="@android:style/TextAppearance.Material.Subhead" />
 
-        <FrameLayout
-            android:id="@+id/container_message_bar"
-            android:layout_width="match_parent"
+         <Button
+            android:id="@+id/button_retry"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:elevation="8dp"
-            android:background="@color/material_grey_50"
-            android:visibility="gone"/>
-
-        <!-- This FrameLayout works around b/24189541 -->
-        <FrameLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent">
-
-            <android.support.v7.widget.RecyclerView
-                android:id="@+id/recyclerView"
-                android:scrollbars="vertical"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:paddingStart="@dimen/grid_padding_horiz"
-                android:paddingEnd="@dimen/grid_padding_horiz"
-                android:paddingTop="@dimen/grid_padding_vert"
-                android:paddingBottom="@dimen/grid_padding_vert"
-                android:clipToPadding="false"
-                android:scrollbarStyle="outsideOverlay"
-                android:drawSelectorOnTop="true"
-                android:background="@color/directory_background" />
-
-        </FrameLayout>
-
+            android:text="@string/button_retry"
+            style="?android:attr/buttonBarPositiveButtonStyle" />
+        
     </LinearLayout>
+    
+    <!-- This FrameLayout works around b/24189541 -->
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <android.support.v7.widget.RecyclerView
+            android:id="@+id/recyclerView"
+            android:scrollbars="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:paddingStart="@dimen/grid_padding_horiz"
+            android:paddingEnd="@dimen/grid_padding_horiz"
+            android:paddingTop="@dimen/grid_padding_vert"
+            android:paddingBottom="@dimen/grid_padding_vert"
+            android:clipToPadding="false"
+            android:scrollbarStyle="outsideOverlay"
+            android:drawSelectorOnTop="true"
+            android:background="@color/directory_background" />
+
+    </FrameLayout>
 
 </com.android.documentsui.DirectoryView>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 28018f8e..a12edf3 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -81,7 +81,8 @@
     <string name="button_move">Move</string>
     <!-- Button label that hides the error bar [CHAR LIMIT=24] -->
     <string name="button_dismiss">Dismiss</string>
-
+    <string name="button_retry">Try Again</string>
+    
     <!-- Mode that sorts documents by their display name alphabetically [CHAR LIMIT=24] -->
     <string name="sort_name">By name</string>
     <!-- Mode that sorts documents by their last modified time in descending order; most recent first [CHAR LIMIT=24] -->
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 1585908..c8ec4dc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -33,14 +33,11 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Root;
 import android.support.annotation.LayoutRes;
 import android.support.annotation.Nullable;
 import android.util.Log;
-import android.util.SparseArray;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -67,7 +64,6 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.Executor;
 
@@ -367,129 +363,6 @@
         public static String EXTRA_DIRECTORY_COPY = "com.android.documentsui.DIRECTORY_COPY";
     }
 
-    public static class State implements android.os.Parcelable {
-        public int action;
-        public String[] acceptMimes;
-
-        /** Explicit user choice */
-        public int userMode = MODE_UNKNOWN;
-        /** Derived after loader */
-        public int derivedMode = MODE_LIST;
-
-        /** Explicit user choice */
-        public int userSortOrder = SORT_ORDER_UNKNOWN;
-        /** Derived after loader */
-        public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
-
-        public boolean allowMultiple;
-        public boolean forceSize ;
-        public boolean showSize;
-        public boolean localOnly ;
-        public boolean forceAdvanced ;
-        public boolean showAdvanced ;
-        public boolean stackTouched ;
-        public boolean restored ;
-        public boolean directoryCopy ;
-        /** Transfer mode for file copy/move operations. */
-        public int transferMode;
-
-        /** Current user navigation stack; empty implies recents. */
-        public DocumentStack stack = new DocumentStack();
-        /** Currently active search, overriding any stack. */
-        public String currentSearch;
-
-        /** Instance state for every shown directory */
-        public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
-
-        /** Currently copying file */
-        public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>();
-
-        /** Name of the package that started DocsUI */
-        public List<String> excludedAuthorities = new ArrayList<>();
-
-        public static final int ACTION_OPEN = 1;
-        public static final int ACTION_CREATE = 2;
-        public static final int ACTION_GET_CONTENT = 3;
-        public static final int ACTION_OPEN_TREE = 4;
-        public static final int ACTION_MANAGE = 5;
-        public static final int ACTION_BROWSE = 6;
-        public static final int ACTION_OPEN_COPY_DESTINATION = 8;
-
-        public static final int MODE_UNKNOWN = 0;
-        public static final int MODE_LIST = 1;
-        public static final int MODE_GRID = 2;
-
-        public static final int SORT_ORDER_UNKNOWN = 0;
-        public static final int SORT_ORDER_DISPLAY_NAME = 1;
-        public static final int SORT_ORDER_LAST_MODIFIED = 2;
-        public static final int SORT_ORDER_SIZE = 3;
-
-        public void initAcceptMimes(Intent intent) {
-            if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
-                acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
-            } else {
-                String glob = intent.getType();
-                acceptMimes = new String[] { glob != null ? glob : "*/*" };
-            }
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeInt(action);
-            out.writeInt(userMode);
-            out.writeStringArray(acceptMimes);
-            out.writeInt(userSortOrder);
-            out.writeInt(allowMultiple ? 1 : 0);
-            out.writeInt(forceSize ? 1 : 0);
-            out.writeInt(showSize ? 1 : 0);
-            out.writeInt(localOnly ? 1 : 0);
-            out.writeInt(forceAdvanced ? 1 : 0);
-            out.writeInt(showAdvanced ? 1 : 0);
-            out.writeInt(stackTouched ? 1 : 0);
-            out.writeInt(restored ? 1 : 0);
-            DurableUtils.writeToParcel(out, stack);
-            out.writeString(currentSearch);
-            out.writeMap(dirState);
-            out.writeList(selectedDocumentsForCopy);
-            out.writeList(excludedAuthorities);
-        }
-
-        public static final Creator<State> CREATOR = new Creator<State>() {
-            @Override
-            public State createFromParcel(Parcel in) {
-                final State state = new State();
-                state.action = in.readInt();
-                state.userMode = in.readInt();
-                state.acceptMimes = in.readStringArray();
-                state.userSortOrder = in.readInt();
-                state.allowMultiple = in.readInt() != 0;
-                state.forceSize = in.readInt() != 0;
-                state.showSize = in.readInt() != 0;
-                state.localOnly = in.readInt() != 0;
-                state.forceAdvanced = in.readInt() != 0;
-                state.showAdvanced = in.readInt() != 0;
-                state.stackTouched = in.readInt() != 0;
-                state.restored = in.readInt() != 0;
-                DurableUtils.readFromParcel(in, state.stack);
-                state.currentSearch = in.readString();
-                in.readMap(state.dirState, null);
-                in.readList(state.selectedDocumentsForCopy, null);
-                in.readList(state.excludedAuthorities, null);
-                return state;
-            }
-
-            @Override
-            public State[] newArray(int size) {
-                return new State[size];
-            }
-        };
-    }
-
     void setDisplayAdvancedDevices(boolean display) {
         State state = getDisplayState();
         LocalPreferences.setDisplayAdvancedDevices(this, display);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index f8ec8f1..f1492dc7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -16,6 +16,7 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
 
@@ -56,7 +57,6 @@
 
 public class CopyService extends IntentService {
     public static final String TAG = "CopyService";
-    public static final boolean DEBUG = false;
 
     private static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL";
     public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index ea8ecf5..5eacf21 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -16,14 +16,15 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE;
-import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
-import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
-import static com.android.documentsui.BaseActivity.State.MODE_GRID;
-import static com.android.documentsui.BaseActivity.State.MODE_LIST;
-import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.Shared.TAG;
+import static com.android.documentsui.State.ACTION_BROWSE;
+import static com.android.documentsui.State.ACTION_CREATE;
+import static com.android.documentsui.State.ACTION_MANAGE;
+import static com.android.documentsui.State.MODE_GRID;
+import static com.android.documentsui.State.MODE_LIST;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
@@ -93,7 +94,6 @@
 import android.widget.Toast;
 
 import com.android.documentsui.BaseActivity.DocumentContext;
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.MultiSelectManager.Selection;
 import com.android.documentsui.ProviderExecutor.Preemptable;
 import com.android.documentsui.RecentsProvider.StateColumns;
@@ -124,7 +124,6 @@
     public static final int REQUEST_COPY_DESTINATION = 1;
 
     private static final int LOADER_ID = 42;
-    private static final boolean DEBUG = false;
     private static final boolean DEBUG_ENABLE_DND = false;
 
     private static final String EXTRA_TYPE = "type";
@@ -367,21 +366,6 @@
 
             @Override
             public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
-                if (result == null || result.exception != null) {
-                    // onBackPressed does a fragment transaction, which can't be done inside
-                    // onLoadFinished
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            final Activity activity = getActivity();
-                            if (activity != null) {
-                                activity.onBackPressed();
-                            }
-                        }
-                    });
-                    return;
-                }
-
                 if (!isAdded()) return;
 
                 mModel.update(result);
@@ -629,7 +613,6 @@
 
         @Override
         public void onItemStateChanged(int position, boolean selected) {
-
             final Cursor cursor = mModel.getItem(position);
             checkNotNull(cursor, "Cursor cannot be null.");
 
@@ -715,8 +698,9 @@
                 return true;
 
             } else if (id == R.id.menu_delete) {
-                deleteDocuments(selection);
+                // Exit selection mode first, so we avoid deselecting deleted documents.
                 mode.finish();
+                deleteDocuments(selection);
                 return true;
 
             } else if (id == R.id.menu_copy_to) {
@@ -725,8 +709,9 @@
                 return true;
 
             } else if (id == R.id.menu_move_to) {
-                transferDocuments(selection, CopyService.TRANSFER_MODE_MOVE);
+                // Exit selection mode first, so we avoid deselecting deleted documents.
                 mode.finish();
+                transferDocuments(selection, CopyService.TRANSFER_MODE_MOVE);
                 return true;
 
             } else if (id == R.id.menu_copy_to_clipboard) {
@@ -898,6 +883,29 @@
         }
     }
 
+    void showEmptyView() {
+        mEmptyView.setVisibility(View.VISIBLE);
+        mRecView.setVisibility(View.GONE);
+        TextView msg = (TextView) mEmptyView.findViewById(R.id.message);
+        msg.setText(R.string.empty);
+        // No retry button for the empty view.
+        mEmptyView.findViewById(R.id.button_retry).setVisibility(View.GONE);
+    }
+
+    void showErrorView() {
+        mEmptyView.setVisibility(View.VISIBLE);
+        mRecView.setVisibility(View.GONE);
+        TextView msg = (TextView) mEmptyView.findViewById(R.id.message);
+        msg.setText(R.string.query_error);
+        // TODO: Enable this once the retry button does something.
+        mEmptyView.findViewById(R.id.button_retry).setVisibility(View.GONE);
+    }
+
+    void showRecyclerView() {
+        mEmptyView.setVisibility(View.GONE);
+        mRecView.setVisibility(View.VISIBLE);
+    }
+
     private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> {
 
         private final Context mContext;
@@ -1950,21 +1958,16 @@
             mProgressBar.setVisibility(model.isLoading() ? View.VISIBLE : View.GONE);
 
             if (model.isEmpty()) {
-                mEmptyView.setVisibility(View.VISIBLE);
-                mRecView.setVisibility(View.GONE);
+                showEmptyView();
             } else {
-                mEmptyView.setVisibility(View.GONE);
-                mRecView.setVisibility(View.VISIBLE);
+                showRecyclerView();
+                mAdapter.notifyDataSetChanged();
             }
-
-            mAdapter.notifyDataSetChanged();
         }
 
         @Override
         public void onModelUpdateFailed(Exception e) {
-            // TODO: deal with catastrophic update failures
-            String error = getString(R.string.query_error);
-            mAdapter.notifyDataSetChanged();
+            showErrorView();
         }
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 0edb241..bb82b38 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -16,12 +16,12 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
 import static com.android.documentsui.Shared.TAG;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 
 import android.content.AsyncTaskLoader;
@@ -37,7 +37,6 @@
 import android.provider.DocumentsContract.Document;
 import android.util.Log;
 
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.RecentsProvider.StateColumns;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.RootInfo;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
index 4893652..000b92a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
@@ -18,9 +18,9 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.widget.FrameLayout;
+import android.widget.LinearLayout;
 
-public class DirectoryView extends FrameLayout {
+public class DirectoryView extends LinearLayout {
     private float mPosition = 0f;
 
     private int mWidth;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index dbfcf40..4658fe3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -16,13 +16,12 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
-import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_COPY_DESTINATION;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
-import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
 import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
+import static com.android.documentsui.State.ACTION_CREATE;
+import static com.android.documentsui.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.State.ACTION_OPEN;
+import static com.android.documentsui.State.ACTION_OPEN_COPY_DESTINATION;
+import static com.android.documentsui.State.ACTION_OPEN_TREE;
 
 import android.app.Activity;
 import android.app.Fragment;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
index ec1cb1d..a1213d2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -222,7 +222,7 @@
                 return context.getDrawable(R.drawable.ic_doc_album);
             }
 
-            if (mode == BaseActivity.State.MODE_GRID) {
+            if (mode == State.MODE_GRID) {
                 return context.getDrawable(R.drawable.ic_grid_folder);
             } else {
                 return context.getDrawable(R.drawable.ic_doc_folder);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
index f5b1d8e..4754899 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
@@ -16,9 +16,8 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
-import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
 import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
+import static com.android.documentsui.State.ACTION_MANAGE;
 
 import android.app.Activity;
 import android.app.Fragment;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
index 5f6a5e9..48e28dc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
@@ -21,7 +21,6 @@
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
 import android.os.Bundle;
-import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -29,8 +28,6 @@
 
 import com.android.documentsui.model.DocumentInfo;
 
-import java.util.Locale;
-
 /**
  * Display pick confirmation bar, usually for selecting a directory.
  */
@@ -93,7 +90,7 @@
     };
 
     /**
-     * @param action Which action defined in BaseActivity.State is the picker shown for.
+     * @param action Which action defined in State is the picker shown for.
      */
     public void setPickTarget(int action, int transferMode, DocumentInfo pickTarget) {
         mAction = action;
@@ -109,11 +106,11 @@
      */
     private void updateView() {
         switch (mAction) {
-            case BaseActivity.State.ACTION_OPEN_TREE:
+            case State.ACTION_OPEN_TREE:
                 mPick.setText(R.string.button_select);
                 mCancel.setVisibility(View.GONE);
                 break;
-            case BaseActivity.State.ACTION_OPEN_COPY_DESTINATION:
+            case State.ACTION_OPEN_COPY_DESTINATION:
                 mPick.setText(R.string.button_copy);
                 mCancel.setVisibility(View.VISIBLE);
                 break;
@@ -123,7 +120,7 @@
         }
 
         if (mPickTarget != null && (
-                mAction == BaseActivity.State.ACTION_OPEN_TREE ||
+                mAction == State.ACTION_OPEN_TREE ||
                 mPickTarget.isCreateSupported())) {
             mContainer.setVisibility(View.VISIBLE);
         } else {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
index 4685c41..607cb95 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -16,6 +16,8 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.Shared.TAG;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
 
 import android.content.ClipData;
@@ -38,9 +40,6 @@
  */
 final class QuickViewIntentBuilder {
 
-    private static final String TAG = "QvIntentBuilder";
-    private static final boolean DEBUG = false;
-
     private final DocumentInfo mDocument;
     private final DocumentContext mContext;
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index 1a7095a..c2b64fb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -16,8 +16,9 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.Shared.TAG;
+import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
 
 import android.app.ActivityManager;
 import android.content.AsyncTaskLoader;
@@ -34,7 +35,6 @@
 import android.text.format.DateUtils;
 import android.util.Log;
 
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.RootInfo;
 
 import com.google.common.util.concurrent.AbstractFuture;
@@ -53,8 +53,6 @@
 import java.util.concurrent.TimeUnit;
 
 public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
-    private static final boolean DEBUG = false;
-
     // TODO: clean up cursor ownership so background thread doesn't traverse
     // previously returned cursors for filtering/sorting; this currently races
     // with the UI thread.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index 6811331..cf682fa 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -45,7 +45,6 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.RecentsProvider.RecentColumns;
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.DurableUtils;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index f6e4349..82eb732 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -39,6 +39,7 @@
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.DurableUtils;
 import com.android.internal.util.Predicate;
+
 import com.google.android.collect.Sets;
 
 import libcore.io.IoUtils;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index cb46bca..de35cef 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -16,8 +16,8 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.Shared.TAG;
 import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.Shared.TAG;
 
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
@@ -35,12 +35,11 @@
 import android.os.SystemClock;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Root;
+import android.support.annotation.VisibleForTesting;
 import android.util.Log;
 
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.RootInfo;
 import com.android.internal.annotations.GuardedBy;
-import android.support.annotation.VisibleForTesting;
 
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Multimap;
@@ -372,10 +371,8 @@
             if (state.directoryCopy && root.isDownloads()) continue;
 
             // Only show empty roots when creating, or in browse mode.
-            if (empty && (state.action != State.ACTION_BROWSE ||
-                 state.action != State.ACTION_CREATE ||
-                 state.action != State.ACTION_OPEN_TREE ||
-                 state.action != State.ACTION_OPEN_COPY_DESTINATION)) {
+            if (empty && (state.action == State.ACTION_OPEN
+                    || state.action == State.ACTION_GET_CONTENT)) {
                 if (DEBUG) Log.i(TAG, "Skipping empty root: " + root);
                 continue;
             }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index c02184b..c98da47 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -41,7 +41,6 @@
 import android.widget.ListView;
 import android.widget.TextView;
 
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.RootInfo;
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
index 49651b4..c81377a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
@@ -19,7 +19,6 @@
 import android.content.AsyncTaskLoader;
 import android.content.Context;
 
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.RootInfo;
 
 import java.util.Collection;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
index 3ec3d1c..6698ff1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
@@ -16,9 +16,9 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.State.SORT_ORDER_SIZE;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
new file mode 100644
index 0000000..bbffad3
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.SparseArray;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.DurableUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class State implements android.os.Parcelable {
+    public int action;
+    public String[] acceptMimes;
+
+    /** Explicit user choice */
+    public int userMode = MODE_UNKNOWN;
+    /** Derived after loader */
+    public int derivedMode = MODE_LIST;
+
+    /** Explicit user choice */
+    public int userSortOrder = SORT_ORDER_UNKNOWN;
+    /** Derived after loader */
+    public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
+
+    public boolean allowMultiple;
+    public boolean forceSize ;
+    public boolean showSize;
+    public boolean localOnly ;
+    public boolean forceAdvanced ;
+    public boolean showAdvanced ;
+    public boolean stackTouched ;
+    public boolean restored ;
+    public boolean directoryCopy ;
+    /** Transfer mode for file copy/move operations. */
+    public int transferMode;
+
+    /** Current user navigation stack; empty implies recents. */
+    public DocumentStack stack = new DocumentStack();
+    /** Currently active search, overriding any stack. */
+    public String currentSearch;
+
+    /** Instance state for every shown directory */
+    public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
+
+    /** Currently copying file */
+    public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>();
+
+    /** Name of the package that started DocsUI */
+    public List<String> excludedAuthorities = new ArrayList<>();
+
+    public static final int ACTION_OPEN = 1;
+    public static final int ACTION_CREATE = 2;
+    public static final int ACTION_GET_CONTENT = 3;
+    public static final int ACTION_OPEN_TREE = 4;
+    public static final int ACTION_MANAGE = 5;
+    public static final int ACTION_BROWSE = 6;
+    public static final int ACTION_OPEN_COPY_DESTINATION = 8;
+
+    public static final int MODE_UNKNOWN = 0;
+    public static final int MODE_LIST = 1;
+    public static final int MODE_GRID = 2;
+
+    public static final int SORT_ORDER_UNKNOWN = 0;
+    public static final int SORT_ORDER_DISPLAY_NAME = 1;
+    public static final int SORT_ORDER_LAST_MODIFIED = 2;
+    public static final int SORT_ORDER_SIZE = 3;
+
+    public void initAcceptMimes(Intent intent) {
+        if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
+            acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
+        } else {
+            String glob = intent.getType();
+            acceptMimes = new String[] { glob != null ? glob : "*/*" };
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(action);
+        out.writeInt(userMode);
+        out.writeStringArray(acceptMimes);
+        out.writeInt(userSortOrder);
+        out.writeInt(allowMultiple ? 1 : 0);
+        out.writeInt(forceSize ? 1 : 0);
+        out.writeInt(showSize ? 1 : 0);
+        out.writeInt(localOnly ? 1 : 0);
+        out.writeInt(forceAdvanced ? 1 : 0);
+        out.writeInt(showAdvanced ? 1 : 0);
+        out.writeInt(stackTouched ? 1 : 0);
+        out.writeInt(restored ? 1 : 0);
+        DurableUtils.writeToParcel(out, stack);
+        out.writeString(currentSearch);
+        out.writeMap(dirState);
+        out.writeList(selectedDocumentsForCopy);
+        out.writeList(excludedAuthorities);
+    }
+
+    public static final Creator<State> CREATOR = new Creator<State>() {
+        @Override
+        public State createFromParcel(Parcel in) {
+            final State state = new State();
+            state.action = in.readInt();
+            state.userMode = in.readInt();
+            state.acceptMimes = in.readStringArray();
+            state.userSortOrder = in.readInt();
+            state.allowMultiple = in.readInt() != 0;
+            state.forceSize = in.readInt() != 0;
+            state.showSize = in.readInt() != 0;
+            state.localOnly = in.readInt() != 0;
+            state.forceAdvanced = in.readInt() != 0;
+            state.showAdvanced = in.readInt() != 0;
+            state.stackTouched = in.readInt() != 0;
+            state.restored = in.readInt() != 0;
+            DurableUtils.readFromParcel(in, state.stack);
+            state.currentSearch = in.readString();
+            in.readMap(state.dirState, null);
+            in.readList(state.selectedDocumentsForCopy, null);
+            in.readList(state.excludedAuthorities, null);
+            return state;
+        }
+
+        @Override
+        public State[] newArray(int size) {
+            return new State[size];
+        }
+    };
+}
\ No newline at end of file
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
index 1325706..7d3498e 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -19,7 +19,6 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.RootInfo;
 
 import com.google.common.collect.Lists;
diff --git a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
index b5d9138..1530a02 100644
--- a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
+++ b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
@@ -166,7 +166,7 @@
     }
 }
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
     {"nativeReadBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) readBitmapPixels},
     {"nativeWriteBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) writeBitmapPixels},
 };
diff --git a/packages/SystemUI/res/layout/recents.xml b/packages/SystemUI/res/layout/recents.xml
index 8140dd6..064d225 100644
--- a/packages/SystemUI/res/layout/recents.xml
+++ b/packages/SystemUI/res/layout/recents.xml
@@ -39,12 +39,6 @@
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
 
-    <!-- Debug Overlay View -->
-    <ViewStub android:id="@+id/debug_overlay_stub"
-           android:layout="@layout/recents_debug_overlay"
-           android:layout_width="match_parent"
-           android:layout_height="match_parent" />
-
     <!-- Nav Bar Scrim View -->
     <ImageView
         android:id="@+id/nav_bar_scrim"
diff --git a/packages/SystemUI/res/layout/recents_debug_overlay.xml b/packages/SystemUI/res/layout/recents_debug_overlay.xml
deleted file mode 100644
index d23495e..0000000
--- a/packages/SystemUI/res/layout/recents_debug_overlay.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.systemui.recents.views.DebugOverlayView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent" 
-    android:layout_height="match_parent"
-    android:focusable="false">
-    <SeekBar
-        android:id="@+id/debug_seek_bar_1"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top"
-        android:layout_marginTop="25dp" />
-    <SeekBar
-        android:id="@+id/debug_seek_bar_2"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top"
-        android:layout_marginTop="50dp" />
-</com.android.systemui.recents.views.DebugOverlayView>
-
-
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
new file mode 100644
index 0000000..86bea87
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+import android.view.MotionEvent;
+
+import java.util.HashMap;
+
+/**
+ * A classifier which looks at the speed and distance between successive points of a Stroke.
+ * It looks at two consecutive speeds between two points and calculates the ratio between them.
+ * The final result is the maximum of these values. It does the same for distances. If some speed
+ * or distance is equal to zero then the ratio between this and the next part is not calculated. To
+ * the duration of each part there is added one nanosecond so that it is always possible to
+ * calculate the speed of a part.
+ */
+public class AccelerationClassifier extends StrokeClassifier {
+    private final HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
+
+    public AccelerationClassifier(ClassifierData classifierData) {
+        mClassifierData = classifierData;
+    }
+
+    @Override
+    public void onTouchEvent(MotionEvent event) {
+        int action = event.getActionMasked();
+
+        if (action == MotionEvent.ACTION_DOWN) {
+            mStrokeMap.clear();
+        }
+
+        for (int i = 0; i < event.getPointerCount(); i++) {
+            Stroke stroke = mClassifierData.getStroke(event.getPointerId(i));
+            Point point = stroke.getPoints().get(stroke.getPoints().size() - 1);
+            if (mStrokeMap.get(stroke) == null) {
+                mStrokeMap.put(stroke, new Data(point));
+            } else {
+                mStrokeMap.get(stroke).addPoint(point);
+            }
+        }
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        Data data = mStrokeMap.get(stroke);
+        return SpeedRatioEvaluator.evaluate(data.maxSpeedRatio)
+                + DistanceRatioEvaluator.evaluate(data.maxDistanceRatio);
+    }
+
+    private static class Data {
+        public Point previousPoint;
+        public float previousSpeed;
+        public float previousDistance;
+        public float maxSpeedRatio;
+        public float maxDistanceRatio;
+
+        public Data(Point point) {
+            previousPoint = point;
+            previousSpeed = previousDistance = 0.0f;
+            maxDistanceRatio = maxSpeedRatio = 0.0f;
+        }
+
+        public void addPoint(Point point) {
+            float distance = previousPoint.dist(point);
+            float duration = (float) (point.timeOffsetNano - previousPoint.timeOffsetNano + 1);
+            float speed = distance / duration;
+            if (previousDistance != 0.0f) {
+                maxDistanceRatio = Math.max(maxDistanceRatio, distance / previousDistance);
+            }
+
+            if (previousSpeed != 0.0f) {
+                maxSpeedRatio = Math.max(maxSpeedRatio, speed / previousSpeed);
+            }
+
+            previousDistance = distance;
+            previousSpeed = speed;
+            previousPoint = point;
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java
index 8c681fc..c74339b 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java
@@ -29,10 +29,15 @@
  * For each stroke it keeps its last three points. If some successive points are the same, it
  * ignores the repetitions. If a new point is added, the classifier calculates the angle between
  * the last three points. After that, it calculates the difference between this angle and the
- * previously calculated angle. The return value of the classifier is the variance of the
- * differences from a stroke. To the differences there is artificially added value 0.0 and the
- * difference between the first angle and PI (angles are in radians). It helps with strokes which
- * have few points and punishes more strokes which are not smooth.
+ * previously calculated angle. Then it calculates the variance of the differences from a stroke.
+ * To the differences there is artificially added value 0.0 and the difference between the first
+ * angle and PI (angles are in radians). It helps with strokes which have few points and punishes
+ * more strokes which are not smooth. This classifier also tries to split the stroke into two parts
+ * int the place in which the biggest angle is. It calculates the angle variance of the two parts
+ * and sums them up. The reason the classifier is doing this, is because some human swipes at the
+ * beginning go for a moment in one direction and then they rapidly change direction for the rest
+ * of the stroke (like a tick). The final result is the minimum of angle variance of the whole
+ * stroke and the sum of angle variances of the two parts split up.
  */
 public class AnglesVarianceClassifier extends StrokeClassifier {
     private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
@@ -61,21 +66,28 @@
 
     @Override
     public float getFalseTouchEvaluation(int type, Stroke stroke) {
-        return mStrokeMap.get(stroke).getAnglesVariance();
+        return AnglesVarianceEvaluator.evaluate(mStrokeMap.get(stroke).getAnglesVariance());
     }
 
-    private class Data {
+    private static class Data {
         private List<Point> mLastThreePoints = new ArrayList<>();
+        private float mFirstAngleVariance;
         private float mPreviousAngle;
+        private float mBiggestAngle;
         private float mSumSquares;
+        private float mSecondSumSquares;
         private float mSum;
+        private float mSecondSum;
         private float mCount;
+        private float mSecondCount;
 
         public Data() {
+            mFirstAngleVariance = 0.0f;
             mPreviousAngle = (float) Math.PI;
-            mSumSquares = 0.0f;
-            mSum = 0.0f;
-            mCount = 1.0f;
+            mBiggestAngle = 0.0f;
+            mSumSquares = mSecondSumSquares = 0.0f;
+            mSum = mSecondSum = 0.0f;
+            mCount = mSecondCount = 1.0f;
         }
 
         public void addPoint(Point point) {
@@ -87,10 +99,26 @@
                 if (mLastThreePoints.size() == 4) {
                     mLastThreePoints.remove(0);
 
-                    float angle = getAngle(mLastThreePoints.get(0), mLastThreePoints.get(1),
+                    float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0),
                             mLastThreePoints.get(2));
 
                     float difference = angle - mPreviousAngle;
+
+                    // If this is the biggest angle of the stroke so then we save the value of
+                    // the angle variance so far and start to count the values for the angle
+                    // variance of the second part.
+                    if (mBiggestAngle < angle) {
+                        mBiggestAngle = angle;
+                        mFirstAngleVariance = getAnglesVariance(mSumSquares, mSum, mCount);
+                        mSecondSumSquares = 0.0f;
+                        mSecondSum = 0.0f;
+                        mSecondCount = 1.0f;
+                    } else {
+                        mSecondSum += difference;
+                        mSecondSumSquares += difference * difference;
+                        mSecondCount += 1.0;
+                    }
+
                     mSum += difference;
                     mSumSquares += difference * difference;
                     mCount += 1.0;
@@ -99,21 +127,14 @@
             }
         }
 
-        private float getAngle(Point a, Point b, Point c) {
-            float dist1 = a.dist(b);
-            float dist2 = b.dist(c);
-            float crossProduct = b.crossProduct(a, c);
-            float dotProduct = b.dotProduct(a, c);
-            float cos = Math.min(1.0f, Math.max(-1.0f, dotProduct / dist1 / dist2));
-            float angle = (float) Math.acos(cos);
-            if (crossProduct < 0.0) {
-                angle = 2.0f * (float) Math.PI - angle;
-            }
-            return angle;
+        public float getAnglesVariance(float sumSquares, float sum, float count) {
+            return sumSquares / count - (sum / count) * (sum / count);
         }
 
         public float getAnglesVariance() {
-            return mSumSquares / mCount - (mSum / mCount) * (mSum / mCount);
+            return Math.min(getAnglesVariance(mSumSquares, mSum, mCount),
+                    mFirstAngleVariance + getAnglesVariance(mSecondSumSquares, mSecondSum,
+                            mSecondCount));
         }
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
new file mode 100644
index 0000000..99cc1a6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+public class AnglesVarianceEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value > 0.05) evaluation++;
+        if (value > 0.10) evaluation++;
+        if (value > 0.20) evaluation++;
+        if (value > 0.40) evaluation++;
+        if (value > 0.80) evaluation++;
+        if (value > 1.50) evaluation++;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java
index bccad4e..649279d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java
@@ -28,8 +28,12 @@
 public class ClassifierData {
     private SparseArray<Stroke> mCurrentStrokes = new SparseArray<>();
     private ArrayList<Stroke> mEndingStrokes = new ArrayList<>();
+    private float mXdpi;
+    private float mYdpi;
 
-    public ClassifierData() {
+    public ClassifierData(float xdpi, float ydpi) {
+        mXdpi = xdpi;
+        mYdpi = ydpi;
     }
 
     public void update(MotionEvent event) {
@@ -42,7 +46,7 @@
         for (int i = 0; i < event.getPointerCount(); i++) {
             int id = event.getPointerId(i);
             if (mCurrentStrokes.get(id) == null) {
-                mCurrentStrokes.put(id, new Stroke(event.getEventTimeNano()));
+                mCurrentStrokes.put(id, new Stroke(event.getEventTimeNano(), mXdpi, mYdpi));
             }
             mCurrentStrokes.get(id).addPoint(event.getX(i), event.getY(i),
                     event.getEventTimeNano());
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java
new file mode 100644
index 0000000..8acb009
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+public class DistanceRatioEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value <= 1.0) evaluation++;
+        if (value <= 0.5) evaluation++;
+        if (value > 4.0) evaluation++;
+        if (value > 7.0) evaluation++;
+        if (value > 14.0) evaluation++;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java
new file mode 100644
index 0000000..8924694
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+/**
+ * A classifier which looks at the ratio between the duration of the stroke and its number of
+ * points.
+ */
+public class DurationCountClassifier extends StrokeClassifier {
+    public DurationCountClassifier(ClassifierData classifierData) {
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        return DurationCountEvaluator.evaluate(stroke.getDurationSeconds() / stroke.getCount());
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java
new file mode 100644
index 0000000..5395983
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+
+public class DurationCountEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value < 0.0105) evaluation++;
+        if (value < 0.00909) evaluation++;
+        if (value < 0.00667) evaluation++;
+        if (value > 0.0333) evaluation++;
+        if (value > 0.0500) evaluation++;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java
new file mode 100644
index 0000000..78bc0dd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+/**
+ * A classifier which looks at the distance between the first and the last point from the stroke.
+ */
+public class EndPointLengthClassifier extends StrokeClassifier {
+    public EndPointLengthClassifier(ClassifierData classifierData) {
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        return EndPointLengthEvaluator.evaluate(stroke.getEndPointLength());
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java
new file mode 100644
index 0000000..bb2f1c4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+public class EndPointLengthEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value < 0.05) evaluation += 2.0;
+        if (value < 0.1) evaluation += 2.0;
+        if (value < 0.2) evaluation += 2.0;
+        if (value < 0.3) evaluation += 2.0;
+        if (value < 0.4) evaluation += 2.0;
+        if (value < 0.5) evaluation += 2.0;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java
new file mode 100644
index 0000000..c125e00
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+/**
+ * A classifier which looks at the ratio between the total length covered by the stroke and the
+ * distance between the first and last point from this stroke.
+ */
+public class EndPointRatioClassifier extends StrokeClassifier {
+    public EndPointRatioClassifier(ClassifierData classifierData) {
+        mClassifierData = classifierData;
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        if (stroke.getTotalLength() == 0.0f) {
+            return 1.0f;
+        }
+        return EndPointRatioEvaluator.evaluate(
+                stroke.getEndPointLength() / stroke.getTotalLength());
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java
new file mode 100644
index 0000000..529fcec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+public class EndPointRatioEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value < 0.85) evaluation++;
+        if (value < 0.75) evaluation++;
+        if (value < 0.65) evaluation++;
+        if (value < 0.55) evaluation++;
+        if (value < 0.45) evaluation++;
+        if (value < 0.35) evaluation++;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java
index e7f4c35..11388fc 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java
@@ -25,7 +25,7 @@
     /**
      * @param type the type of action for which this method is called
      * @return a non-negative value which is used to determine whether the most recent gesture is a
-     *         false interaction. The bigger the value the greater the chance that this a false
+     *         false interaction; the bigger the value the greater the chance that this a false
      *         interaction.
      */
     public abstract float getFalseTouchEvaluation(int type);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java
index b057bda..85a9bee 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java
@@ -100,7 +100,7 @@
      * For each stroke it holds its initial value and the current weight. Initially the
      * weight is set to 1.0
      */
-    private class Data {
+    private static class Data {
         public float evaluation;
         public float weight;
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 86ea640..6ef805c 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -55,10 +55,21 @@
 
     private HumanInteractionClassifier(Context context) {
         mContext = context;
-        mClassifierData = new ClassifierData();
+        mClassifierData = new ClassifierData(mContext.getResources().getDisplayMetrics().xdpi,
+                mContext.getResources().getDisplayMetrics().ydpi);
         mHistoryEvaluator = new HistoryEvaluator();
 
         mStrokeClassifiers.add(new AnglesVarianceClassifier(mClassifierData));
+        mStrokeClassifiers.add(new SpeedClassifier(mClassifierData));
+        mStrokeClassifiers.add(new DurationCountClassifier(mClassifierData));
+        mStrokeClassifiers.add(new EndPointRatioClassifier(mClassifierData));
+        mStrokeClassifiers.add(new EndPointLengthClassifier(mClassifierData));
+        mStrokeClassifiers.add(new AccelerationClassifier(mClassifierData));
+        mStrokeClassifiers.add(new SpeedVarianceClassifier(mClassifierData));
+        mStrokeClassifiers.add(new LengthCountClassifier(mClassifierData));
+
+        mGestureClassifiers.add(new PointerCountClassifier(mClassifierData));
+        mGestureClassifiers.add(new ProximityClassifier(mClassifierData));
 
         mStrokeClassifiersSize = mStrokeClassifiers.size();
         mGestureClassifiersSize = mGestureClassifiers.size();
@@ -128,6 +139,13 @@
 
     @Override
     public void onSensorChanged(SensorEvent event) {
+        for (int i = 0; i < mStrokeClassifiers.size(); i++) {
+            mStrokeClassifiers.get(i).onSensorChanged(event);
+        }
+
+        for (int i = 0; i < mGestureClassifiers.size(); i++) {
+            mGestureClassifiers.get(i).onSensorChanged(event);
+        }
     }
 
     public boolean isFalseTouch() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java
new file mode 100644
index 0000000..1ea467b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+/**
+ * A classifier which looks at the ratio between the duration of the stroke and its number of
+ * points.
+ */
+public class LengthCountClassifier extends StrokeClassifier {
+    public LengthCountClassifier(ClassifierData classifierData) {
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        return LengthCountEvaluator.evaluate(stroke.getTotalLength() / stroke.getCount());
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java
new file mode 100644
index 0000000..68f163d1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+/**
+ * A classifier which looks at the ratio between the length of the stroke and its number of
+ * points.
+ */
+public class LengthCountEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value < 0.07) evaluation++;
+        if (value < 0.05) evaluation++;
+        if (value < 0.02) evaluation++;
+        if (value > 0.6) evaluation++;
+        if (value > 1.2) evaluation++;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Point.java b/packages/SystemUI/src/com/android/systemui/classifier/Point.java
index e7dbae1..f3dc2be 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Point.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Point.java
@@ -56,4 +56,28 @@
     public float dotProduct(Point a, Point b) {
         return (a.x - x) * (b.x - x) + (a.y - y) * (b.y - y);
     }
+
+    /**
+     * Calculates the angle in radians created by points (a, this, b). If any two of these points
+     * are the same, the method will return 0.0f
+     *
+     * @return the angle in radians
+     */
+    public float getAngle(Point a, Point b) {
+        float dist1 = dist(a);
+        float dist2 = dist(b);
+
+        if (dist1 == 0.0f || dist2 == 0.0f) {
+            return 0.0f;
+        }
+
+        float crossProduct = crossProduct(a, b);
+        float dotProduct = dotProduct(a, b);
+        float cos = Math.min(1.0f, Math.max(-1.0f, dotProduct / dist1 / dist2));
+        float angle = (float) Math.acos(cos);
+        if (crossProduct < 0.0) {
+            angle = 2.0f * (float) Math.PI - angle;
+        }
+        return angle;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
new file mode 100644
index 0000000..5097b63
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+import android.view.MotionEvent;
+
+/**
+ * A classifier which looks at the total number of traces in the whole gesture.
+ */
+public class PointerCountClassifier extends GestureClassifier {
+    private int mCount;
+
+    public PointerCountClassifier(ClassifierData classifierData) {
+        mCount = 0;
+    }
+
+    @Override
+    public void onTouchEvent(MotionEvent event) {
+        int action = event.getActionMasked();
+
+        if (action == MotionEvent.ACTION_DOWN) {
+            mCount = 1;
+        }
+
+        if (action == MotionEvent.ACTION_POINTER_DOWN) {
+            ++mCount;
+        }
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type) {
+        return PointerCountEvaluator.evaluate(mCount);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java
similarity index 73%
copy from services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
copy to packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java
index c47d194..d7a3af0 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java
@@ -11,11 +11,13 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License.
+ * limitations under the License
  */
-package com.android.server.devicepolicy;
 
-import android.app.admin.DeviceAdminReceiver;
+package com.android.systemui.classifier;
 
-public class DummyDeviceAdmin extends DeviceAdminReceiver {
+public class PointerCountEvaluator {
+    public static float evaluate(int value) {
+        return (value - 1) * (value - 1);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
new file mode 100644
index 0000000..6995064
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.view.MotionEvent;
+
+/**
+ * A classifier which looks at the proximity sensor during the gesture. It calculates the percentage
+ * the proximity sensor showing the near state during the whole gesture
+ */
+public class ProximityClassifier extends GestureClassifier {
+    private long mGestureStartTimeNano;
+    private long mNearStartTimeNano;
+    private long mNearDuration;
+    private boolean mNear;
+    private float mAverageNear;
+
+    public ProximityClassifier(ClassifierData classifierData) {
+    }
+
+    @Override
+    public void onSensorChanged(SensorEvent event) {
+        if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) {
+            update(event.values[0] < event.sensor.getMaximumRange(), event.timestamp);
+        }
+    }
+
+    @Override
+    public void onTouchEvent(MotionEvent event) {
+        int action = event.getActionMasked();
+
+        if (action == MotionEvent.ACTION_DOWN) {
+            mGestureStartTimeNano = event.getEventTimeNano();
+            mNearStartTimeNano = event.getEventTimeNano();
+            mNearDuration = 0;
+        }
+
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            update(mNear, event.getEventTimeNano());
+            long duration = event.getEventTimeNano() - mGestureStartTimeNano;
+
+            if (duration == 0) {
+                mAverageNear = mNear ? 1.0f : 0.0f;
+            } else {
+                mAverageNear = (float) mNearDuration / (float) duration;
+            }
+        }
+    }
+
+
+    /**
+     * @param near is the sensor showing the near state right now
+     * @param timestampNano time of this event in nanoseconds
+     */
+    private void update(boolean near, long timestampNano) {
+        // This if is necessary because MotionEvents and SensorEvents do not come in
+        // chronological order
+        if (timestampNano > mNearStartTimeNano) {
+            // if the state before was near then add the difference of the current time and
+            // mNearStartTimeNano to mNearDuration.
+            if (mNear) {
+                mNearDuration += timestampNano - mNearStartTimeNano;
+            }
+
+            // if the new state is near, set mNearStartTimeNano equal to this moment.
+            if (near) {
+                mNearStartTimeNano = timestampNano;
+            }
+        }
+        mNear = near;
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type) {
+        return ProximityEvaluator.evaluate(mAverageNear, type);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java
new file mode 100644
index 0000000..91002bf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+public class ProximityEvaluator {
+    public static float evaluate(float value, int type) {
+        float evaluation = 0.0f;
+        float threshold = 0.1f;
+        if (type == Classifier.QUICK_SETTINGS) {
+            threshold = 1.0f;
+        }
+        if (value >= threshold) evaluation += 2.0;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java
new file mode 100644
index 0000000..81b78c7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+/**
+ * A classifier that looks at the speed of the stroke. It calculates the speed of a stroke in
+ * inches per second.
+ */
+public class SpeedClassifier extends StrokeClassifier {
+    private final float NANOS_TO_SECONDS = 1e9f;
+
+    public SpeedClassifier(ClassifierData classifierData) {
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        float duration = (float) stroke.getDurationNanos() / NANOS_TO_SECONDS;
+        if (duration == 0.0f) {
+            return SpeedEvaluator.evaluate(0.0f);
+        }
+        return SpeedEvaluator.evaluate(stroke.getTotalLength() / duration);
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java
similarity index 61%
copy from services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
copy to packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java
index c47d194..c0e4a2d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java
@@ -11,11 +11,17 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License.
+ * limitations under the License
  */
-package com.android.server.devicepolicy;
 
-import android.app.admin.DeviceAdminReceiver;
+package com.android.systemui.classifier;
 
-public class DummyDeviceAdmin extends DeviceAdminReceiver {
+public class SpeedEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value < 4.0 || value > 35.0) evaluation += 1.0;
+        if (value < 2.2) evaluation += 1.0;
+        if (value > 50.0) evaluation += 1.0;
+        return evaluation;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java
similarity index 65%
copy from services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
copy to packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java
index c47d194..349aa9e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java
@@ -11,11 +11,16 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License.
+ * limitations under the License
  */
-package com.android.server.devicepolicy;
 
-import android.app.admin.DeviceAdminReceiver;
+package com.android.systemui.classifier;
 
-public class DummyDeviceAdmin extends DeviceAdminReceiver {
+public class SpeedRatioEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value > 9.0) ++evaluation;
+        if (value > 18.0) ++evaluation;
+        return evaluation;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java
new file mode 100644
index 0000000..9a30fe1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+import android.view.MotionEvent;
+
+import java.lang.Math;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * A classifier which for each point from a stroke, it creates a point on plane with coordinates
+ * (timeOffsetNano, distanceCoveredUpToThisPoint) (scaled by DURATION_SCALE and LENGTH_SCALE)
+ * and then it calculates the angle variance of these points like the class
+ * {@link AnglesVarianceClassifier} (without splitting it into two parts). The classifier ignores
+ * the last point of a stroke because the UP event comes in with some delay and this ruins the
+ * smoothness of this curve
+ */
+public class SpeedVarianceClassifier extends StrokeClassifier {
+    private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
+
+    public SpeedVarianceClassifier(ClassifierData classifierData) {
+        mClassifierData = classifierData;
+    }
+
+    @Override
+    public void onTouchEvent(MotionEvent event) {
+        int action = event.getActionMasked();
+
+        if (action == MotionEvent.ACTION_DOWN) {
+            mStrokeMap.clear();
+        }
+
+        for (int i = 0; i < event.getPointerCount(); i++) {
+            Stroke stroke = mClassifierData.getStroke(event.getPointerId(i));
+
+            if (mStrokeMap.get(stroke) == null) {
+                mStrokeMap.put(stroke, new Data());
+            }
+
+            if (action != MotionEvent.ACTION_UP && action != MotionEvent.ACTION_CANCEL
+                    && !(action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) {
+                mStrokeMap.get(stroke).addPoint(
+                        stroke.getPoints().get(stroke.getPoints().size() - 1));
+            }
+        }
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        return SpeedVarianceEvaluator.evaluate(mStrokeMap.get(stroke).getAnglesVariance());
+    }
+
+    private static class Data {
+        private final float DURATION_SCALE = 1e8f;
+        private final float LENGTH_SCALE = 1.0f;
+
+        private List<Point> mLastThreePoints = new ArrayList<>();
+        private Point mPreviousPoint;
+        private float mPreviousAngle;
+        private float mSumSquares;
+        private float mSum;
+        private float mCount;
+        private float mDist;
+
+        public Data() {
+            mPreviousPoint = null;
+            mPreviousAngle = (float) Math.PI;
+            mSumSquares = 0.0f;
+            mSum = 0.0f;
+            mCount = 1.0f;
+            mDist = 0.0f;
+        }
+
+        public void addPoint(Point point) {
+            if (mPreviousPoint != null) {
+                mDist += mPreviousPoint.dist(point);
+            }
+
+            mPreviousPoint = point;
+            Point speedPoint = new Point((float) point.timeOffsetNano / DURATION_SCALE,
+                    mDist / LENGTH_SCALE);
+
+            // Checking if the added point is different than the previously added point
+            // Repetitions are being ignored so that proper angles are calculated.
+            if (mLastThreePoints.isEmpty()
+                    || !mLastThreePoints.get(mLastThreePoints.size() - 1).equals(speedPoint)) {
+                mLastThreePoints.add(speedPoint);
+                if (mLastThreePoints.size() == 4) {
+                    mLastThreePoints.remove(0);
+
+                    float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0),
+                            mLastThreePoints.get(2));
+
+                    float difference = angle - mPreviousAngle;
+                    mSum += difference;
+                    mSumSquares += difference * difference;
+                    mCount += 1.0;
+                    mPreviousAngle = angle;
+                }
+            }
+        }
+
+        public float getAnglesVariance() {
+            return mSumSquares / mCount - (mSum / mCount) * (mSum / mCount);
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.java
new file mode 100644
index 0000000..8f9a7e1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+public class SpeedVarianceEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value > 0.06) evaluation += 1.0;
+        if (value > 0.15) evaluation += 1.0;
+        if (value > 0.3) evaluation += 1.0;
+        if (value > 0.6) evaluation += 1.0;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java
index 8c3fdd4..49e6fb8 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java
@@ -23,17 +23,48 @@
  * DOWN/POINTER_DOWN event till the UP/POINTER_UP/CANCEL event.)
  */
 public class Stroke {
+    private final float NANOS_TO_SECONDS = 1e9f;
+
     private ArrayList<Point> mPoints = new ArrayList<>();
     private long mStartTimeNano;
     private long mEndTimeNano;
+    private float mLength;
+    private float mXdpi;
+    private float mYdpi;
 
-    public Stroke(long eventTimeNano) {
+    public Stroke(long eventTimeNano, float xdpi, float ydpi) {
+        mXdpi = xdpi;
+        mYdpi = ydpi;
         mStartTimeNano = mEndTimeNano = eventTimeNano;
     }
 
     public void addPoint(float x, float y, long eventTimeNano) {
         mEndTimeNano = eventTimeNano;
-        mPoints.add(new Point(x, y, eventTimeNano - mStartTimeNano));
+        Point point = new Point(x / mXdpi, y / mYdpi, eventTimeNano - mStartTimeNano);
+        if (!mPoints.isEmpty()) {
+            mLength += mPoints.get(mPoints.size() - 1).dist(point);
+        }
+        mPoints.add(point);
+    }
+
+    public int getCount() {
+        return mPoints.size();
+    }
+
+    public float getTotalLength() {
+        return mLength;
+    }
+
+    public float getEndPointLength() {
+        return mPoints.get(0).dist(mPoints.get(mPoints.size() - 1));
+    }
+
+    public long getDurationNanos() {
+        return mEndTimeNano - mStartTimeNano;
+    }
+
+    public float getDurationSeconds() {
+        return (float) getDurationNanos() / NANOS_TO_SECONDS;
     }
 
     public ArrayList<Point> getPoints() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java
index d561f46..5da392f 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java
@@ -24,8 +24,8 @@
     /**
      * @param type the type of action for which this method is called
      * @param stroke the stroke for which the evaluation will be calculated
-     * @return a non-negative value which is used to determine whether this a false touch. The
-     *         bigger the value the greater the chance that this a false touch.
+     * @return a non-negative value which is used to determine whether this a false touch; the
+     *         bigger the value the greater the chance that this a false touch
      */
     public abstract float getFalseTouchEvaluation(int type, Stroke stroke);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index e1a8815..9781664 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -29,8 +29,6 @@
     }
 
     public static class DebugFlags {
-        // Enable this with any other debug flag to see more info
-        public static final boolean Verbose = false;
 
         public static class App {
             // Enables debug drawing for the transition thumbnail
@@ -39,10 +37,6 @@
             public static final boolean EnableTaskFiltering = false;
             // Enables dismiss-all
             public static final boolean EnableDismissAll = false;
-            // Enables debug mode
-            public static final boolean EnableDebugMode = false;
-            // Enables the search bar layout
-            public static final boolean EnableSearchLayout = true;
             // Enables the thumbnail alpha on the front-most task
             public static final boolean EnableThumbnailAlphaOnFrontmost = false;
             // This disables the bitmap and icon caches
@@ -63,7 +57,6 @@
     public static class Values {
         public static class App {
             public static int AppWidgetHostId = 1024;
-            public static String DebugModeVersion = "A";
         }
 
         public static class TaskStackView {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 4bb3e4a..c53e573 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -38,14 +38,12 @@
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.misc.Console;
-import com.android.systemui.recents.misc.DebugTrigger;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.views.DebugOverlayView;
 import com.android.systemui.recents.views.RecentsView;
 import com.android.systemui.recents.views.SystemBarScrimViews;
 import com.android.systemui.recents.views.ViewAnimation;
@@ -57,8 +55,7 @@
  * The main Recents activity that is started from AlternateRecentsComponent.
  */
 public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks,
-        RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks,
-        DebugOverlayView.DebugOverlayViewCallbacks {
+        RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks {
 
     RecentsConfiguration mConfig;
     long mLastTabKeyEventTime;
@@ -67,9 +64,7 @@
     RecentsView mRecentsView;
     SystemBarScrimViews mScrimViews;
     ViewStub mEmptyViewStub;
-    ViewStub mDebugOverlayStub;
     View mEmptyView;
-    DebugOverlayView mDebugOverlay;
 
     // Resize task debug
     RecentsResizeTaskDialog mResizeTaskDebugDialog;
@@ -176,16 +171,6 @@
         }
     };
 
-    /**
-     * A custom debug trigger to listen for a debug key chord.
-     */
-    final DebugTrigger mDebugTrigger = new DebugTrigger(new Runnable() {
-        @Override
-        public void run() {
-            onDebugModeTriggered();
-        }
-    });
-
     /** Updates the set of recent tasks */
     void updateRecentsTasks() {
         // If AlternateRecentsComponent has preloaded a load plan, then use that to prevent
@@ -352,9 +337,7 @@
                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
         mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
-        mDebugOverlayStub = (ViewStub) findViewById(R.id.debug_overlay_stub);
         mScrimViews = new SystemBarScrimViews(this, mConfig);
-        inflateDebugOverlay();
 
         // Bind the search app widget when we first start up
         mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
@@ -366,27 +349,10 @@
         registerReceiver(mSystemBroadcastReceiver, filter);
     }
 
-    /** Inflates the debug overlay if debug mode is enabled. */
-    void inflateDebugOverlay() {
-        if (!Constants.DebugFlags.App.EnableDebugMode) return;
-
-        if (mConfig.debugModeEnabled && mDebugOverlay == null) {
-            // Inflate the overlay and seek bars
-            mDebugOverlay = (DebugOverlayView) mDebugOverlayStub.inflate();
-            mDebugOverlay.setCallbacks(this);
-            mRecentsView.setDebugOverlay(mDebugOverlay);
-        }
-    }
-
     @Override
     protected void onNewIntent(Intent intent) {
         super.onNewIntent(intent);
         setIntent(intent);
-
-        // Clear any debug rects
-        if (mDebugOverlay != null) {
-            mDebugOverlay.clear();
-        }
     }
 
     @Override
@@ -538,8 +504,6 @@
             default:
                 break;
         }
-        // Pass through the debug trigger
-        mDebugTrigger.onKeyEvent(keyCode);
         return super.onKeyDown(keyCode, event);
     }
 
@@ -557,33 +521,6 @@
         dismissRecentsToFocusedTaskOrHome(true);
     }
 
-    /** Called when debug mode is triggered */
-    public void onDebugModeTriggered() {
-        if (mConfig.developerOptionsEnabled) {
-            if (Prefs.getBoolean(this, Prefs.Key.DEBUG_MODE_ENABLED, false /* boolean */)) {
-                // Disable the debug mode
-                Prefs.remove(this, Prefs.Key.DEBUG_MODE_ENABLED);
-                mConfig.debugModeEnabled = false;
-                inflateDebugOverlay();
-                if (mDebugOverlay != null) {
-                    mDebugOverlay.disable();
-                }
-            } else {
-                // Enable the debug mode
-                Prefs.putBoolean(this, Prefs.Key.DEBUG_MODE_ENABLED, true);
-                mConfig.debugModeEnabled = true;
-                inflateDebugOverlay();
-                if (mDebugOverlay != null) {
-                    mDebugOverlay.enable();
-                }
-            }
-            Toast.makeText(this, "Debug mode (" + Constants.Values.App.DebugModeVersion + ") " +
-                (mConfig.debugModeEnabled ? "Enabled" : "Disabled") + ", please restart Recents now",
-                Toast.LENGTH_SHORT).show();
-        }
-    }
-
-
     /**** RecentsResizeTaskDialog ****/
 
     private RecentsResizeTaskDialog getResizeTaskDebugDialog() {
@@ -655,16 +592,4 @@
             mRecentsView.setSearchBar(null);
         }
     }
-
-    /**** DebugOverlayView.DebugOverlayViewCallbacks ****/
-
-    @Override
-    public void onPrimarySeekBarChanged(float progress) {
-        // Do nothing
-    }
-
-    @Override
-    public void onSecondarySeekBarChanged(float progress) {
-        // Do nothing
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java
deleted file mode 100644
index fbf8a86..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.misc;
-
-import android.os.Handler;
-import android.os.SystemClock;
-import android.view.KeyEvent;
-import com.android.systemui.recents.Constants;
-
-/**
- * A trigger for catching a debug chord.
- * We currently use volume up then volume down to trigger this mode.
- */
-public class DebugTrigger {
-
-    Handler mHandler;
-    Runnable mTriggeredRunnable;
-
-    int mLastKeyCode;
-    long mLastKeyCodeTime;
-
-    public DebugTrigger(Runnable triggeredRunnable) {
-        mHandler = new Handler();
-        mTriggeredRunnable = triggeredRunnable;
-    }
-
-    /** Resets the debug trigger */
-    void reset() {
-        mLastKeyCode = 0;
-        mLastKeyCodeTime = 0;
-    }
-
-    /**
-     * Processes a key event and tests if it is a part of the trigger. If the chord is complete,
-     * then we just call the callback.
-     */
-    public void onKeyEvent(int keyCode) {
-        if (!Constants.DebugFlags.App.EnableDebugMode) return;
-
-        if (mLastKeyCode == 0) {
-            if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
-                mLastKeyCode = keyCode;
-                mLastKeyCodeTime = SystemClock.uptimeMillis();
-                return;
-            }
-        } else {
-            if (mLastKeyCode == KeyEvent.KEYCODE_VOLUME_UP &&
-                    keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
-                if ((SystemClock.uptimeMillis() - mLastKeyCodeTime) < 750) {
-                    mTriggeredRunnable.run();
-                }
-            }
-        }
-        reset();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index a760a41..515e578 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -17,7 +17,6 @@
 package com.android.systemui.recents.model;
 
 import android.graphics.Color;
-import android.graphics.Rect;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.NamedCounter;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java b/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java
deleted file mode 100644
index 452830d..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.views;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.Pair;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.SeekBar;
-import com.android.systemui.R;
-import com.android.systemui.recents.RecentsConfiguration;
-
-import java.util.ArrayList;
-
-/**
- * A full screen overlay layer that allows us to draw views from throughout the system on the top
- * most layer.
- */
-public class DebugOverlayView extends FrameLayout implements SeekBar.OnSeekBarChangeListener {
-
-    public interface DebugOverlayViewCallbacks {
-        public void onPrimarySeekBarChanged(float progress);
-        public void onSecondarySeekBarChanged(float progress);
-    }
-
-    final static int sCornerRectSize = 50;
-
-    RecentsConfiguration mConfig;
-    DebugOverlayViewCallbacks mCb;
-
-    ArrayList<Pair<Rect, Integer>> mRects = new ArrayList<Pair<Rect, Integer>>();
-    String mText;
-    Paint mDebugOutline = new Paint();
-    Paint mTmpPaint = new Paint();
-    Rect mTmpRect = new Rect();
-    boolean mEnabled = true;
-
-    SeekBar mPrimarySeekBar;
-    SeekBar mSecondarySeekBar;
-
-    public DebugOverlayView(Context context) {
-        this(context, null);
-    }
-
-    public DebugOverlayView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public DebugOverlayView(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public DebugOverlayView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        mConfig = RecentsConfiguration.getInstance();
-        mDebugOutline.setColor(0xFFff0000);
-        mDebugOutline.setStyle(Paint.Style.STROKE);
-        mDebugOutline.setStrokeWidth(8f);
-        setWillNotDraw(false);
-    }
-
-    public void setCallbacks(DebugOverlayViewCallbacks cb) {
-        mCb = cb;
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        mPrimarySeekBar = (SeekBar) findViewById(R.id.debug_seek_bar_1);
-        mPrimarySeekBar.setOnSeekBarChangeListener(this);
-        mSecondarySeekBar = (SeekBar) findViewById(R.id.debug_seek_bar_2);
-        mSecondarySeekBar.setOnSeekBarChangeListener(this);
-    }
-
-    /** Enables the debug overlay drawing. */
-    public void enable() {
-        mEnabled = true;
-        setVisibility(View.VISIBLE);
-    }
-
-    /** Disables the debug overlay drawing. */
-    public void disable() {
-        mEnabled = false;
-        setVisibility(View.GONE);
-    }
-
-    /** Clears all debug rects. */
-    public void clear() {
-        mRects.clear();
-    }
-
-    /** Adds a rect to be drawn. */
-    void addRect(Rect r, int color) {
-        mRects.add(new Pair<Rect, Integer>(r, color));
-        invalidate();
-    }
-
-    /** Adds a view's global rect to be drawn. */
-    void addViewRect(View v, int color) {
-        Rect vr = new Rect();
-        v.getGlobalVisibleRect(vr);
-        mRects.add(new Pair<Rect, Integer>(vr, color));
-        invalidate();
-    }
-
-    /** Adds a rect, relative to a given view to be drawn. */
-    void addRectRelativeToView(View v, Rect r, int color) {
-        Rect vr = new Rect();
-        v.getGlobalVisibleRect(vr);
-        r.offsetTo(vr.left, vr.top);
-        mRects.add(new Pair<Rect, Integer>(r, color));
-        invalidate();
-    }
-
-    /** Sets the debug text at the bottom of the screen. */
-    void setText(String message) {
-        mText = message;
-        invalidate();
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        addRect(new Rect(0, 0, sCornerRectSize, sCornerRectSize), 0xFFff0000);
-        addRect(new Rect(getMeasuredWidth() - sCornerRectSize, getMeasuredHeight() - sCornerRectSize,
-                getMeasuredWidth(), getMeasuredHeight()), 0xFFff0000);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mEnabled) {
-            // Draw the outline
-            canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mDebugOutline);
-
-            // Draw the rects
-            int numRects = mRects.size();
-            for (int i = 0; i < numRects; i++) {
-                Pair<Rect, Integer> r = mRects.get(i);
-                mTmpPaint.setColor(r.second);
-                canvas.drawRect(r.first, mTmpPaint);
-            }
-
-            // Draw the text
-            if (mText != null && mText.length() > 0) {
-                mTmpPaint.setColor(0xFFff0000);
-                mTmpPaint.setTextSize(60);
-                mTmpPaint.getTextBounds(mText, 0, 1, mTmpRect);
-                canvas.drawText(mText, 10f, getMeasuredHeight() - mTmpRect.height() - mConfig.systemInsets.bottom, mTmpPaint);
-            }
-        }
-    }
-
-    /**** SeekBar.OnSeekBarChangeListener Implementation ****/
-
-    @Override
-    public void onStopTrackingTouch(SeekBar seekBar) {
-        // Do nothing
-    }
-
-    @Override
-    public void onStartTrackingTouch(SeekBar seekBar) {
-        // Do nothing
-    }
-
-    @Override
-    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-        if (seekBar == mPrimarySeekBar) {
-            mCb.onPrimarySeekBarChanged((float) progress / mPrimarySeekBar.getMax());
-        } else if (seekBar == mSecondarySeekBar) {
-            mCb.onSecondarySeekBarChanged((float) progress / mSecondarySeekBar.getMax());
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
index 509ad1b..41adbed 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
@@ -28,7 +28,6 @@
 import android.graphics.Shader;
 import android.graphics.drawable.Drawable;
 import android.util.Log;
-
 import com.android.systemui.R;
 import com.android.systemui.recents.RecentsConfiguration;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index c7d1dd1..fab8b3a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -78,7 +78,6 @@
 
     RecentsConfiguration mConfig;
     LayoutInflater mInflater;
-    DebugOverlayView mDebugOverlay;
 
     ArrayList<TaskStack> mStacks;
     TaskStackView mTaskStackView;
@@ -108,11 +107,6 @@
         mCb = cb;
     }
 
-    /** Sets the debug overlay */
-    public void setDebugOverlay(DebugOverlayView overlay) {
-        mDebugOverlay = overlay;
-    }
-
     /** Set/get the bsp root node */
     public void setTaskStack(TaskStack stack) {
         if (mConfig.launchedReuseTaskStackViews) {
@@ -134,11 +128,6 @@
             addView(mTaskStackView);
         }
 
-        // Enable debug mode drawing on all the stacks if necessary
-        if (mConfig.debugModeEnabled) {
-            mTaskStackView.setDebugOverlay(mDebugOverlay);
-        }
-
         // Trigger a new layout
         requestLayout();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 8058c5e..4db8b37 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -79,7 +79,6 @@
     ViewPool<TaskView, Task> mViewPool;
     ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<TaskViewTransform>();
     DozeTrigger mUIDozeTrigger;
-    DebugOverlayView mDebugOverlay;
     DismissView mDismissAllButton;
     boolean mDismissAllButtonAnimating;
     int mFocusedTaskIndex = -1;
@@ -161,11 +160,6 @@
         return mStack;
     }
 
-    /** Sets the debug overlay */
-    public void setDebugOverlay(DebugOverlayView overlay) {
-        mDebugOverlay = overlay;
-    }
-
     /** Updates the list of task views */
     void updateTaskViewsList() {
         mTaskViews.clear();
@@ -334,9 +328,6 @@
             int[] visibleRange = mTmpVisibleRange;
             boolean isValidVisibleRange = updateStackTransforms(mCurrentTaskTransforms, tasks,
                     stackScroll, visibleRange, false);
-            if (mDebugOverlay != null) {
-                mDebugOverlay.setText("vis[" + visibleRange[1] + "-" + visibleRange[0] + "]");
-            }
 
             // Inflate and add the dismiss button if necessary
             if (Constants.DebugFlags.App.EnableDismissAll && mDismissAllButton == null) {
diff --git a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
index 2727338..990d770 100644
--- a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
+++ b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
@@ -130,7 +130,7 @@
     return jret;
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "createV8ParserNativeLocked", "()Z",
         (void*)com_android_pacprocessor_PacNative_createV8ParserNativeLocked},
     { "destroyV8ParserNativeLocked", "()Z",
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 0419d33..8c830e8 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -2494,7 +2494,7 @@
 
 static const char *classPathName = "android/renderscript/RenderScript";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nInit",                         "()V",                                     (void*)_nInit },
 
 {"nDeviceCreate",                  "()J",                                     (void*)nDeviceCreate },
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 85730cd..c3f5c43 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -29,6 +29,7 @@
 import android.os.Handler;
 import android.os.SystemClock;
 import android.util.Slog;
+import android.view.GestureDetector;
 import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -114,9 +115,6 @@
     // Timeout within which we try to detect a tap.
     private final int mTapTimeout;
 
-    // Timeout within which we try to detect a double tap.
-    private final int mDoubleTapTimeout;
-
     // Slop between the down and up tap to be a tap.
     private final int mTouchSlop;
 
@@ -230,7 +228,6 @@
         mInjectedPointerTracker = new InjectedPointerTracker();
         mTapTimeout = ViewConfiguration.getTapTimeout();
         mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout();
-        mDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
         mHandler = new Handler(context.getMainLooper());
@@ -248,7 +245,7 @@
         mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed(
                 AccessibilityEvent.TYPE_TOUCH_INTERACTION_END,
                 mDetermineUserIntentTimeout);
-        mDoubleTapDetector = new DoubleTapDetector();
+        mDoubleTapDetector = new DoubleTapDetector(mContext);
         final float density = context.getResources().getDisplayMetrics().density;
         mScaledMinPointerDistanceToUseMiddleLocation =
             (int) (MIN_POINTER_DISTANCE_TO_USE_MIDDLE_LOCATION_DIP * density);
@@ -1109,66 +1106,63 @@
         }
     }
 
-    private class DoubleTapDetector {
-        private MotionEvent mDownEvent;
-        private MotionEvent mFirstTapEvent;
+    private class DoubleTapDetector extends GestureDetector.SimpleOnGestureListener {
+        private final GestureDetector mGestureDetector;
+        private boolean mFirstTapDetected;
+        private boolean mDoubleTapDetected;
 
-        public void onMotionEvent(MotionEvent event, int policyFlags) {
-            final int actionIndex = event.getActionIndex();
-            final int action = event.getActionMasked();
-            switch (action) {
-                case MotionEvent.ACTION_DOWN:
-                case MotionEvent.ACTION_POINTER_DOWN: {
-                    if (mFirstTapEvent != null
-                            && !GestureUtils.isSamePointerContext(mFirstTapEvent, event)) {
-                        clear();
-                    }
-                    mDownEvent = MotionEvent.obtain(event);
-                } break;
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_POINTER_UP: {
-                    if (mDownEvent == null) {
-                        return;
-                    }
-                    if (!GestureUtils.isSamePointerContext(mDownEvent, event)) {
-                        clear();
-                        return;
-                    }
-                    if (GestureUtils.isTap(mDownEvent, event, mTapTimeout, mTouchSlop,
-                            actionIndex)) {
-                        if (mFirstTapEvent == null || GestureUtils.isTimedOut(mFirstTapEvent,
-                                event, mDoubleTapTimeout)) {
-                            mFirstTapEvent = MotionEvent.obtain(event);
-                            mDownEvent.recycle();
-                            mDownEvent = null;
-                            return;
-                        }
-                        if (GestureUtils.isMultiTap(mFirstTapEvent, event, mDoubleTapTimeout,
-                                mDoubleTapSlop, actionIndex)) {
-                            onDoubleTap(event, policyFlags);
-                            mFirstTapEvent.recycle();
-                            mFirstTapEvent = null;
-                            mDownEvent.recycle();
-                            mDownEvent = null;
-                            return;
-                        }
-                        mFirstTapEvent.recycle();
-                        mFirstTapEvent = null;
-                    } else {
-                        if (mFirstTapEvent != null) {
-                            mFirstTapEvent.recycle();
-                            mFirstTapEvent = null;
-                        }
-                    }
-                    mDownEvent.recycle();
-                    mDownEvent = null;
-                } break;
-            }
+        DoubleTapDetector(Context context) {
+            mGestureDetector = new GestureDetector(context, this);
+            mGestureDetector.setOnDoubleTapListener(this);
         }
 
-        public void onDoubleTap(MotionEvent secondTapUp, int policyFlags) {
+        public void onMotionEvent(MotionEvent event, int policyFlags) {
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                    mDoubleTapDetected = false;
+                    break;
+
+                case MotionEvent.ACTION_UP:
+                    maybeFinishDoubleTap(event, policyFlags);
+                    break;
+            }
+            mGestureDetector.onTouchEvent(event);
+        }
+
+        @Override
+        public boolean onDown(MotionEvent event) {
+            return true;
+        }
+
+        @Override
+        public boolean onSingleTapUp(MotionEvent event) {
+            mFirstTapDetected = true;
+            return false;
+        }
+
+        @Override
+        public boolean onSingleTapConfirmed(MotionEvent event) {
+            clear();
+            return false;
+        }
+
+        @Override
+        public boolean onDoubleTap(MotionEvent event) {
+            // The processing of the double tap is deferred until the finger is
+            // lifted, so that we can detect a long press on the second tap.
+            mDoubleTapDetected = true;
+            return true;
+        }
+
+        private void maybeFinishDoubleTap(MotionEvent event, int policyFlags) {
+            if (!mDoubleTapDetected) {
+                return;
+            }
+
+            clear();
+
             // This should never be called when more than two pointers are down.
-            if (secondTapUp.getPointerCount() > 2) {
+            if (event.getPointerCount() > 2) {
                 return;
             }
 
@@ -1184,8 +1178,8 @@
                 mSendTouchInteractionEndDelayed.forceSendAndRemove();
             }
 
-            final int pointerId = secondTapUp.getPointerId(secondTapUp.getActionIndex());
-            final int pointerIndex = secondTapUp.findPointerIndex(pointerId);
+            final int pointerId = event.getPointerId(event.getActionIndex());
+            final int pointerIndex = event.findPointerIndex(pointerId);
 
             Point clickLocation = mTempPoint;
             final int result = computeClickLocation(clickLocation);
@@ -1196,34 +1190,28 @@
             // Do the click.
             PointerProperties[] properties = new PointerProperties[1];
             properties[0] = new PointerProperties();
-            secondTapUp.getPointerProperties(pointerIndex, properties[0]);
+            event.getPointerProperties(pointerIndex, properties[0]);
             PointerCoords[] coords = new PointerCoords[1];
             coords[0] = new PointerCoords();
             coords[0].x = clickLocation.x;
             coords[0].y = clickLocation.y;
-            MotionEvent event = MotionEvent.obtain(secondTapUp.getDownTime(),
-                    secondTapUp.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
-                    coords, 0, 0, 1.0f, 1.0f, secondTapUp.getDeviceId(), 0,
-                    secondTapUp.getSource(), secondTapUp.getFlags());
+            MotionEvent click_event = MotionEvent.obtain(event.getDownTime(),
+                    event.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
+                    coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0,
+                    event.getSource(), event.getFlags());
             final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS);
-            sendActionDownAndUp(event, policyFlags, targetAccessibilityFocus);
-            event.recycle();
+            sendActionDownAndUp(click_event, policyFlags, targetAccessibilityFocus);
+            click_event.recycle();
+            return;
         }
 
         public void clear() {
-            if (mDownEvent != null) {
-                mDownEvent.recycle();
-                mDownEvent = null;
-            }
-            if (mFirstTapEvent != null) {
-                mFirstTapEvent.recycle();
-                mFirstTapEvent = null;
-            }
+            mFirstTapDetected = false;
+            mDoubleTapDetected = false;
         }
 
         public boolean firstTapDetected() {
-            return mFirstTapEvent != null
-                && SystemClock.uptimeMillis() - mFirstTapEvent.getEventTime() < mDoubleTapTimeout;
+            return mFirstTapDetected;
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 07a7af4..bd10c63 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -994,6 +994,8 @@
      */
     int mConfigurationSeq = 0;
 
+    boolean mSuppressResizeConfigChanges = false;
+
     /**
      * Hardware-reported OpenGLES version.
      */
@@ -17515,6 +17517,15 @@
     }
 
     @Override
+    public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "suppressResizeConfigChanges()");
+        synchronized (this) {
+            mSuppressResizeConfigChanges = suppress;
+        }
+    }
+
+    @Override
     public void updatePersistentConfiguration(Configuration values) {
         enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
                 "updateConfiguration()");
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 9809c2e..5d106dc 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4181,8 +4181,12 @@
                 | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) == 0;
     }
 
-    private boolean relaunchActivityLocked(ActivityRecord r, int changes, boolean andResume,
-            boolean preserveWindow) {
+    private void relaunchActivityLocked(
+            ActivityRecord r, int changes, boolean andResume, boolean preserveWindow) {
+        if (mService.mSuppressResizeConfigChanges && preserveWindow) {
+            return;
+        }
+
         List<ResultInfo> results = null;
         List<ReferrerIntent> newIntents = null;
         if (andResume) {
@@ -4222,8 +4226,6 @@
             mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
             r.state = ActivityState.PAUSED;
         }
-
-        return true;
     }
 
     boolean willActivityBeVisibleLocked(IBinder token) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index af0a73e..17a3f56 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6156,41 +6156,6 @@
                     it.remove();
                 }
             }
-            // Give priority to system apps.
-            for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
-                PackageParser.Package pkg = it.next();
-                if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
-                    if (DEBUG_DEXOPT) {
-                        Log.i(TAG, "Adding system app " + sortedPkgs.size() + ": " + pkg.packageName);
-                    }
-                    sortedPkgs.add(pkg);
-                    it.remove();
-                }
-            }
-            // Give priority to updated system apps.
-            for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
-                PackageParser.Package pkg = it.next();
-                if (pkg.isUpdatedSystemApp()) {
-                    if (DEBUG_DEXOPT) {
-                        Log.i(TAG, "Adding updated system app " + sortedPkgs.size() + ": " + pkg.packageName);
-                    }
-                    sortedPkgs.add(pkg);
-                    it.remove();
-                }
-            }
-            // Give priority to apps that listen for boot complete.
-            intent = new Intent(Intent.ACTION_BOOT_COMPLETED);
-            pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
-            for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
-                PackageParser.Package pkg = it.next();
-                if (pkgNames.contains(pkg.packageName)) {
-                    if (DEBUG_DEXOPT) {
-                        Log.i(TAG, "Adding boot app " + sortedPkgs.size() + ": " + pkg.packageName);
-                    }
-                    sortedPkgs.add(pkg);
-                    it.remove();
-                }
-            }
             // Filter out packages that aren't recently used.
             filterRecentlyUsedApps(pkgs);
             // Add all remaining apps.
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 3974205..dbc3970 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4432,6 +4432,7 @@
         if (attrs.type == TYPE_STATUS_BAR) {
             if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
                 mForceStatusBarFromKeyguard = true;
+                mShowingLockscreen = true;
             }
             if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
                 mForceStatusBarTransparent = true;
@@ -4452,9 +4453,6 @@
                     mForceStatusBar = true;
                 }
             }
-            if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-                mShowingLockscreen = true;
-            }
             if (attrs.type == TYPE_DREAM) {
                 // If the lockscreen was showing when the dream started then wait
                 // for the dream to draw before hiding the lockscreen.
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4392ab4..ede377d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -22,6 +22,7 @@
 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerService.TAG;
 import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
+import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
 
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -255,10 +256,10 @@
     }
 
     /**
-     * Find the id of the task whose outside touch area (for resizing) (x, y)
-     * falls within. Returns -1 if the touch doesn't fall into a resizing area.
+     * Find the window whose outside touch area (for resizing) (x, y) falls within.
+     * Returns null if the touch doesn't fall into a resizing area.
      */
-    int taskIdForControlPoint(int x, int y) {
+    WindowState findWindowForControlPoint(int x, int y) {
         final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
             TaskStack stack = mStacks.get(stackNdx);
@@ -269,22 +270,31 @@
             for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                 final Task task = tasks.get(taskNdx);
                 if (task.isFullscreen()) {
-                    return -1;
+                    return null;
                 }
-                task.getBounds(mTmpRect);
-                mTmpRect.inset(-delta, -delta);
-                if (mTmpRect.contains(x, y)) {
-                    mTmpRect.inset(delta, delta);
-                    if (!mTmpRect.contains(x, y)) {
-                        return task.mTaskId;
+
+                // We need to use the visible frame on the window for any touch-related
+                // tests. Can't use the task's bounds because the original task bounds
+                // might be adjusted to fit the content frame. (One example is when the
+                // task is put to top-left quadrant, the actual visible frame would not
+                // start at (0,0) after it's adjusted for the status bar.)
+                WindowState win = task.getTopAppMainWindow();
+                if (win != null) {
+                    win.getVisibleBounds(mTmpRect, !BOUNDS_FOR_TOUCH);
+                    mTmpRect.inset(-delta, -delta);
+                    if (mTmpRect.contains(x, y)) {
+                        mTmpRect.inset(delta, delta);
+                        if (!mTmpRect.contains(x, y)) {
+                            return win;
+                        }
+                        // User touched inside the task. No need to look further,
+                        // focus transfer will be handled in ACTION_UP.
+                        return null;
                     }
-                    // User touched inside the task. No need to look further,
-                    // focus transfer will be handled in ACTION_UP.
-                    return -1;
                 }
             }
         }
-        return -1;
+        return null;
     }
 
     void setTouchExcludeRegion(Task focusedTask) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 6ebff42..d1111f7 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -437,6 +437,11 @@
         return mStack != null && mStack.mStackId == DOCKED_STACK_ID;
     }
 
+    WindowState getTopAppMainWindow() {
+        final int tokensCount = mAppTokens.size();
+        return tokensCount > 0 ? mAppTokens.get(tokensCount - 1).findMainWindow() : null;
+    }
+
     @Override
     public boolean isFullscreen() {
         return mFullscreen;
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index c4ff886..d1904d8 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -97,6 +97,7 @@
     private float mStartDragY;
     @CtrlType
     private int mCtrlType = CTRL_NONE;
+    private boolean mDragEnded = false;
 
     InputChannel mServerChannel;
     InputChannel mClientChannel;
@@ -119,7 +120,14 @@
             boolean handled = false;
 
             try {
-                boolean endDrag = false;
+                if (mDragEnded) {
+                    // The drag has ended but the clean-up message has not been processed by
+                    // window manager. Drop events that occur after this until window manager
+                    // has a chance to clean-up the input handle.
+                    handled = true;
+                    return;
+                }
+
                 final float newX = motionEvent.getRawX();
                 final float newY = motionEvent.getRawY();
 
@@ -135,7 +143,7 @@
                             Slog.w(TAG, "ACTION_MOVE @ {" + newX + ", " + newY + "}");
                         }
                         synchronized (mService.mWindowMap) {
-                            endDrag = notifyMoveLocked(newX, newY);
+                            mDragEnded = notifyMoveLocked(newX, newY);
                         }
                         try {
                             mService.mActivityManager.resizeTask(
@@ -147,18 +155,18 @@
                         if (DEBUG_TASK_POSITIONING) {
                             Slog.w(TAG, "ACTION_UP @ {" + newX + ", " + newY + "}");
                         }
-                        endDrag = true;
+                        mDragEnded = true;
                     } break;
 
                     case MotionEvent.ACTION_CANCEL: {
                         if (DEBUG_TASK_POSITIONING) {
                             Slog.w(TAG, "ACTION_CANCEL @ {" + newX + ", " + newY + "}");
                         }
-                        endDrag = true;
+                        mDragEnded = true;
                     } break;
                 }
 
-                if (endDrag) {
+                if (mDragEnded) {
                     synchronized (mService.mWindowMap) {
                         endDragLocked();
                     }
@@ -264,6 +272,8 @@
         mSideMargin = mService.dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics);
         mMinVisibleWidth = mService.dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
         mMinVisibleHeight = mService.dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
+
+        mDragEnded = false;
     }
 
     void unregister() {
@@ -294,6 +304,7 @@
             mDimLayer = null;
         }
         mCurrentDimSide = CTRL_NONE;
+        mDragEnded = true;
 
         // Resume rotations after a drag.
         if (WindowManagerService.DEBUG_ORIENTATION) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d510c4a..22f9f50 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6885,37 +6885,29 @@
     }
 
     boolean startMovingTask(IWindow window, float startX, float startY) {
-        WindowState callingWin = null;
+        WindowState win = null;
         synchronized (mWindowMap) {
-            callingWin = windowForClientLocked(null, window, false);
-            if (!startPositioningLocked(callingWin, false /*resize*/, startX, startY)) {
+            win = windowForClientLocked(null, window, false);
+            if (!startPositioningLocked(win, false /*resize*/, startX, startY)) {
                 return false;
             }
         }
         try {
-            mActivityManager.setFocusedTask(callingWin.getTask().mTaskId);
+            mActivityManager.setFocusedTask(win.getTask().mTaskId);
         } catch(RemoteException e) {}
         return true;
     }
 
     private void startResizingTask(DisplayContent displayContent, int startX, int startY) {
-        int taskId = -1;
-        AppWindowToken atoken = null;
+        WindowState win = null;
         synchronized (mWindowMap) {
-            taskId = displayContent.taskIdForControlPoint(startX, startY);
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null || task.mAppTokens == null) {
-                return;
-            }
-            AppTokenList tokens = task.mAppTokens;
-            atoken = tokens.get(tokens.size() - 1);
-            WindowState win = atoken.findMainWindow();
+            win = displayContent.findWindowForControlPoint(startX, startY);
             if (!startPositioningLocked(win, true /*resize*/, startX, startY)) {
                 return;
             }
         }
         try {
-            mActivityManager.setFocusedTask(taskId);
+            mActivityManager.setFocusedTask(win.getTask().mTaskId);
         } catch(RemoteException e) {}
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 64440d3..c73dbaf 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -943,7 +943,6 @@
      */
     void getVisibleBounds(Rect bounds, boolean forTouch) {
         boolean intersectWithStackBounds = mAppToken != null && mAppToken.mCropWindowsToStack;
-        boolean isFreeform = false;
         bounds.setEmpty();
         mTmpRect.setEmpty();
         if (intersectWithStackBounds) {
@@ -955,13 +954,9 @@
             }
         }
 
-        final Task task = getTask();
-        if (task != null) {
-            task.getBounds(bounds);
-            isFreeform = task.inFreeformWorkspace();
-            if (intersectWithStackBounds) {
-                bounds.intersect(mTmpRect);
-            }
+        bounds.set(mVisibleFrame);
+        if (intersectWithStackBounds) {
+            bounds.intersect(mTmpRect);
         }
 
         if (bounds.isEmpty()) {
@@ -971,7 +966,7 @@
             }
             return;
         }
-        if (forTouch && isFreeform) {
+        if (forTouch && inFreeformWorkspace()) {
             final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
             final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics);
             bounds.inset(-delta, -delta);
diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
index 3fd0f84..5cbb277 100644
--- a/services/core/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/core/jni/com_android_server_AlarmManagerService.cpp
@@ -460,7 +460,7 @@
     return result;
 }
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     {"init", "()J", (void*)android_server_AlarmManagerService_init},
     {"close", "(J)V", (void*)android_server_AlarmManagerService_close},
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
index 8f4fb51..ed79ceb 100644
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -204,7 +204,7 @@
 
 const char* const kClassPathName = "com/android/server/AssetAtlasService";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nUploadAtlas", "(Landroid/view/GraphicBuffer;Landroid/graphics/Bitmap;)Z",
             (void*) com_android_server_AssetAtlasService_upload },
 };
diff --git a/services/core/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp
index f5121cd..7104870 100644
--- a/services/core/jni/com_android_server_ConsumerIrService.cpp
+++ b/services/core/jni/com_android_server_ConsumerIrService.cpp
@@ -100,7 +100,7 @@
     return freqsOut.getJavaArray();
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "halOpen", "()J", (void *)halOpen },
     { "halTransmit", "(JI[I)I", (void *)halTransmit },
     { "halGetCarrierFrequencies", "(J)[I", (void *)halGetCarrierFrequencies},
diff --git a/services/core/jni/com_android_server_PersistentDataBlockService.cpp b/services/core/jni/com_android_server_PersistentDataBlockService.cpp
index 4ccfa56..06de592 100644
--- a/services/core/jni/com_android_server_PersistentDataBlockService.cpp
+++ b/services/core/jni/com_android_server_PersistentDataBlockService.cpp
@@ -97,7 +97,7 @@
         return wipe_block_device(fd);
     }
 
-    static JNINativeMethod sMethods[] = {
+    static const JNINativeMethod sMethods[] = {
          /* name, signature, funcPtr */
         {"nativeGetBlockDeviceSize", "(Ljava/lang/String;)J", (void*)com_android_server_PersistentDataBlockService_getBlockDeviceSize},
         {"nativeWipe", "(Ljava/lang/String;)I", (void*)com_android_server_PersistentDataBlockService_wipe},
diff --git a/services/core/jni/com_android_server_SerialService.cpp b/services/core/jni/com_android_server_SerialService.cpp
index d48d159..1bd7a59 100644
--- a/services/core/jni/com_android_server_SerialService.cpp
+++ b/services/core/jni/com_android_server_SerialService.cpp
@@ -55,7 +55,7 @@
 }
 
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "native_open",                "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
                                     (void*)android_server_SerialService_open },
 };
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 64514a9..c7d6b95 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -37,7 +37,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService },
 };
diff --git a/services/core/jni/com_android_server_UsbDeviceManager.cpp b/services/core/jni/com_android_server_UsbDeviceManager.cpp
index a1bff9d..3733a55 100644
--- a/services/core/jni/com_android_server_UsbDeviceManager.cpp
+++ b/services/core/jni/com_android_server_UsbDeviceManager.cpp
@@ -118,7 +118,7 @@
     return result;
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "nativeGetAccessoryStrings",  "()[Ljava/lang/String;",
                                     (void*)android_server_UsbDeviceManager_getAccessoryStrings },
     { "nativeOpenAccessory",        "()Landroid/os/ParcelFileDescriptor;",
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
index d8c172f..795f6aa 100644
--- a/services/core/jni/com_android_server_UsbHostManager.cpp
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -186,7 +186,7 @@
         gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "monitorUsbHostBus", "()V", (void*)android_server_UsbHostManager_monitorUsbHostBus },
     { "nativeOpenDevice",  "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
                                   (void*)android_server_UsbHostManager_openDevice },
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index fb1166b..64278ed 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -46,7 +46,7 @@
     vibrator_off();
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "vibratorExists", "()Z", (void*)vibratorExists },
     { "vibratorOn", "(J)V", (void*)vibratorOn },
     { "vibratorOff", "()V", (void*)vibratorOff }
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index dfc5ef6..5c43659 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -170,7 +170,7 @@
     return mergedreasonpos - mergedreason;
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup },
 };
 
diff --git a/services/core/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp
index 7faeb49..2d0dfd2 100644
--- a/services/core/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/core/jni/com_android_server_connectivity_Vpn.cpp
@@ -350,7 +350,7 @@
 
 //------------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"jniCreate", "(I)I", (void *)create},
     {"jniGetName", "(I)Ljava/lang/String;", (void *)getName},
     {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index f2d0f06..b72cf4d 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -384,7 +384,7 @@
     return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ;
 }
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
       "(Lcom/android/server/hdmi/HdmiCecController;Landroid/os/MessageQueue;)J",
diff --git a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
index 11388d8..bdc109d 100644
--- a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
+++ b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
@@ -120,7 +120,7 @@
 }
 
 
-static JNINativeMethod gInputApplicationHandleMethods[] = {
+static const JNINativeMethod gInputApplicationHandleMethods[] = {
     /* name, signature, funcPtr */
     { "nativeDispose", "()V",
             (void*) android_server_InputApplicationHandle_nativeDispose },
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index e29d0a9..1d4f047 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1369,7 +1369,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gInputManagerMethods[] = {
+static const JNINativeMethod gInputManagerMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
             "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)J",
diff --git a/services/core/jni/com_android_server_input_InputWindowHandle.cpp b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
index 01c51cf..92ef7f1 100644
--- a/services/core/jni/com_android_server_input_InputWindowHandle.cpp
+++ b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
@@ -210,7 +210,7 @@
 }
 
 
-static JNINativeMethod gInputWindowHandleMethods[] = {
+static const JNINativeMethod gInputWindowHandleMethods[] = {
     /* name, signature, funcPtr */
     { "nativeDispose", "()V",
             (void*) android_server_InputWindowHandle_nativeDispose },
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index b2b2783..3f074f5 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -126,7 +126,7 @@
     }
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "init_native", "()J", (void*)init_native },
     { "finalize_native", "(J)V", (void*)finalize_native },
     { "setLight_native", "(JIIIIII)V", (void*)setLight_native },
diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
index c0a0c9c..774577d 100644
--- a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
+++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -1023,7 +1023,7 @@
   env->ReleaseIntArrayElements(geofenceIdsArray, geofenceIds, 0 /*mode*/);
 }
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
   //{"name", "signature", functionPointer }
   {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)},
   {"nativeInit", "()V", reinterpret_cast<void*>(Init)},
diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
index 5c27b1f..b8d4196 100644
--- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -1434,7 +1434,7 @@
     env->ReleaseStringUTFChars(config_content, data);
 }
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
     {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 1662755..2fdb8e2 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -166,7 +166,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gPowerManagerServiceMethods[] = {
+static const JNINativeMethod gPowerManagerServiceMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit", "()V",
             (void*) nativeInit },
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 507bc9c..89b2a47 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -662,7 +662,7 @@
     delete tvInputHal;
 }
 
-static JNINativeMethod gTvInputHalMethods[] = {
+static const JNINativeMethod gTvInputHalMethods[] = {
     /* name, signature, funcPtr */
     { "nativeOpen", "(Landroid/os/MessageQueue;)J",
             (void*) nativeOpen },
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b0a04c7..3f70e0c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -271,7 +271,6 @@
     final Context mContext;
     final PackageManager mPackageManager;
     final UserManager mUserManager;
-    final PowerManager.WakeLock mWakeLock;
 
     final LocalService mLocalService;
 
@@ -995,7 +994,7 @@
         boolean removed = false;
         if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
         DevicePolicyData policy = getUserData(userHandle);
-        IPackageManager pm = AppGlobals.getPackageManager();
+        IPackageManager pm = getIPackageManager();
         synchronized (this) {
             for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
                 ActiveAdmin aa = policy.mAdminList.get(i);
@@ -1071,7 +1070,7 @@
 
     /** Unit test will override it to inject a mock. */
     @VisibleForTesting
-    IWindowManager newIWindowManager() {
+    IWindowManager getIWindowManager() {
         return IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
     }
 
@@ -1083,6 +1082,12 @@
 
     /** Unit test will override it to inject a mock. */
     @VisibleForTesting
+    IPackageManager getIPackageManager() {
+        return AppGlobals.getPackageManager();
+    }
+
+    /** Unit test will override it to inject a mock. */
+    @VisibleForTesting
     LockPatternUtils newLockPatternUtils(Context context) {
         return new LockPatternUtils(context);
     }
@@ -1129,13 +1134,33 @@
     }
 
     @VisibleForTesting
-    WakeLock powerManagerNewWakeLock(int levelAndFlags, String tag) {
-        return mContext.getSystemService(PowerManager.class).newWakeLock(levelAndFlags, tag);
+    void powerManagerGoToSleep(long time, int reason, int flags) {
+        mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags);
     }
 
     @VisibleForTesting
-    void powerManagerGoToSleep(long time, int reason, int flags) {
-        mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags);
+    boolean systemPropertiesGetBoolean(String key, boolean def) {
+        return SystemProperties.getBoolean(key, def);
+    }
+
+    @VisibleForTesting
+    long systemPropertiesGetLong(String key, long def) {
+        return SystemProperties.getLong(key, def);
+    }
+
+    @VisibleForTesting
+    String systemPropertiesGet(String key, String def) {
+        return SystemProperties.get(key, def);
+    }
+
+    @VisibleForTesting
+    String systemPropertiesGet(String key) {
+        return SystemProperties.get(key);
+    }
+
+    @VisibleForTesting
+    void systemPropertiesSet(String key, String value) {
+        SystemProperties.set(key, value);
     }
 
     /**
@@ -1145,14 +1170,16 @@
         mContext = context;
         mHandler = new Handler(getMyLooper());
         mOwners = newOwners();
-        mUserManager = getUserManager();
-        mPackageManager = getPackageManager();
-        mHasFeature = mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
-        mPowerManagerInternal = getPowerManagerInternal();
-        mWakeLock = powerManagerNewWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
-        mIWindowManager = newIWindowManager();
-        mNotificationManager = getNotificationManager();
+
+        mUserManager = Preconditions.checkNotNull(getUserManager());
+        mPackageManager = Preconditions.checkNotNull(getPackageManager());
+        mPowerManagerInternal = Preconditions.checkNotNull(getPowerManagerInternal());
+        mIWindowManager = Preconditions.checkNotNull(getIWindowManager());
+        mNotificationManager = Preconditions.checkNotNull(getNotificationManager());
+
         mLocalService = new LocalService();
+
+        mHasFeature = mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
         if (!mHasFeature) {
             // Skip the rest of the initialization
             return;
@@ -1862,7 +1889,7 @@
         // Ensure the status of the camera is synced down to the system. Interested native services
         // should monitor this value and act accordingly.
         String cameraPropertyForUser = SYSTEM_PROP_DISABLE_CAMERA_PREFIX + policy.mUserHandle;
-        boolean systemState = SystemProperties.getBoolean(cameraPropertyForUser, false);
+        boolean systemState = systemPropertiesGetBoolean(cameraPropertyForUser, false);
         boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
         if (cameraDisabled != systemState) {
             long token = binderClearCallingIdentity();
@@ -1870,7 +1897,7 @@
                 String value = cameraDisabled ? "1" : "0";
                 if (DBG) Slog.v(LOG_TAG, "Change in camera state ["
                         + cameraPropertyForUser + "] = " + value);
-                SystemProperties.set(cameraPropertyForUser, value);
+                systemPropertiesSet(cameraPropertyForUser, value);
             } finally {
                 binderRestoreCallingIdentity(token);
             }
@@ -3231,7 +3258,7 @@
     }
 
     private boolean isExtStorageEncrypted() {
-        String state = SystemProperties.get("vold.decrypt");
+        String state = systemPropertiesGet("vold.decrypt");
         return !"".equals(state);
     }
 
@@ -3969,7 +3996,7 @@
      * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
      */
     private int getEncryptionStatus() {
-        String status = SystemProperties.get("ro.crypto.state", "unsupported");
+        String status = systemPropertiesGet("ro.crypto.state", "unsupported");
         if ("encrypted".equalsIgnoreCase(status)) {
             final long token = binderClearCallingIdentity();
             try {
@@ -4377,7 +4404,7 @@
         }
         boolean isInitializerSystemApp;
         try {
-            isInitializerSystemApp = isSystemApp(AppGlobals.getPackageManager(),
+            isInitializerSystemApp = isSystemApp(getIPackageManager(),
                     initializer.getPackageName(), binderGetCallingUserHandle().getIdentifier());
         } catch (RemoteException | IllegalArgumentException e) {
             isInitializerSystemApp = false;
@@ -4528,7 +4555,7 @@
         final long ident = binderClearCallingIdentity();
         try {
             clearUserRestrictions(userHandle);
-            AppGlobals.getPackageManager().updatePermissionFlagsForAllApps(
+            getIPackageManager().updatePermissionFlagsForAllApps(
                     PackageManager.FLAG_PERMISSION_POLICY_FIXED,
                     0  /* flagValues */, userHandle.getIdentifier());
         } catch (RemoteException re) {
@@ -4596,7 +4623,7 @@
             long id = binderClearCallingIdentity();
             try {
                 if (!isDeviceOwner(activeAdmin.info.getPackageName())) {
-                    IPackageManager ipm = AppGlobals.getPackageManager();
+                    IPackageManager ipm = getIPackageManager();
                     ipm.setComponentEnabledSetting(who,
                             PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                             PackageManager.DONT_KILL_APP, userId);
@@ -4857,7 +4884,7 @@
 
     private void enableIfNecessary(String packageName, int userId) {
         try {
-            IPackageManager ipm = AppGlobals.getPackageManager();
+            IPackageManager ipm = getIPackageManager();
             ApplicationInfo ai = ipm.getApplicationInfo(packageName,
                     PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
                     userId);
@@ -4919,7 +4946,7 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            IPackageManager pm = AppGlobals.getPackageManager();
+            IPackageManager pm = getIPackageManager();
             long id = binderClearCallingIdentity();
             try {
                 pm.addPersistentPreferredActivity(filter, activity, userHandle);
@@ -4938,7 +4965,7 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            IPackageManager pm = AppGlobals.getPackageManager();
+            IPackageManager pm = getIPackageManager();
             long id = binderClearCallingIdentity();
             try {
                 pm.clearPackagePersistentPreferredActivities(packageName, userHandle);
@@ -5074,7 +5101,7 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            IPackageManager pm = AppGlobals.getPackageManager();
+            IPackageManager pm = getIPackageManager();
             long id = binderClearCallingIdentity();
             try {
                 UserInfo parent = mUserManager.getProfileParent(callingUserId);
@@ -5105,7 +5132,7 @@
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            IPackageManager pm = AppGlobals.getPackageManager();
+            IPackageManager pm = getIPackageManager();
             long id = binderClearCallingIdentity();
             try {
                 UserInfo parent = mUserManager.getProfileParent(callingUserId);
@@ -5144,7 +5171,7 @@
                 userIdToCheck = user.profileGroupId;
             }
 
-            IPackageManager pm = AppGlobals.getPackageManager();
+            IPackageManager pm = getIPackageManager();
             for (String enabledPackage : enabledPackages) {
                 boolean systemService = false;
                 try {
@@ -5276,7 +5303,7 @@
                     List<AccessibilityServiceInfo> installedServices =
                             accessibilityManager.getInstalledAccessibilityServiceList();
 
-                    IPackageManager pm = AppGlobals.getPackageManager();
+                    IPackageManager pm = getIPackageManager();
                     if (installedServices != null) {
                         for (AccessibilityServiceInfo service : installedServices) {
                             ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
@@ -5425,7 +5452,7 @@
                 List<InputMethodInfo> imes = inputMethodManager.getInputMethodList();
                 long id = binderClearCallingIdentity();
                 try {
-                    IPackageManager pm = AppGlobals.getPackageManager();
+                    IPackageManager pm = getIPackageManager();
                     if (imes != null) {
                         for (InputMethodInfo ime : imes) {
                             ServiceInfo serviceInfo = ime.getServiceInfo();
@@ -5472,7 +5499,7 @@
         long id = binderClearCallingIdentity();
         try {
             String profileOwnerPkg = profileOwnerComponent.getPackageName();
-            final IPackageManager ipm = AppGlobals.getPackageManager();
+            final IPackageManager ipm = getIPackageManager();
             IActivityManager activityManager = getIActivityManager();
 
             final int userHandle = user.getIdentifier();
@@ -5624,8 +5651,8 @@
                         // Send out notifications however as some clients may want to reread the
                         // value which actually changed due to a restriction having been applied.
                         final String property = Settings.Secure.SYS_PROP_SETTING_VERSION;
-                        long version = SystemProperties.getLong(property, 0) + 1;
-                        SystemProperties.set(property, Long.toString(version));
+                        long version = systemPropertiesGetLong(property, 0) + 1;
+                        systemPropertiesSet(property, Long.toString(version));
 
                         final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED;
                         Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
@@ -5660,7 +5687,7 @@
 
             long id = binderClearCallingIdentity();
             try {
-                IPackageManager pm = AppGlobals.getPackageManager();
+                IPackageManager pm = getIPackageManager();
                 return pm.setApplicationHiddenSettingAsUser(packageName, hidden, callingUserId);
             } catch (RemoteException re) {
                 // shouldn't happen
@@ -5681,7 +5708,7 @@
 
             long id = binderClearCallingIdentity();
             try {
-                IPackageManager pm = AppGlobals.getPackageManager();
+                IPackageManager pm = getIPackageManager();
                 return pm.getApplicationHiddenSettingAsUser(packageName, callingUserId);
             } catch (RemoteException re) {
                 // shouldn't happen
@@ -5718,7 +5745,7 @@
                     primaryUser = um.getUserInfo(userId);
                 }
 
-                IPackageManager pm = AppGlobals.getPackageManager();
+                IPackageManager pm = getIPackageManager();
                 if (!isSystemApp(pm, packageName, primaryUser.id)) {
                     throw new IllegalArgumentException("Only system apps can be enabled this way.");
                 }
@@ -5755,7 +5782,7 @@
                     primaryUser = um.getUserInfo(userId);
                 }
 
-                IPackageManager pm = AppGlobals.getPackageManager();
+                IPackageManager pm = getIPackageManager();
                 List<ResolveInfo> activitiesToEnable = pm.queryIntentActivities(intent,
                         intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                         0, // no flags
@@ -5851,7 +5878,7 @@
 
             long id = binderClearCallingIdentity();
             try {
-                IPackageManager pm = AppGlobals.getPackageManager();
+                IPackageManager pm = getIPackageManager();
                 pm.setBlockUninstallForUser(packageName, uninstallBlocked, userId);
             } catch (RemoteException re) {
                 // Shouldn't happen.
@@ -5876,7 +5903,7 @@
 
             long id = binderClearCallingIdentity();
             try {
-                IPackageManager pm = AppGlobals.getPackageManager();
+                IPackageManager pm = getIPackageManager();
                 return pm.getBlockUninstallForUser(packageName, userId);
             } catch (RemoteException re) {
                 // Shouldn't happen.
@@ -6560,7 +6587,7 @@
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             long ident = binderClearCallingIdentity();
             try {
-                final ApplicationInfo ai = AppGlobals.getPackageManager()
+                final ApplicationInfo ai = getIPackageManager()
                         .getApplicationInfo(packageName, 0, user.getIdentifier());
                 final int targetSdkVersion = ai == null ? 0 : ai.targetSdkVersion;
                 if (targetSdkVersion < android.os.Build.VERSION_CODES.M) {
@@ -6607,7 +6634,7 @@
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             long ident = binderClearCallingIdentity();
             try {
-                int granted = AppGlobals.getPackageManager().checkPermission(permission,
+                int granted = getIPackageManager().checkPermission(permission,
                         packageName, user.getIdentifier());
                 int permFlags = packageManager.getPermissionFlags(permission, packageName, user);
                 if ((permFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED)
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index cb2c9b7..c147bcc 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -67,8 +67,26 @@
             </intent-filter>
         </receiver>
 
-        <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmin"
-                android:permission="android.permission.BIND_DEVICE_ADMIN">
+        <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                android:resource="@xml/device_admin_sample" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+
+        <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin2"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                android:resource="@xml/device_admin_sample" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+
+        <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin3"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
             <meta-data android:name="android.app.device_admin"
                 android:resource="@xml/device_admin_sample" />
             <intent-filter>
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index cb439eb..7e730f6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -20,6 +20,7 @@
 import android.app.IActivityManager;
 import android.app.NotificationManager;
 import android.content.Context;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.os.Looper;
 import android.os.PowerManager.WakeLock;
@@ -45,9 +46,9 @@
         public static final String DEVICE_OWNER_FILE = "device_owner2.xml";
         public static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml";
 
-        final private File mLegacyFile;
-        final private File mDeviceOwnerFile;
-        final private File mProfileOwnerBase;
+        private final File mLegacyFile;
+        private final File mDeviceOwnerFile;
+        private final File mProfileOwnerBase;
 
         public OwnersTestable(Context context, File dataDir) {
             super(context);
@@ -96,47 +97,52 @@
     }
 
     @Override
-    protected Owners newOwners() {
+    Owners newOwners() {
         return new OwnersTestable(getContext(), dataDir);
     }
 
     @Override
-    protected UserManager getUserManager() {
+    UserManager getUserManager() {
         return getContext().userManager;
     }
 
     @Override
-    protected PackageManager getPackageManager() {
+    PackageManager getPackageManager() {
         return getContext().packageManager;
     }
 
     @Override
-    protected PowerManagerInternal getPowerManagerInternal() {
+    PowerManagerInternal getPowerManagerInternal() {
         return getContext().powerManagerInternal;
     }
 
     @Override
-    protected NotificationManager getNotificationManager() {
+    NotificationManager getNotificationManager() {
         return getContext().notificationManager;
     }
 
     @Override
-    protected IWindowManager newIWindowManager() {
+    IWindowManager getIWindowManager() {
         return getContext().iwindowManager;
     }
 
     @Override
-    protected IActivityManager getIActivityManager() {
+    IActivityManager getIActivityManager() {
         return getContext().iactivityManager;
     }
 
     @Override
-    protected LockPatternUtils newLockPatternUtils(Context context) {
+    IPackageManager getIPackageManager() {
+        return getContext().ipackageManager;
+    }
+
+    @Override
+    LockPatternUtils newLockPatternUtils(Context context) {
         return getContext().lockPatternUtils;
     }
 
     @Override
-    protected Looper getMyLooper() {
+    Looper getMyLooper() {
         return Looper.getMainLooper();
     }
 
@@ -181,12 +187,32 @@
     }
 
     @Override
-    WakeLock powerManagerNewWakeLock(int levelAndFlags, String tag) {
-        return getContext().powerManager.newWakeLock(levelAndFlags, tag);
+    void powerManagerGoToSleep(long time, int reason, int flags) {
+        getContext().powerManager.goToSleep(time, reason, flags);
     }
 
     @Override
-    void powerManagerGoToSleep(long time, int reason, int flags) {
-        getContext().powerManager.goToSleep(time, reason, flags);
+    boolean systemPropertiesGetBoolean(String key, boolean def) {
+        return getContext().systemProperties.getBoolean(key, def);
+    }
+
+    @Override
+    long systemPropertiesGetLong(String key, long def) {
+        return getContext().systemProperties.getLong(key, def);
+    }
+
+    @Override
+    String systemPropertiesGet(String key, String def) {
+        return getContext().systemProperties.get(key, def);
+    }
+
+    @Override
+    String systemPropertiesGet(String key) {
+        return getContext().systemProperties.get(key);
+    }
+
+    @Override
+    void systemPropertiesSet(String key, String value) {
+        getContext().systemProperties.set(key, value);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 7cce56c..0da459d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -13,33 +13,39 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package com.android.server.devicepolicy;
 
 import com.android.server.LocalServices;
 
+import android.Manifest.permission;
+import android.app.Activity;
 import android.app.admin.DeviceAdminReceiver;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManagerInternal;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.os.UserHandle;
+import android.os.Bundle;
 
 import org.mockito.ArgumentCaptor;
 
 import java.util.List;
 
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 /**
- * Tests for {@link DevicePolicyManager} and {@link DevicePolicyManagerService}.
+ * Tests for DevicePolicyManager( and DevicePolicyManagerService).
  *
  m FrameworksServicesTests &&
  adb install \
@@ -51,9 +57,13 @@
  */
 public class DevicePolicyManagerTest extends DpmTestBase {
 
+
     private DpmMockContext mContext;
     public DevicePolicyManager dpm;
     public DevicePolicyManagerServiceTestable dpms;
+    public ComponentName admin1;
+    public ComponentName admin2;
+    public ComponentName admin3;
 
     @Override
     protected void setUp() throws Exception {
@@ -67,6 +77,59 @@
         LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
         dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir);
         dpm = new DevicePolicyManagerTestable(mContext, dpms);
+
+        admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class);
+        admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class);
+        admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class);
+
+        setUpPackageManagerForAdmin(admin1);
+        setUpPackageManagerForAdmin(admin2);
+        setUpPackageManagerForAdmin(admin3);
+
+        setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
+    }
+
+    /**
+     * Set up a mock result for {@link PackageManager#queryBroadcastReceivers}.  We'll return
+     * the actual ResolveInfo for the admin component, but we need to mock PM so it'll return
+     * it for user {@link DpmMockContext#CALLER_USER_HANDLE}.
+     */
+    private void setUpPackageManagerForAdmin(ComponentName admin) {
+        final Intent resolveIntent = new Intent();
+        resolveIntent.setComponent(admin);
+        final List<ResolveInfo> realResolveInfo =
+                mRealTestContext.getPackageManager().queryBroadcastReceivers(
+                        resolveIntent,
+                        PackageManager.GET_META_DATA);
+        assertNotNull(realResolveInfo);
+        assertEquals(1, realResolveInfo.size());
+
+        // We need to rewrite the UID in the activity info.
+        realResolveInfo.get(0).activityInfo.applicationInfo.uid = DpmMockContext.CALLER_UID;
+
+        doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers(
+                MockUtils.checkIntentComponent(admin),
+                eq(PackageManager.GET_META_DATA
+                        | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
+                eq(DpmMockContext.CALLER_USER_HANDLE)
+        );
+    }
+
+    /**
+     * Set up a mock result for {@link IPackageManager#getApplicationInfo} for user
+     * {@link DpmMockContext#CALLER_USER_HANDLE}.
+     */
+    private void setUpApplicationInfo(int enabledSetting) throws Exception {
+        final ApplicationInfo ai = mRealTestContext.getPackageManager().getApplicationInfo(
+                admin1.getPackageName(),
+                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
+
+        ai.enabledSetting = enabledSetting;
+
+        doReturn(ai).when(mContext.ipackageManager).getApplicationInfo(
+                eq(admin1.getPackageName()),
+                eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
+                eq(DpmMockContext.CALLER_USER_HANDLE));
     }
 
     public void testHasNoFeature() {
@@ -84,13 +147,11 @@
      * Caller doesn't have proper permissions.
      */
     public void testSetActiveAdmin_SecurityException() {
-        final ComponentName admin = new ComponentName(mRealTestContext, DummyDeviceAdmin.class);
-
         // 1. Failure cases.
 
         // Caller doesn't have MANAGE_DEVICE_ADMINS.
         try {
-            dpm.setActiveAdmin(admin, false);
+            dpm.setActiveAdmin(admin1, false);
             fail("Didn't throw SecurityException");
         } catch (SecurityException expected) {
         }
@@ -98,62 +159,246 @@
         // Caller has MANAGE_DEVICE_ADMINS, but for different user.
         mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
         try {
-            dpm.setActiveAdmin(admin, false, DpmMockContext.CALLER_USER_HANDLE + 1);
+            dpm.setActiveAdmin(admin1, false, DpmMockContext.CALLER_USER_HANDLE + 1);
             fail("Didn't throw SecurityException");
         } catch (SecurityException expected) {
         }
     }
 
-    public void testSetActiveAdmin() {
-        final ComponentName admin = new ComponentName(mRealTestContext, DummyDeviceAdmin.class);
-
-        // 1. Prepare mock package manager (and other mocks)
-
+    /**
+     * Test for:
+     * {@link DevicePolicyManager#setActiveAdmin}
+     *   with replace=false and replace=true
+     * {@link DevicePolicyManager#isAdminActive}
+     * {@link DevicePolicyManager#isAdminActiveAsUser}
+     * {@link DevicePolicyManager#getActiveAdmins}
+     * {@link DevicePolicyManager#getActiveAdminsAsUser}
+     */
+    public void testSetActiveAdmin() throws Exception {
+        // 1. Make sure the caller has proper permissions.
         mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
 
-        // Create ResolveInfo for the admin.
-        final Intent resolveIntent = new Intent();
-        resolveIntent.setComponent(admin);
-        final List<ResolveInfo> realResolveInfo =
-                mRealTestContext.getPackageManager().queryBroadcastReceivers(
-                        resolveIntent,
-                        PackageManager.GET_META_DATA
-                            | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
-        assertNotNull(realResolveInfo);
-        assertEquals(1, realResolveInfo.size());
-
-        // We need to rewrite the UID in the activity info.
-        realResolveInfo.get(0).activityInfo.applicationInfo.uid = DpmMockContext.CALLER_UID;
-
-        doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers(
-                any(Intent.class), // TODO check the intent too.
-                eq(PackageManager.GET_META_DATA
-                        | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
-                eq(DpmMockContext.CALLER_USER_HANDLE)
-        );
-
-        // 2. Everything is ready; call the method.
-        dpm.setActiveAdmin(admin, false);
+        // 2. Call the API.
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
 
         // 3. Verify internal calls.
 
         // Check if the boradcast is sent.
-        final ArgumentCaptor<Intent> intentCap = ArgumentCaptor.forClass(Intent.class);
-        final ArgumentCaptor<UserHandle> uhCap = ArgumentCaptor.forClass(UserHandle.class);
-
-        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
-                intentCap.capture(),
+        verify(mContext.spiedContext).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+        verify(mContext.spiedContext).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
                 MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
 
-        // First call from saveSettingsLocked().
-        assertEquals(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED,
-                intentCap.getAllValues().get(0).getAction());
-
-        // Second call from setActiveAdmin/sendAdminCommandLocked()
-        assertEquals(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
-                intentCap.getAllValues().get(1).getAction());
+        verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting(
+                eq(admin1.getPackageName()),
+                eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
+                eq(PackageManager.DONT_KILL_APP),
+                eq(DpmMockContext.CALLER_USER_HANDLE),
+                anyString());
 
         // TODO Verify other calls too.
+
+        // Make sure it's active admin1.
+        assertTrue(dpm.isAdminActive(admin1));
+        assertFalse(dpm.isAdminActive(admin2));
+        assertFalse(dpm.isAdminActive(admin3));
+
+        // But not admin1 for a different user.
+
+        // For this to work, caller needs android.permission.INTERACT_ACROSS_USERS_FULL.
+        // (Because we're checking a different user's status from CALLER_USER_HANDLE.)
+        mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");
+
+        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE + 1));
+        assertFalse(dpm.isAdminActiveAsUser(admin2, DpmMockContext.CALLER_USER_HANDLE + 1));
+
+        mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
+
+        // Next, add one more admin.
+        // Before doing so, update the application info, now it's enabled.
+        setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+
+        dpm.setActiveAdmin(admin2, /* replace =*/ false);
+
+        // Now we have two admins.
+        assertTrue(dpm.isAdminActive(admin1));
+        assertTrue(dpm.isAdminActive(admin2));
+        assertFalse(dpm.isAdminActive(admin3));
+
+        // Admin2 was already enabled, so setApplicationEnabledSetting() shouldn't have called
+        // again.  (times(1) because it was previously called for admin1)
+        verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting(
+                eq(admin1.getPackageName()),
+                eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
+                eq(PackageManager.DONT_KILL_APP),
+                eq(DpmMockContext.CALLER_USER_HANDLE),
+                anyString());
+
+        // 4. Add the same admin1 again without replace, which should throw.
+        try {
+            dpm.setActiveAdmin(admin1, /* replace =*/ false);
+            fail("Didn't throw");
+        } catch (IllegalArgumentException expected) {
+        }
+
+        // 5. Add the same admin1 again with replace, which should succeed.
+        dpm.setActiveAdmin(admin1, /* replace =*/ true);
+
+        // TODO make sure it's replaced.
+
+        // 6. Test getActiveAdmins()
+        List<ComponentName> admins = dpm.getActiveAdmins();
+        assertEquals(2, admins.size());
+        assertEquals(admin1, admins.get(0));
+        assertEquals(admin2, admins.get(1));
+
+        // Another user has no admins.
+        mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");
+
+        assertEquals(0, DpmTestUtils.getListSizeAllowingNull(
+                dpm.getActiveAdminsAsUser(DpmMockContext.CALLER_USER_HANDLE + 1)));
+
+        mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
+    }
+
+    /**
+     * Test for:
+     * {@link DevicePolicyManager#setActiveAdmin}
+     *   with replace=false
+     */
+    public void testSetActiveAdmin_twiceWithoutReplace() throws Exception {
+        // 1. Make sure the caller has proper permissions.
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+        assertTrue(dpm.isAdminActive(admin1));
+
+        // Add the same admin1 again without replace, which should throw.
+        try {
+            dpm.setActiveAdmin(admin1, /* replace =*/ false);
+            fail("Didn't throw");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    /**
+     * Test for:
+     * {@link DevicePolicyManager#removeActiveAdmin}
+     */
+    public void testRemoveActiveAdmin_SecurityException() {
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        // Add admin.
+
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+        assertTrue(dpm.isAdminActive(admin1));
+
+        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+        // Directly call the DPMS method with a different userid, which should fail.
+        try {
+            dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE + 1);
+            fail("Didn't throw SecurityException");
+        } catch (SecurityException expected) {
+        }
+
+        // Try to remove active admin with a different caller userid should fail too, without
+        // having MANAGE_DEVICE_ADMINS.
+        mContext.callerPermissions.clear();
+
+        mContext.binder.callingUid = 1234567;
+        try {
+            dpm.removeActiveAdmin(admin1);
+            fail("Didn't throw SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    /**
+     * Test for:
+     * {@link DevicePolicyManager#removeActiveAdmin}
+     */
+    public void testRemoveActiveAdmin_fromDifferentUserWithMINTERACT_ACROSS_USERS_FULL() {
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        // Add admin1.
+
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+        assertTrue(dpm.isAdminActive(admin1));
+        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+        // Different user, but should work, because caller has proper permissions.
+        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
+        mContext.binder.callingUid = 1234567;
+        dpm.removeActiveAdmin(admin1);
+
+        assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+        // TODO DO Still can't be removed in this case.
+    }
+
+    /**
+     * Test for:
+     * {@link DevicePolicyManager#removeActiveAdmin}
+     */
+    public void testRemoveActiveAdmin_sameUserNoMANAGE_DEVICE_ADMINS() {
+        // Need MANAGE_DEVICE_ADMINS for setActiveAdmin.  We'll remove it later.
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        // Add admin1.
+
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+        assertTrue(dpm.isAdminActive(admin1));
+        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+        // Broadcast from saveSettingsLocked().
+        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+
+        // Remove.  No permissions, but same user, so it'll work.
+        mContext.callerPermissions.clear();
+        dpm.removeActiveAdmin(admin1);
+
+        final ArgumentCaptor<BroadcastReceiver> brCap =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+
+        // Is removing now, but not removed yet.
+        assertTrue(dpm.isAdminActive(admin1));
+        assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+        verify(mContext.spiedContext).sendOrderedBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED),
+                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
+                isNull(String.class),
+                brCap.capture(),
+                eq(dpms.mHandler),
+                eq(Activity.RESULT_OK),
+                isNull(String.class),
+                isNull(Bundle.class));
+
+        brCap.getValue().onReceive(mContext, null);
+
+        assertFalse(dpm.isAdminActive(admin1));
+        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+        // Again broadcast from saveSettingsLocked().
+        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+
+        // TODO Check other internal calls.
     }
 }
 
+
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 8644311..6bb9833 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -16,6 +16,7 @@
 
 package com.android.server.devicepolicy;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.LockPatternUtils;
 
 import android.app.IActivityManager;
@@ -24,11 +25,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.PowerManager.WakeLock;
 import android.os.PowerManagerInternal;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.test.mock.MockContext;
@@ -71,27 +74,27 @@
     public static final int SYSTEM_PID = 11111;
 
     public static class MockBinder {
-        int mCallingUid = CALLER_UID;
-        int mCallingPid = CALLER_PID;
+        public int callingUid = CALLER_UID;
+        public int callingPid = CALLER_PID;
 
         public long clearCallingIdentity() {
-            final long token = (((long) mCallingUid) << 32) | (mCallingPid);
-            mCallingUid = SYSTEM_UID;
-            mCallingPid = SYSTEM_PID;
+            final long token = (((long) callingUid) << 32) | (callingPid);
+            callingUid = SYSTEM_UID;
+            callingPid = SYSTEM_PID;
             return token;
         }
 
         public void restoreCallingIdentity(long token) {
-            mCallingUid = (int) (token >> 32);
-            mCallingPid = (int) token;
+            callingUid = (int) (token >> 32);
+            callingPid = (int) token;
         }
 
         public int getCallingUid() {
-            return mCallingUid;
+            return callingUid;
         }
 
         public int getCallingPid() {
-            return mCallingPid;
+            return callingPid;
         }
 
         public UserHandle getCallingUserHandle() {
@@ -99,7 +102,7 @@
         }
 
         public boolean isCallerUidMyUid() {
-            return mCallingUid == SYSTEM_UID;
+            return callingUid == SYSTEM_UID;
         }
     }
 
@@ -118,6 +121,27 @@
         }
     }
 
+    public static class SystemPropertiesForMock {
+        public boolean getBoolean(String key, boolean def) {
+            return false;
+        }
+
+        public long getLong(String key, long def) {
+            return 0;
+        }
+
+        public String get(String key, String def) {
+            return null;
+        }
+
+        public String get(String key) {
+            return null;
+        }
+
+        public void set(String key, String value) {
+        }
+    }
+
     public final Context realTestContext;
 
     /**
@@ -129,12 +153,14 @@
 
     public final MockBinder binder;
     public final EnvironmentForMock environment;
+    public final SystemPropertiesForMock systemProperties;
     public final UserManager userManager;
     public final PowerManagerForMock powerManager;
     public final PowerManagerInternal powerManagerInternal;
     public final NotificationManager notificationManager;
     public final IWindowManager iwindowManager;
     public final IActivityManager iactivityManager;
+    public final IPackageManager ipackageManager;
     public final LockPatternUtils lockPatternUtils;
 
     /** Note this is a partial mock, not a real mock. */
@@ -146,12 +172,14 @@
         realTestContext = context;
         binder = new MockBinder();
         environment = mock(EnvironmentForMock.class);
+        systemProperties= mock(SystemPropertiesForMock.class);
         userManager = mock(UserManager.class);
         powerManager = mock(PowerManagerForMock.class);
         powerManagerInternal = mock(PowerManagerInternal.class);
         notificationManager = mock(NotificationManager.class);
         iwindowManager = mock(IWindowManager.class);
         iactivityManager = mock(IActivityManager.class);
+        ipackageManager = mock(IPackageManager.class);
         lockPatternUtils = mock(LockPatternUtils.class);
 
         // Package manager is huge, so we use a partial mock instead.
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
index a8e2c3c..44a851a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
@@ -23,6 +23,7 @@
 import org.junit.Assert;
 
 import java.io.File;
+import java.util.List;
 
 public class DpmTestUtils {
     private DpmTestUtils() {
@@ -33,6 +34,11 @@
             Assert.assertTrue("failed to delete dir", FileUtils.deleteContents(dir));
         }
         dir.mkdirs();
+        Log.i(DpmTestBase.TAG, "Created " + dir);
+    }
+
+    public static int getListSizeAllowingNull(List<?> list) {
+        return list == null ? 0 : list.size();
     }
 
     public static Printer LOG_PRINTER = new Printer() {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
similarity index 75%
rename from services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
rename to services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
index c47d194..5cd1555 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
@@ -17,5 +17,11 @@
 
 import android.app.admin.DeviceAdminReceiver;
 
-public class DummyDeviceAdmin extends DeviceAdminReceiver {
-}
+public class DummyDeviceAdmins {
+    public static class Admin1 extends DeviceAdminReceiver {
+    }
+    public static class Admin2 extends DeviceAdminReceiver {
+    }
+    public static class Admin3 extends DeviceAdminReceiver {
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
index f2a2bf7..5008fbf 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
@@ -17,6 +17,8 @@
 
 import com.google.common.base.Objects;
 
+import android.content.ComponentName;
+import android.content.Intent;
 import android.os.UserHandle;
 
 import org.hamcrest.BaseMatcher;
@@ -44,4 +46,35 @@
         return Mockito.argThat(m);
     }
 
+    public static Intent checkIntentComponent(final ComponentName component) {
+        final Matcher<Intent> m = new BaseMatcher<Intent>() {
+            @Override
+            public boolean matches(Object item) {
+                if (item == null) return false;
+                return Objects.equal(((Intent) item).getComponent(), component);
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Intent: component=\"" + component + "\"");
+            }
+        };
+        return Mockito.argThat(m);
+    }
+
+    public static Intent checkIntentAction(final String action) {
+        final Matcher<Intent> m = new BaseMatcher<Intent>() {
+            @Override
+            public boolean matches(Object item) {
+                if (item == null) return false;
+                return Objects.equal(((Intent) item).getAction(), action);
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Intent: action=\"" + action + "\"");
+            }
+        };
+        return Mockito.argThat(m);
+    }
 }