Merge "New API to allow third-party apps to bind widgets"
diff --git a/api/current.txt b/api/current.txt
index d10d4c5..408d044 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5321,6 +5321,7 @@
     field public static final int MODE_WORLD_WRITEABLE = 2; // 0x2
     field public static final java.lang.String NFC_SERVICE = "nfc";
     field public static final java.lang.String NOTIFICATION_SERVICE = "notification";
+    field public static final java.lang.String NSD_SERVICE = "servicediscovery";
     field public static final java.lang.String POWER_SERVICE = "power";
     field public static final java.lang.String SEARCH_SERVICE = "search";
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
@@ -24082,11 +24083,7 @@
     field public static final int ACCESSIBILITY_FOCUS_BACKWARD = 4097; // 0x1001
     field public static final int ACCESSIBILITY_FOCUS_DOWN = 4226; // 0x1082
     field public static final int ACCESSIBILITY_FOCUS_FORWARD = 4098; // 0x1002
-    field public static final int ACCESSIBILITY_FOCUS_IN = 4100; // 0x1004
     field public static final int ACCESSIBILITY_FOCUS_LEFT = 4113; // 0x1011
-    field public static final int ACCESSIBILITY_FOCUS_NEXT = 4112; // 0x1010
-    field public static final int ACCESSIBILITY_FOCUS_OUT = 4104; // 0x1008
-    field public static final int ACCESSIBILITY_FOCUS_PREVIOUS = 4128; // 0x1020
     field public static final int ACCESSIBILITY_FOCUS_RIGHT = 4162; // 0x1042
     field public static final int ACCESSIBILITY_FOCUS_UP = 4129; // 0x1021
     field public static final android.util.Property ALPHA;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 1abb7de..0519d3e 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1538,6 +1538,9 @@
                     FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
         }
         if (!f.mUserVisibleHint) {
+            if (result == null) {
+                result = new Bundle();
+            }
             // Only add this if it's not the default value
             result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint);
         }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 381daa3..4c169d38 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1770,12 +1770,11 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
-     * android.net.NsdManager} for handling management of network service
+     * android.net.nsd.NsdManager} for handling management of network service
      * discovery
      *
-     * @hide
      * @see #getSystemService
-     * @see android.net.NsdManager
+     * @see android.net.nsd.NsdManager
      */
     public static final String NSD_SERVICE = "servicediscovery";
 
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 0ba7b88..1df53e8 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -92,6 +92,12 @@
     public static final int MEDIA_UID = 1013;
 
     /**
+     * Defines the UID/GID for the DRM process.
+     * @hide
+     */
+    public static final int DRM_UID = 1019;
+
+    /**
      * Defines the GID for the group that allows write access to the SD card.
      * @hide
      */
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 593762a..09bf42b 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -1354,6 +1354,8 @@
                         GUESTS_CAN_INVITE_OTHERS);
                 DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, GUESTS_CAN_MODIFY);
                 DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, GUESTS_CAN_SEE_GUESTS);
+                DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CUSTOM_APP_PACKAGE);
+                DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CUSTOM_APP_URI);
                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, ORGANIZER);
                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_ID);
                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DIRTY);
@@ -1556,6 +1558,8 @@
      * <li>{@link #GUESTS_CAN_MODIFY}</li>
      * <li>{@link #GUESTS_CAN_INVITE_OTHERS}</li>
      * <li>{@link #GUESTS_CAN_SEE_GUESTS}</li>
+     * <li>{@link #CUSTOM_APP_PACKAGE}</li>
+     * <li>{@link #CUSTOM_APP_URI}</li>
      * </ul>
      * The following Events columns are writable only by a sync adapter
      * <ul>
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index ea9f650..c5e2c42 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -428,6 +428,12 @@
         final int origLen = end - start;
         final int newLen = tbend - tbstart;
 
+        if (origLen == 0 && newLen == 0 && !hasNonExclusiveExclusiveSpanAt(tb, tbstart)) {
+            // This is a no-op iif there are no spans in tb that would be added (with a 0-length)
+            // Early exit so that the text watchers do not get notified
+            return this;
+        }
+
         TextWatcher[] textWatchers = getSpans(start, start + origLen, TextWatcher.class);
         sendBeforeTextChanged(textWatchers, start, origLen, newLen);
 
@@ -470,6 +476,20 @@
         return this; 
     }
 
+    private static boolean hasNonExclusiveExclusiveSpanAt(CharSequence text, int offset) {
+        if (text instanceof Spanned) {
+            Spanned spanned = (Spanned) text;
+            Object[] spans = spanned.getSpans(offset, offset, Object.class);
+            final int length = spans.length;
+            for (int i = 0; i < length; i++) {
+                Object span = spans[i];
+                int flags = spanned.getSpanFlags(span);
+                if (flags != Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) return true;
+            }
+        }
+        return false;
+    }
+
     private void sendToSpanWatchers(int replaceStart, int replaceEnd, int nbNewChars) {
         for (int i = 0; i < mSpanCountBeforeAdd; i++) {
             int spanStart = mSpanStarts[i];
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 7d569ad..6387148 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -662,29 +662,31 @@
                 ViewGroup parentGroup = (ViewGroup) parent;
                 ChildListForAccessibility children = ChildListForAccessibility.obtain(parentGroup,
                         false);
-                final int childCount = children.getChildCount();
-                for (int i = 0; i < childCount; i++) {
-                    if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
-                        children.recycle();
-                        return;
-                    }
-                    View child = children.getChildAt(i);
-                    if (child.getAccessibilityViewId() != current.getAccessibilityViewId()
-                            &&  child.isDisplayedOnScreen()) {
-                        AccessibilityNodeInfo info = null;
-                        AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
-                        if (provider == null) {
-                            info = child.createAccessibilityNodeInfo();
-                        } else {
-                            info = provider.createAccessibilityNodeInfo(
-                                    AccessibilityNodeInfo.UNDEFINED);
+                try {
+                    final int childCount = children.getChildCount();
+                    for (int i = 0; i < childCount; i++) {
+                        if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+                            return;
                         }
-                        if (info != null) {
-                            outInfos.add(info);
+                        View child = children.getChildAt(i);
+                        if (child.getAccessibilityViewId() != current.getAccessibilityViewId()
+                                &&  child.isDisplayedOnScreen()) {
+                            AccessibilityNodeInfo info = null;
+                            AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
+                            if (provider == null) {
+                                info = child.createAccessibilityNodeInfo();
+                            } else {
+                                info = provider.createAccessibilityNodeInfo(
+                                        AccessibilityNodeInfo.UNDEFINED);
+                            }
+                            if (info != null) {
+                                outInfos.add(info);
+                            }
                         }
                     }
+                } finally {
+                    children.recycle();
                 }
-                children.recycle();
             }
         }
 
@@ -697,32 +699,34 @@
             HashMap<View, AccessibilityNodeInfo> addedChildren =
                 new HashMap<View, AccessibilityNodeInfo>();
             ChildListForAccessibility children = ChildListForAccessibility.obtain(rootGroup, false);
-            final int childCount = children.getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
-                    children.recycle();
-                    return;
-                }
-                View child = children.getChildAt(i);
-                if (child.isDisplayedOnScreen()) {
-                    AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
-                    if (provider == null) {
-                        AccessibilityNodeInfo info = child.createAccessibilityNodeInfo();
-                        if (info != null) {
-                            outInfos.add(info);
-                            addedChildren.put(child, null);
-                        }
-                    } else {
-                        AccessibilityNodeInfo info = provider.createAccessibilityNodeInfo(
-                               AccessibilityNodeInfo.UNDEFINED);
-                        if (info != null) {
-                            outInfos.add(info);
-                            addedChildren.put(child, info);
+            try {
+                final int childCount = children.getChildCount();
+                for (int i = 0; i < childCount; i++) {
+                    if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+                        return;
+                    }
+                    View child = children.getChildAt(i);
+                    if (child.isDisplayedOnScreen()) {
+                        AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
+                        if (provider == null) {
+                            AccessibilityNodeInfo info = child.createAccessibilityNodeInfo();
+                            if (info != null) {
+                                outInfos.add(info);
+                                addedChildren.put(child, null);
+                            }
+                        } else {
+                            AccessibilityNodeInfo info = provider.createAccessibilityNodeInfo(
+                                   AccessibilityNodeInfo.UNDEFINED);
+                            if (info != null) {
+                                outInfos.add(info);
+                                addedChildren.put(child, info);
+                            }
                         }
                     }
                 }
+            } finally {
+                children.recycle();
             }
-            children.recycle();
             if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                 for (Map.Entry<View, AccessibilityNodeInfo> entry : addedChildren.entrySet()) {
                     View addedChild = entry.getKey();
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 8a01c15..98375ae 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -17,12 +17,10 @@
 package android.view;
 
 import android.graphics.Rect;
-import android.view.ViewGroup.ChildListForAccessibility;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.Stack;
 
 /**
  * The algorithm used for finding the next focusable view in a given direction
@@ -30,7 +28,7 @@
  */
 public class FocusFinder {
 
-    private static ThreadLocal<FocusFinder> tlFocusFinder =
+    private static final ThreadLocal<FocusFinder> tlFocusFinder =
             new ThreadLocal<FocusFinder>() {
                 @Override
                 protected FocusFinder initialValue() {
@@ -45,15 +43,13 @@
         return tlFocusFinder.get();
     }
 
-    Rect mFocusedRect = new Rect();
-    Rect mOtherRect = new Rect();
-    Rect mBestCandidateRect = new Rect();
-    SequentialFocusComparator mSequentialFocusComparator = new SequentialFocusComparator();
+    final Rect mFocusedRect = new Rect();
+    final Rect mOtherRect = new Rect();
+    final Rect mBestCandidateRect = new Rect();
+    final SequentialFocusComparator mSequentialFocusComparator = new SequentialFocusComparator();
 
     private final ArrayList<View> mTempList = new ArrayList<View>();
 
-    private Stack<View> mTempStack;
-
     // enforce thread local access
     private FocusFinder() {}
 
@@ -78,149 +74,116 @@
      * @return The next focusable view, or null if none exists.
      */
     public View findNextFocusFromRect(ViewGroup root, Rect focusedRect, int direction) {
-        return findNextFocus(root, null, focusedRect, direction);
+        mFocusedRect.set(focusedRect);
+        return findNextFocus(root, null, mFocusedRect, direction);
     }
 
     private View findNextFocus(ViewGroup root, View focused, Rect focusedRect, int direction) {
         if ((direction & View.FOCUS_ACCESSIBILITY) != View.FOCUS_ACCESSIBILITY) {
             return findNextInputFocus(root, focused, focusedRect, direction);
         } else {
-            return findNextAccessibilityFocus(root, focused, direction);
+            return findNextAccessibilityFocus(root, focused, focusedRect, direction);
         }
     }
 
     private View findNextInputFocus(ViewGroup root, View focused, Rect focusedRect, int direction) {
+        View next = null;
         if (focused != null) {
-            // check for user specified next focus
-            View userSetNextFocus = focused.findUserSetNextFocus(root, direction);
-            if (userSetNextFocus != null &&
-                userSetNextFocus.isFocusable() &&
-                (!userSetNextFocus.isInTouchMode() ||
-                 userSetNextFocus.isFocusableInTouchMode())) {
-                return userSetNextFocus;
+            next = findNextUserSpecifiedInputFocus(root, focused, direction);
+        }
+        if (next != null) {
+            return next;
+        }
+        ArrayList<View> focusables = mTempList;
+        try {
+            focusables.clear();
+            root.addFocusables(focusables, direction);
+            if (!focusables.isEmpty()) {
+                next = findNextFocus(root, focused, focusedRect, direction, focusables);
             }
+        } finally {
+            focusables.clear();
+        }
+        return next;
+    }
 
+    private View findNextUserSpecifiedInputFocus(ViewGroup root, View focused, int direction) {
+        // check for user specified next focus
+        View userSetNextFocus = focused.findUserSetNextFocus(root, direction);
+        if (userSetNextFocus != null && userSetNextFocus.isFocusable()
+                && (!userSetNextFocus.isInTouchMode()
+                        || userSetNextFocus.isFocusableInTouchMode())) {
+            return userSetNextFocus;
+        }
+        return null;
+    }
+
+    private View findNextFocus(ViewGroup root, View focused, Rect focusedRect,
+            int direction, ArrayList<View> focusables) {
+        final int directionMasked = (direction & ~View.FOCUS_ACCESSIBILITY);
+        if (focused != null) {
             // fill in interesting rect from focused
-            focused.getFocusedRect(mFocusedRect);
-            root.offsetDescendantRectToMyCoords(focused, mFocusedRect);
+            focused.getFocusedRect(focusedRect);
+            root.offsetDescendantRectToMyCoords(focused, focusedRect);
         } else {
             // make up a rect at top left or bottom right of root
-            switch (direction) {
+            switch (directionMasked) {
                 case View.FOCUS_RIGHT:
                 case View.FOCUS_DOWN:
-                    setFocusTopLeft(root);
+                    setFocusTopLeft(root, focusedRect);
                     break;
                 case View.FOCUS_FORWARD:
                     if (root.isLayoutRtl()) {
-                        setFocusBottomRight(root);
+                        setFocusBottomRight(root, focusedRect);
                     } else {
-                        setFocusTopLeft(root);
+                        setFocusTopLeft(root, focusedRect);
                     }
                     break;
 
                 case View.FOCUS_LEFT:
                 case View.FOCUS_UP:
-                    setFocusBottomRight(root);
+                    setFocusBottomRight(root, focusedRect);
                     break;
                 case View.FOCUS_BACKWARD:
                     if (root.isLayoutRtl()) {
-                        setFocusTopLeft(root);
+                        setFocusTopLeft(root, focusedRect);
                     } else {
-                        setFocusBottomRight(root);
+                        setFocusBottomRight(root, focusedRect);
                     break;
                 }
             }
         }
 
-        ArrayList<View> focusables = mTempList;
-        focusables.clear();
-        root.addFocusables(focusables, direction);
-        if (focusables.isEmpty()) {
-            // The focus cannot change.
-            return null;
+        switch (directionMasked) {
+            case View.FOCUS_FORWARD:
+            case View.FOCUS_BACKWARD:
+                return findNextInputFocusInRelativeDirection(focusables, root, focused, focusedRect,
+                        directionMasked);
+            case View.FOCUS_UP:
+            case View.FOCUS_DOWN:
+            case View.FOCUS_LEFT:
+            case View.FOCUS_RIGHT:
+                return findNextInputFocusInAbsoluteDirection(focusables, root, focused,
+                        focusedRect, directionMasked);
+            default:
+                throw new IllegalArgumentException("Unknown direction: " + directionMasked);
         }
+    }
 
+    private View findNextAccessibilityFocus(ViewGroup root, View focused,
+            Rect focusedRect, int direction) {
+        ArrayList<View> focusables = mTempList;
         try {
-            switch (direction) {
-                case View.FOCUS_FORWARD:
-                case View.FOCUS_BACKWARD:
-                    return findNextInputFocusInRelativeDirection(focusables, root, focused,
-                            focusedRect, direction);
-                case View.FOCUS_UP:
-                case View.FOCUS_DOWN:
-                case View.FOCUS_LEFT:
-                case View.FOCUS_RIGHT:
-                    return findNextInputFocusInAbsoluteDirection(focusables, root, focused,
-                            focusedRect, direction);
-                default:
-                    throw new IllegalArgumentException("Unknown direction: " + direction);
-            }
+            focusables.clear();
+            root.addFocusables(focusables, direction, View.FOCUSABLES_ACCESSIBILITY);
+            View next = findNextFocus(root, focused, focusedRect, direction,
+                    focusables);
+            return next;
         } finally {
             focusables.clear();
         }
     }
 
-    /**
-     * Find the next view to take accessibility focus in root's descendants,
-     * starting from the view that currently is accessibility focused.
-     *
-     * @param root The root which also contains the focused view.
-     * @param focused The current accessibility focused view.
-     * @param direction Direction to look.
-     * @return The next focusable view, or null if none exists.
-     */
-    private View findNextAccessibilityFocus(ViewGroup root, View focused, int direction) {
-        switch (direction) {
-            case View.ACCESSIBILITY_FOCUS_IN:
-            case View.ACCESSIBILITY_FOCUS_OUT:
-            case View.ACCESSIBILITY_FOCUS_FORWARD:
-            case View.ACCESSIBILITY_FOCUS_BACKWARD: {
-                return findNextHierarchicalAcessibilityFocus(root, focused, direction);
-            }
-            case View.ACCESSIBILITY_FOCUS_LEFT:
-            case View.ACCESSIBILITY_FOCUS_RIGHT:
-            case View.ACCESSIBILITY_FOCUS_UP:
-            case View.ACCESSIBILITY_FOCUS_DOWN: {
-                return findNextDirectionalAccessibilityFocus(root, focused, direction);
-            }
-            default:
-                throw new IllegalArgumentException("Unknown direction: " + direction);
-        }
-    }
-
-    private View findNextHierarchicalAcessibilityFocus(ViewGroup root, View focused,
-            int direction) {
-        View current = (focused != null) ? focused : root;
-        switch (direction) {
-            case View.ACCESSIBILITY_FOCUS_IN: {
-                return findNextAccessibilityFocusIn(current);
-            }
-            case View.ACCESSIBILITY_FOCUS_OUT: {
-                return findNextAccessibilityFocusOut(current);
-            }
-            case View.ACCESSIBILITY_FOCUS_FORWARD: {
-                return findNextAccessibilityFocusForward(current);
-            }
-            case View.ACCESSIBILITY_FOCUS_BACKWARD: {
-                return findNextAccessibilityFocusBackward(current);
-            }
-        }
-        return null;
-    }
-
-    private View findNextDirectionalAccessibilityFocus(ViewGroup root, View focused,
-            int direction) {
-        ArrayList<View> focusables = mTempList;
-        focusables.clear();
-        root.addFocusables(focusables, direction, View.FOCUSABLES_ACCESSIBILITY);
-        Rect focusedRect = getFocusedRect(root, focused, direction);
-        final int inputFocusDirection = getCorrespondingInputFocusDirection(direction);
-        View next = findNextInputFocusInAbsoluteDirection(focusables, root,
-                focused, focusedRect, inputFocusDirection);
-        focusables.clear();
-        return next;
-    }
-
     private View findNextInputFocusInRelativeDirection(ArrayList<View> focusables, ViewGroup root,
             View focused, Rect focusedRect, int direction) {
         try {
@@ -241,17 +204,16 @@
         return focusables.get(count - 1);
     }
 
-    private void setFocusBottomRight(ViewGroup root) {
+    private void setFocusBottomRight(ViewGroup root, Rect focusedRect) {
         final int rootBottom = root.getScrollY() + root.getHeight();
         final int rootRight = root.getScrollX() + root.getWidth();
-        mFocusedRect.set(rootRight, rootBottom,
-                rootRight, rootBottom);
+        focusedRect.set(rootRight, rootBottom, rootRight, rootBottom);
     }
 
-    private void setFocusTopLeft(ViewGroup root) {
+    private void setFocusTopLeft(ViewGroup root, Rect focusedRect) {
         final int rootTop = root.getScrollY();
         final int rootLeft = root.getScrollX();
-        mFocusedRect.set(rootLeft, rootTop, rootLeft, rootTop);
+        focusedRect.set(rootLeft, rootTop, rootLeft, rootTop);
     }
 
     View findNextInputFocusInAbsoluteDirection(ArrayList<View> focusables, ViewGroup root, View focused,
@@ -294,140 +256,6 @@
         return closest;
     }
 
-    private View findNextAccessibilityFocusIn(View view) {
-        // We have to traverse the full view tree to make sure
-        // we consider views in the order specified by their
-        // parent layout managers since some managers could be
-        // LTR while some could be RTL.
-        if (mTempStack == null) {
-            mTempStack = new Stack<View>();
-        }
-        Stack<View> fringe = mTempStack;
-        fringe.clear();
-        fringe.add(view);
-        while (!fringe.isEmpty()) {
-            View current = fringe.pop();
-            if (current.getAccessibilityNodeProvider() != null) {
-                fringe.clear();
-                return current;
-            }
-            if (current != view && current.includeForAccessibility()) {
-                fringe.clear();
-                return current;
-            }
-            if (current instanceof ViewGroup) {
-                ViewGroup currentGroup = (ViewGroup) current;
-                ChildListForAccessibility children = ChildListForAccessibility.obtain(
-                        currentGroup, true);
-                final int childCount = children.getChildCount();
-                for (int i = childCount - 1; i >= 0; i--) {
-                    fringe.push(children.getChildAt(i));
-                }
-                children.recycle();
-            }
-        }
-        return null;
-    }
-
-    private View findNextAccessibilityFocusOut(View view) {
-        ViewParent parent = view.getParentForAccessibility();
-        if (parent instanceof View) {
-            return (View) parent;
-        }
-        return null;
-    }
-
-    private View findNextAccessibilityFocusForward(View view) {
-        // We have to traverse the full view tree to make sure
-        // we consider views in the order specified by their
-        // parent layout managers since some managers could be
-        // LTR while some could be RTL.
-        View current = view;
-        while (current != null) {
-            ViewParent parent = current.getParent();
-            if (!(parent instanceof ViewGroup)) {
-                return null;
-            }
-            ViewGroup parentGroup = (ViewGroup) parent;
-            // Ask the parent to find a sibling after the current view
-            // that can take accessibility focus.
-            ChildListForAccessibility children = ChildListForAccessibility.obtain(
-                    parentGroup, true);
-            final int fromIndex = children.getChildIndex(current) + 1;
-            final int childCount = children.getChildCount();
-            for (int i = fromIndex; i < childCount; i++) {
-                View child = children.getChildAt(i);
-                View next = null;
-                if (child.getAccessibilityNodeProvider() != null) {
-                    next = child;
-                } else if (child.includeForAccessibility()) {
-                    next = child;
-                } else {
-                    next = findNextAccessibilityFocusIn(child);
-                }
-                if (next != null) {
-                    children.recycle();
-                    return next;
-                }
-            }
-            children.recycle();
-            // Reaching a regarded for accessibility predecessor without
-            // finding a next view to take focus means that at this level
-            // there is no next accessibility focusable sibling.
-            if (parentGroup.includeForAccessibility()) {
-                return null;
-            }
-            // Try asking a predecessor to find a focusable.
-            current = parentGroup;
-        }
-        return null;
-    }
-
-    private View findNextAccessibilityFocusBackward(View view) {
-        // We have to traverse the full view tree to make sure
-        // we consider views in the order specified by their
-        // parent layout managers since some managers could be
-        // LTR while some could be RTL.
-        View current = view;
-        while (current != null) {
-            ViewParent parent = current.getParent();
-            if (!(parent instanceof ViewGroup)) {
-                return null;
-            }
-            ViewGroup parentGroup = (ViewGroup) parent;
-            // Ask the parent to find a sibling after the current view
-            // to take accessibility focus
-            ChildListForAccessibility children = ChildListForAccessibility.obtain(
-                    parentGroup, true);
-            final int fromIndex = children.getChildIndex(current) - 1;
-            for (int i = fromIndex; i >= 0; i--) {
-                View child = children.getChildAt(i);
-                View next = null;
-                if (child.getAccessibilityNodeProvider() != null) {
-                    next = child;
-                } else if (child.includeForAccessibility()) {
-                    next = child;
-                } else {
-                    next = findNextAccessibilityFocusIn(child);
-                }
-                if (next != null) {
-                    children.recycle();
-                    return next;
-                }
-            }
-            children.recycle();
-            // Reaching a regarded for accessibility predecessor without
-            // finding a previous view to take focus means that at this level
-            // there is no previous accessibility focusable sibling.
-            if (parentGroup.includeForAccessibility()) {
-                return null;
-            }
-            // Try asking a predecessor to find a focusable.
-            current = parentGroup;
-        }
-        return null;
-    }
-
     private static View getForwardFocusable(ViewGroup root, View focused,
                                             ArrayList<View> focusables, int count) {
         return (root.isLayoutRtl()) ?
@@ -462,47 +290,6 @@
         return focusables.get(count - 1);
     }
 
-    private Rect getFocusedRect(ViewGroup root, View focused, int direction) {
-        Rect focusedRect = mFocusedRect;
-        if (focused != null) {
-            focused.getFocusedRect(focusedRect);
-            root.offsetDescendantRectToMyCoords(focused, focusedRect);
-        } else {
-            switch (direction) {
-                case View.FOCUS_RIGHT:
-                case View.FOCUS_DOWN:
-                    final int rootTop = root.getScrollY();
-                    final int rootLeft = root.getScrollX();
-                    focusedRect.set(rootLeft, rootTop, rootLeft, rootTop);
-                    break;
-
-                case View.FOCUS_LEFT:
-                case View.FOCUS_UP:
-                    final int rootBottom = root.getScrollY() + root.getHeight();
-                    final int rootRight = root.getScrollX() + root.getWidth();
-                    focusedRect.set(rootRight, rootBottom, rootRight, rootBottom);
-                    break;
-            }
-        }
-        return focusedRect;
-    }
-
-    private int getCorrespondingInputFocusDirection(int accessFocusDirection) {
-        switch (accessFocusDirection) {
-            case View.ACCESSIBILITY_FOCUS_LEFT:
-                return View.FOCUS_LEFT;
-            case View.ACCESSIBILITY_FOCUS_RIGHT:
-                return View.FOCUS_RIGHT;
-            case View.ACCESSIBILITY_FOCUS_UP:
-                return View.FOCUS_UP;
-            case View.ACCESSIBILITY_FOCUS_DOWN:
-                return View.FOCUS_DOWN;
-            default:
-                throw new IllegalArgumentException("Cannot map accessiblity focus"
-                        + " direction: " + accessFocusDirection);
-        }
-    }
-
     /**
      * Is rect1 a better candidate than rect2 for a focus search in a particular
      * direction from a source rect?  This is the core routine that determines
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index eb80290d..53af3c5 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -323,6 +323,15 @@
         return mSurfaceGenerationId;
     }
 
+
+    /**
+     * Whether the consumer of this Surface is running behind the producer;
+     * that is, isConsumerRunningBehind() returns true if the consumer is more
+     * than one buffer ahead of the producer.
+     * @hide
+     */
+    public native boolean isConsumerRunningBehind();
+
     /**
      * A Canvas class that can handle the compatibility mode. This does two
      * things differently.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0e6af61..b65bf8f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1056,26 +1056,6 @@
     public static final int ACCESSIBILITY_FOCUS_BACKWARD = FOCUS_BACKWARD | FOCUS_ACCESSIBILITY;
 
     /**
-     * Use with {@link #focusSearch(int)}. Move acessibility focus in a view.
-     */
-    public static final int ACCESSIBILITY_FOCUS_IN = 0x00000004 | FOCUS_ACCESSIBILITY;
-
-    /**
-     * Use with {@link #focusSearch(int)}. Move acessibility focus out of a view.
-     */
-    public static final int ACCESSIBILITY_FOCUS_OUT = 0x00000008 | FOCUS_ACCESSIBILITY;
-
-    /**
-     * Use with {@link #focusSearch(int)}. Move acessibility focus to the next view.
-     */
-    public static final int ACCESSIBILITY_FOCUS_NEXT = 0x00000010 | FOCUS_ACCESSIBILITY;
-
-    /**
-     * Use with {@link #focusSearch(int)}. Move acessibility focus to the previous view.
-     */
-    public static final int ACCESSIBILITY_FOCUS_PREVIOUS = 0x00000020 | FOCUS_ACCESSIBILITY;
-
-    /**
      * Bits of {@link #getMeasuredWidthAndState()} and
      * {@link #getMeasuredWidthAndState()} that provide the actual measured size.
      */
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 6ecd767..343ae4c 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1622,18 +1622,22 @@
 
     @Override
     public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
-        View[] children = mChildren;
-        final int childrenCount = mChildrenCount;
-        for (int i = 0; i < childrenCount; i++) {
-            View child = children[i];
-            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
-                    && (child.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
-                if (child.includeForAccessibility()) {
-                    childrenForAccessibility.add(child);
-                } else {
-                    child.addChildrenForAccessibility(childrenForAccessibility);
+        ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
+        try {
+            final int childrenCount = children.getChildCount();
+            for (int i = 0; i < childrenCount; i++) {
+                View child = children.getChildAt(i);
+                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
+                        && (child.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
+                    if (child.includeForAccessibility()) {
+                        childrenForAccessibility.add(child);
+                    } else {
+                        child.addChildrenForAccessibility(childrenForAccessibility);
+                    }
                 }
             }
+        } finally {
+            children.recycle();
         }
     }
 
@@ -2424,18 +2428,21 @@
         }
         // Let our children have a shot in populating the event.
         ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
-        final int childCount = children.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = children.getChildAt(i);
-            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
-                handled = child.dispatchPopulateAccessibilityEvent(event);
-                if (handled) {
-                    children.recycle();
-                    return handled;
+        try {
+            final int childCount = children.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                View child = children.getChildAt(i);
+                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
+                    handled = child.dispatchPopulateAccessibilityEvent(event);
+                    if (handled) {
+                        children.recycle();
+                        return handled;
+                    }
                 }
             }
+        } finally {
+            children.recycle();
         }
-        children.recycle();
         return false;
     }
 
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index bc310b0..d62f513 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -429,6 +429,12 @@
         public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;
 
         /**
+         * Window type: Navigation bar panel (when navigation bar is distinct from status bar)
+         * @hide
+         */
+        public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;
+
+        /**
          * End of types of system windows.
          */
         public static final int LAST_SYSTEM_WINDOW      = 2999;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index cdb9e77..3cb3b54 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -391,8 +391,6 @@
      *     {@link View#FOCUS_RIGHT},
      *     {@link View#FOCUS_FORWARD},
      *     {@link View#FOCUS_BACKWARD},
-     *     {@link View#ACCESSIBILITY_FOCUS_IN},
-     *     {@link View#ACCESSIBILITY_FOCUS_OUT},
      *     {@link View#ACCESSIBILITY_FOCUS_FORWARD},
      *     {@link View#ACCESSIBILITY_FOCUS_BACKWARD},
      *     {@link View#ACCESSIBILITY_FOCUS_UP},
diff --git a/core/java/android/view/accessibility/AccessibilityNodeProvider.java b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
index ba6433f..a2e0d88 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeProvider.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
@@ -168,8 +168,6 @@
      *
      * @param direction The direction in which to search for a focus candidate.
      *     Values are
-     *     {@link View#ACCESSIBILITY_FOCUS_IN},
-     *     {@link View#ACCESSIBILITY_FOCUS_OUT},
      *     {@link View#ACCESSIBILITY_FOCUS_FORWARD},
      *     {@link View#ACCESSIBILITY_FOCUS_BACKWARD},
      *     {@link View#ACCESSIBILITY_FOCUS_UP},
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index fa18dce..05b3e64 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -7825,6 +7825,12 @@
             // This provides a hook for ProfiledWebView to observe the tile page swaps.
             ((PageSwapDelegate) mWebView).onPageSwapOccurred(notifyAnimationStarted);
         }
+
+        if (mPictureListener != null) {
+            // trigger picture listener for hardware layers. Software layers are
+            // triggered in setNewPicture
+            mPictureListener.onNewPicture(getWebView(), capturePicture());
+        }
     }
 
     void setNewPicture(final WebViewCore.DrawData draw, boolean updateBaseLayer) {
@@ -7894,7 +7900,12 @@
         scrollEditWithCursor();
 
         if (mPictureListener != null) {
-            mPictureListener.onNewPicture(getWebView(), capturePicture());
+            if (!mWebView.isHardwareAccelerated()
+                    || mWebView.getLayerType() == View.LAYER_TYPE_SOFTWARE) {
+                // trigger picture listener for software layers. Hardware layers are
+                // triggered in pageSwapCallback
+                mPictureListener.onNewPicture(getWebView(), capturePicture());
+            }
         }
     }
 
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 2f72e4a..214775a 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -16,13 +16,7 @@
 
 package android.widget;
 
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-
+import android.app.ActivityOptions;
 import android.app.PendingIntent;
 import android.appwidget.AppWidgetHostView;
 import android.content.Context;
@@ -40,13 +34,20 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
+import android.view.LayoutInflater.Filter;
 import android.view.RemotableViewMethod;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.LayoutInflater.Filter;
 import android.view.View.OnClickListener;
+import android.view.ViewGroup;
 import android.widget.AdapterView.OnItemClickListener;
 
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+
 
 /**
  * A class that describes a view hierarchy that can be displayed in
@@ -140,14 +141,18 @@
             return;
         }
 
-        protected boolean startIntentSafely(Context context, PendingIntent pendingIntent,
+        protected boolean startIntentSafely(View view, PendingIntent pendingIntent,
                 Intent fillInIntent) {
             try {
                 // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
+                Context context = view.getContext();
+                ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view,
+                        0, 0,
+                        view.getMeasuredWidth(), view.getMeasuredHeight());
                 context.startIntentSender(
                         pendingIntent.getIntentSender(), fillInIntent,
                         Intent.FLAG_ACTIVITY_NEW_TASK,
-                        Intent.FLAG_ACTIVITY_NEW_TASK, 0);
+                        Intent.FLAG_ACTIVITY_NEW_TASK, 0, opts.toBundle());
             } catch (IntentSender.SendIntentException e) {
                 android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
                 return false;
@@ -263,7 +268,7 @@
                         rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
 
                         fillInIntent.setSourceBounds(rect);
-                        startIntentSafely(v.getContext(), pendingIntent, fillInIntent);
+                        startIntentSafely(v, pendingIntent, fillInIntent);
                     }
 
                 };
@@ -341,7 +346,7 @@
 
                             final Intent intent = new Intent();
                             intent.setSourceBounds(rect);
-                            startIntentSafely(view.getContext(), pendingIntentTemplate, fillInIntent);
+                            startIntentSafely(view, pendingIntentTemplate, fillInIntent);
                         }
                     }
                 };
@@ -479,7 +484,7 @@
     
                             final Intent intent = new Intent();
                             intent.setSourceBounds(rect);
-                            startIntentSafely(v.getContext(), pendingIntent, intent);
+                            startIntentSafely(v, pendingIntent, intent);
                         }
                     };
                 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index eba580d..36b1cd6 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -799,22 +799,22 @@
 
             case com.android.internal.R.styleable.TextView_imeOptions:
                 createEditorIfNeeded("IME options specified in constructor");
-                getEditor().createInputContentTypeIfNeeded();
-                getEditor().mInputContentType.imeOptions = a.getInt(attr,
-                        getEditor().mInputContentType.imeOptions);
+                mEditor.createInputContentTypeIfNeeded();
+                mEditor.mInputContentType.imeOptions = a.getInt(attr,
+                        mEditor.mInputContentType.imeOptions);
                 break;
 
             case com.android.internal.R.styleable.TextView_imeActionLabel:
                 createEditorIfNeeded("IME action label specified in constructor");
-                getEditor().createInputContentTypeIfNeeded();
-                getEditor().mInputContentType.imeActionLabel = a.getText(attr);
+                mEditor.createInputContentTypeIfNeeded();
+                mEditor.mInputContentType.imeActionLabel = a.getText(attr);
                 break;
 
             case com.android.internal.R.styleable.TextView_imeActionId:
                 createEditorIfNeeded("IME action id specified in constructor");
-                getEditor().createInputContentTypeIfNeeded();
-                getEditor().mInputContentType.imeActionId = a.getInt(attr,
-                        getEditor().mInputContentType.imeActionId);
+                mEditor.createInputContentTypeIfNeeded();
+                mEditor.mInputContentType.imeActionId = a.getInt(attr,
+                        mEditor.mInputContentType.imeActionId);
                 break;
 
             case com.android.internal.R.styleable.TextView_privateImeOptions:
@@ -884,26 +884,26 @@
 
             try {
                 createEditorIfNeeded("inputMethod in ctor");
-                getEditor().mKeyListener = (KeyListener) c.newInstance();
+                mEditor.mKeyListener = (KeyListener) c.newInstance();
             } catch (InstantiationException ex) {
                 throw new RuntimeException(ex);
             } catch (IllegalAccessException ex) {
                 throw new RuntimeException(ex);
             }
             try {
-                getEditor().mInputType = inputType != EditorInfo.TYPE_NULL
+                mEditor.mInputType = inputType != EditorInfo.TYPE_NULL
                         ? inputType
-                        : getEditor().mKeyListener.getInputType();
+                        : mEditor.mKeyListener.getInputType();
             } catch (IncompatibleClassChangeError e) {
-                getEditor().mInputType = EditorInfo.TYPE_CLASS_TEXT;
+                mEditor.mInputType = EditorInfo.TYPE_CLASS_TEXT;
             }
         } else if (digits != null) {
             createEditorIfNeeded("digits in ctor");
-            getEditor().mKeyListener = DigitsKeyListener.getInstance(digits.toString());
+            mEditor.mKeyListener = DigitsKeyListener.getInstance(digits.toString());
             // If no input type was specified, we will default to generic
             // text, since we can't tell the IME about the set of digits
             // that was selected.
-            getEditor().mInputType = inputType != EditorInfo.TYPE_NULL
+            mEditor.mInputType = inputType != EditorInfo.TYPE_NULL
                     ? inputType : EditorInfo.TYPE_CLASS_TEXT;
         } else if (inputType != EditorInfo.TYPE_NULL) {
             setInputType(inputType, true);
@@ -911,11 +911,11 @@
             singleLine = !isMultilineInputType(inputType);
         } else if (phone) {
             createEditorIfNeeded("dialer in ctor");
-            getEditor().mKeyListener = DialerKeyListener.getInstance();
-            getEditor().mInputType = inputType = EditorInfo.TYPE_CLASS_PHONE;
+            mEditor.mKeyListener = DialerKeyListener.getInstance();
+            mEditor.mInputType = inputType = EditorInfo.TYPE_CLASS_PHONE;
         } else if (numeric != 0) {
             createEditorIfNeeded("numeric in ctor");
-            getEditor().mKeyListener = DigitsKeyListener.getInstance((numeric & SIGNED) != 0,
+            mEditor.mKeyListener = DigitsKeyListener.getInstance((numeric & SIGNED) != 0,
                                                    (numeric & DECIMAL) != 0);
             inputType = EditorInfo.TYPE_CLASS_NUMBER;
             if ((numeric & SIGNED) != 0) {
@@ -924,7 +924,7 @@
             if ((numeric & DECIMAL) != 0) {
                 inputType |= EditorInfo.TYPE_NUMBER_FLAG_DECIMAL;
             }
-            getEditor().mInputType = inputType;
+            mEditor.mInputType = inputType;
         } else if (autotext || autocap != -1) {
             TextKeyListener.Capitalize cap;
 
@@ -952,23 +952,23 @@
             }
 
             createEditorIfNeeded("text input in ctor");
-            getEditor().mKeyListener = TextKeyListener.getInstance(autotext, cap);
-            getEditor().mInputType = inputType;
+            mEditor.mKeyListener = TextKeyListener.getInstance(autotext, cap);
+            mEditor.mInputType = inputType;
         } else if (isTextSelectable()) {
             // Prevent text changes from keyboard.
             if (mEditor != null) {
-                getEditor().mKeyListener = null;
-                getEditor().mInputType = EditorInfo.TYPE_NULL;
+                mEditor.mKeyListener = null;
+                mEditor.mInputType = EditorInfo.TYPE_NULL;
             }
             bufferType = BufferType.SPANNABLE;
             // So that selection can be changed using arrow keys and touch is handled.
             setMovementMethod(ArrowKeyMovementMethod.getInstance());
         } else if (editable) {
             createEditorIfNeeded("editable input in ctor");
-            getEditor().mKeyListener = TextKeyListener.getInstance();
-            getEditor().mInputType = EditorInfo.TYPE_CLASS_TEXT;
+            mEditor.mKeyListener = TextKeyListener.getInstance();
+            mEditor.mInputType = EditorInfo.TYPE_CLASS_TEXT;
         } else {
-            if (mEditor != null) getEditor().mKeyListener = null;
+            if (mEditor != null) mEditor.mKeyListener = null;
 
             switch (buffertype) {
                 case 0:
@@ -983,12 +983,12 @@
             }
         }
 
-        if (mEditor != null) getEditor().adjustInputType(password, passwordInputType, webPasswordInputType,
-                numberPasswordInputType);
+        if (mEditor != null) mEditor.adjustInputType(password, passwordInputType,
+                webPasswordInputType, numberPasswordInputType);
 
         if (selectallonfocus) {
             createEditorIfNeeded("selectallonfocus in constructor");
-            getEditor().mSelectAllOnFocus = true;
+            mEditor.mSelectAllOnFocus = true;
 
             if (bufferType == BufferType.NORMAL)
                 bufferType = BufferType.SPANNABLE;
@@ -1045,7 +1045,8 @@
         if (password || passwordInputType || webPasswordInputType || numberPasswordInputType) {
             setTransformationMethod(PasswordTransformationMethod.getInstance());
             typefaceIndex = MONOSPACE;
-        } else if (mEditor != null && (getEditor().mInputType & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_MASK_VARIATION))
+        } else if (mEditor != null &&
+                (mEditor.mInputType & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_MASK_VARIATION))
                 == (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD)) {
             typefaceIndex = MONOSPACE;
         }
@@ -1189,11 +1190,11 @@
 
         // Will change text color
         if (mEditor != null) {
-            getEditor().invalidateTextDisplayList();
-            getEditor().prepareCursorControllers();
+            mEditor.invalidateTextDisplayList();
+            mEditor.prepareCursorControllers();
 
             // start or stop the cursor blinking as appropriate
-            getEditor().makeBlink();
+            mEditor.makeBlink();
         }
     }
 
@@ -1295,7 +1296,7 @@
      * This will frequently be null for non-EditText TextViews.
      */
     public final KeyListener getKeyListener() {
-        return mEditor == null ? null : getEditor().mKeyListener;
+        return mEditor == null ? null : mEditor.mKeyListener;
     }
 
     /**
@@ -1327,15 +1328,15 @@
         if (input != null) {
             createEditorIfNeeded("input is not null");
             try {
-                getEditor().mInputType = getEditor().mKeyListener.getInputType();
+                mEditor.mInputType = mEditor.mKeyListener.getInputType();
             } catch (IncompatibleClassChangeError e) {
-                getEditor().mInputType = EditorInfo.TYPE_CLASS_TEXT;
+                mEditor.mInputType = EditorInfo.TYPE_CLASS_TEXT;
             }
             // Change inputType, without affecting transformation.
             // No need to applySingleLine since mSingleLine is unchanged.
             setInputTypeSingleLine(mSingleLine);
         } else {
-            if (mEditor != null) getEditor().mInputType = EditorInfo.TYPE_NULL;
+            if (mEditor != null) mEditor.mInputType = EditorInfo.TYPE_NULL;
         }
 
         InputMethodManager imm = InputMethodManager.peekInstance();
@@ -1346,8 +1347,8 @@
         if (mEditor == null && input == null) return; // null is the default value
 
         createEditorIfNeeded("setKeyListenerOnly");
-        if (getEditor().mKeyListener != input) {
-            getEditor().mKeyListener = input;
+        if (mEditor.mKeyListener != input) {
+            mEditor.mKeyListener = input;
             if (input != null && !(mText instanceof Editable)) {
                 setText(mText);
             }
@@ -1385,13 +1386,14 @@
 
             fixFocusableAndClickableSettings();
 
-            // SelectionModifierCursorController depends on textCanBeSelected, which depends on mMovement
-            if (mEditor != null) getEditor().prepareCursorControllers();
+            // SelectionModifierCursorController depends on textCanBeSelected, which depends on
+            // mMovement
+            if (mEditor != null) mEditor.prepareCursorControllers();
         }
     }
 
     private void fixFocusableAndClickableSettings() {
-        if (mMovement != null || (mEditor != null && getEditor().mKeyListener != null)) {
+        if (mMovement != null || (mEditor != null && mEditor.mKeyListener != null)) {
             setFocusable(true);
             setClickable(true);
             setLongClickable(true);
@@ -2096,7 +2098,8 @@
         ColorStateList colors;
         int ts;
 
-        color = appearance.getColor(com.android.internal.R.styleable.TextAppearance_textColorHighlight, 0);
+        color = appearance.getColor(
+                com.android.internal.R.styleable.TextAppearance_textColorHighlight, 0);
         if (color != 0) {
             setHighlightColor(color);
         }
@@ -2349,7 +2352,7 @@
         mShadowDy = dy;
 
         // Will change text clip region
-        if (mEditor != null) getEditor().invalidateTextDisplayList();
+        if (mEditor != null) mEditor.invalidateTextDisplayList();
         invalidate();
     }
 
@@ -2842,7 +2845,7 @@
         }
         if (inval) {
             // Text needs to be redrawn with the new color
-            if (mEditor != null) getEditor().invalidateTextDisplayList();
+            if (mEditor != null) mEditor.invalidateTextDisplayList();
             invalidate();
         }
     }
@@ -2921,7 +2924,7 @@
 
                 if (mEditor != null) {
                     removeMisspelledSpans(sp);
-                    sp.removeSpan(getEditor().mSuggestionRangeSpan);
+                    sp.removeSpan(mEditor.mSuggestionRangeSpan);
                 }
 
                 ss.text = sp;
@@ -2987,7 +2990,7 @@
 
                     if (ss.frozenWithFocus) {
                         createEditorIfNeeded("restore instance with focus");
-                        getEditor().mFrozenWithFocus = true;
+                        mEditor.mFrozenWithFocus = true;
                     }
                 }
             }
@@ -3145,7 +3148,8 @@
             needEditableForNotification = true;
         }
 
-        if (type == BufferType.EDITABLE || getKeyListener() != null || needEditableForNotification) {
+        if (type == BufferType.EDITABLE || getKeyListener() != null ||
+                needEditableForNotification) {
             createEditorIfNeeded("setText with BufferType.EDITABLE or non null mInput");
             Editable t = mEditableFactory.newEditable(text);
             text = t;
@@ -3226,7 +3230,7 @@
                  * selection, so reset mSelectionMoved to keep that from
                  * interfering with the normal on-focus selection-setting.
                  */
-                if (mEditor != null) getEditor().mSelectionMoved = false;
+                if (mEditor != null) mEditor.mSelectionMoved = false;
             }
         }
 
@@ -3242,7 +3246,7 @@
         }
 
         // SelectionModifierCursorController depends on textCanBeSelected, which depends on text
-        if (mEditor != null) getEditor().prepareCursorControllers();
+        if (mEditor != null) mEditor.prepareCursorControllers();
     }
 
     /**
@@ -3332,7 +3336,7 @@
 
         // Invalidate display list if hint is currently used
         if (mEditor != null && mText.length() == 0 && mHint != null) {
-            getEditor().invalidateTextDisplayList();
+            mEditor.invalidateTextDisplayList();
         }
     }
 
@@ -3425,9 +3429,9 @@
                 forceUpdate = true;
             }
         }
-        
+
         boolean singleLine = !isMultilineInputType(type);
-        
+
         // We need to update the single line mode if it has changed or we
         // were previously in password mode.
         if (mSingleLine != singleLine || forceUpdate) {
@@ -3435,7 +3439,7 @@
             // we are not in password mode.
             applySingleLine(singleLine, !isPassword, true);
         }
-        
+
         if (!isSuggestionsEnabled()) {
             mText = removeSuggestionSpans(mText);
         }
@@ -3491,7 +3495,7 @@
     public void setRawInputType(int type) {
         if (type == InputType.TYPE_NULL && mEditor == null) return; //TYPE_NULL is the default value
         createEditorIfNeeded("non null input type");
-        getEditor().mInputType = type;
+        mEditor.mInputType = type;
     }
 
     private void setInputType(int type, boolean direct) {
@@ -3534,7 +3538,7 @@
         setRawInputType(type);
         if (direct) {
             createEditorIfNeeded("setInputType");
-            getEditor().mKeyListener = input;
+            mEditor.mKeyListener = input;
         } else {
             setKeyListenerOnly(input);
         }
@@ -3547,7 +3551,7 @@
      * @see android.text.InputType
      */
     public int getInputType() {
-        return mEditor == null ? EditorInfo.TYPE_NULL : getEditor().mInputType;
+        return mEditor == null ? EditorInfo.TYPE_NULL : mEditor.mInputType;
     }
 
     /**
@@ -3560,8 +3564,8 @@
      */
     public void setImeOptions(int imeOptions) {
         createEditorIfNeeded("IME options specified");
-        getEditor().createInputContentTypeIfNeeded();
-        getEditor().mInputContentType.imeOptions = imeOptions;
+        mEditor.createInputContentTypeIfNeeded();
+        mEditor.mInputContentType.imeOptions = imeOptions;
     }
 
     /**
@@ -3571,8 +3575,8 @@
      * @see android.view.inputmethod.EditorInfo
      */
     public int getImeOptions() {
-        return mEditor != null && getEditor().mInputContentType != null
-                ? getEditor().mInputContentType.imeOptions : EditorInfo.IME_NULL;
+        return mEditor != null && mEditor.mInputContentType != null
+                ? mEditor.mInputContentType.imeOptions : EditorInfo.IME_NULL;
     }
 
     /**
@@ -3587,9 +3591,9 @@
      */
     public void setImeActionLabel(CharSequence label, int actionId) {
         createEditorIfNeeded("IME action label specified");
-        getEditor().createInputContentTypeIfNeeded();
-        getEditor().mInputContentType.imeActionLabel = label;
-        getEditor().mInputContentType.imeActionId = actionId;
+        mEditor.createInputContentTypeIfNeeded();
+        mEditor.mInputContentType.imeActionLabel = label;
+        mEditor.mInputContentType.imeActionId = actionId;
     }
 
     /**
@@ -3599,8 +3603,8 @@
      * @see android.view.inputmethod.EditorInfo
      */
     public CharSequence getImeActionLabel() {
-        return mEditor != null && getEditor().mInputContentType != null
-                ? getEditor().mInputContentType.imeActionLabel : null;
+        return mEditor != null && mEditor.mInputContentType != null
+                ? mEditor.mInputContentType.imeActionLabel : null;
     }
 
     /**
@@ -3610,8 +3614,8 @@
      * @see android.view.inputmethod.EditorInfo
      */
     public int getImeActionId() {
-        return mEditor != null && getEditor().mInputContentType != null
-                ? getEditor().mInputContentType.imeActionId : 0;
+        return mEditor != null && mEditor.mInputContentType != null
+                ? mEditor.mInputContentType.imeActionId : 0;
     }
 
     /**
@@ -3624,8 +3628,8 @@
      */
     public void setOnEditorActionListener(OnEditorActionListener l) {
         createEditorIfNeeded("Editor action listener set");
-        getEditor().createInputContentTypeIfNeeded();
-        getEditor().mInputContentType.onEditorActionListener = l;
+        mEditor.createInputContentTypeIfNeeded();
+        mEditor.mInputContentType.onEditorActionListener = l;
     }
 
     /**
@@ -3638,18 +3642,18 @@
      * EditorInfo.IME_ACTION_NEXT}, {@link EditorInfo#IME_ACTION_PREVIOUS
      * EditorInfo.IME_ACTION_PREVIOUS}, or {@link EditorInfo#IME_ACTION_DONE
      * EditorInfo.IME_ACTION_DONE}.
-     * 
+     *
      * <p>For backwards compatibility, if no IME options have been set and the
      * text view would not normally advance focus on enter, then
      * the NEXT and DONE actions received here will be turned into an enter
      * key down/up pair to go through the normal key handling.
-     * 
+     *
      * @param actionCode The code of the action being performed.
-     * 
+     *
      * @see #setOnEditorActionListener
      */
     public void onEditorAction(int actionCode) {
-        final Editor.InputContentType ict = mEditor == null ? null : getEditor().mInputContentType;
+        final Editor.InputContentType ict = mEditor == null ? null : mEditor.mInputContentType;
         if (ict != null) {
             if (ict.onEditorActionListener != null) {
                 if (ict.onEditorActionListener.onEditorAction(this,
@@ -3721,8 +3725,8 @@
      */
     public void setPrivateImeOptions(String type) {
         createEditorIfNeeded("Private IME option set");
-        getEditor().createInputContentTypeIfNeeded();
-        getEditor().mInputContentType.privateImeOptions = type;
+        mEditor.createInputContentTypeIfNeeded();
+        mEditor.mInputContentType.privateImeOptions = type;
     }
 
     /**
@@ -3732,8 +3736,8 @@
      * @see EditorInfo#privateImeOptions
      */
     public String getPrivateImeOptions() {
-        return mEditor != null && getEditor().mInputContentType != null
-                ? getEditor().mInputContentType.privateImeOptions : null;
+        return mEditor != null && mEditor.mInputContentType != null
+                ? mEditor.mInputContentType.privateImeOptions : null;
     }
 
     /**
@@ -3743,16 +3747,16 @@
      * given integer is the resource ID of an XML resource holding an
      * {@link android.R.styleable#InputExtras &lt;input-extras&gt;} XML tree.
      *
-     * @see #getInputExtras(boolean) 
+     * @see #getInputExtras(boolean)
      * @see EditorInfo#extras
      * @attr ref android.R.styleable#TextView_editorExtras
      */
     public void setInputExtras(int xmlResId) throws XmlPullParserException, IOException {
         createEditorIfNeeded("Input extra set");
         XmlResourceParser parser = getResources().getXml(xmlResId);
-        getEditor().createInputContentTypeIfNeeded();
-        getEditor().mInputContentType.extras = new Bundle();
-        getResources().parseBundleExtras(parser, getEditor().mInputContentType.extras);
+        mEditor.createInputContentTypeIfNeeded();
+        mEditor.mInputContentType.extras = new Bundle();
+        getResources().parseBundleExtras(parser, mEditor.mInputContentType.extras);
     }
 
     /**
@@ -3768,15 +3772,15 @@
     public Bundle getInputExtras(boolean create) {
         if (mEditor == null && !create) return null;
         createEditorIfNeeded("get Input extra");
-        if (getEditor().mInputContentType == null) {
+        if (mEditor.mInputContentType == null) {
             if (!create) return null;
-            getEditor().createInputContentTypeIfNeeded();
+            mEditor.createInputContentTypeIfNeeded();
         }
-        if (getEditor().mInputContentType.extras == null) {
+        if (mEditor.mInputContentType.extras == null) {
             if (!create) return null;
-            getEditor().mInputContentType.extras = new Bundle();
+            mEditor.mInputContentType.extras = new Bundle();
         }
-        return getEditor().mInputContentType.extras;
+        return mEditor.mInputContentType.extras;
     }
 
     /**
@@ -3785,7 +3789,7 @@
      * or if it the error was cleared by the widget after user input.
      */
     public CharSequence getError() {
-        return mEditor == null ? null : getEditor().mError;
+        return mEditor == null ? null : mEditor.mError;
     }
 
     /**
@@ -3820,14 +3824,14 @@
      */
     public void setError(CharSequence error, Drawable icon) {
         createEditorIfNeeded("setError");
-        getEditor().setError(error, icon);
+        mEditor.setError(error, icon);
     }
 
     @Override
     protected boolean setFrame(int l, int t, int r, int b) {
         boolean result = super.setFrame(l, t, r, b);
 
-        if (mEditor != null) getEditor().setFrame();
+        if (mEditor != null) mEditor.setFrame();
 
         restartMarqueeIfNeeded();
 
@@ -3864,11 +3868,11 @@
      * and includes mInput in the list if it is an InputFilter.
      */
     private void setFilters(Editable e, InputFilter[] filters) {
-        if (mEditor != null && getEditor().mKeyListener instanceof InputFilter) {
+        if (mEditor != null && mEditor.mKeyListener instanceof InputFilter) {
             InputFilter[] nf = new InputFilter[filters.length + 1];
 
             System.arraycopy(filters, 0, nf, 0, filters.length);
-            nf[filters.length] = (InputFilter) getEditor().mKeyListener;
+            nf[filters.length] = (InputFilter) mEditor.mKeyListener;
 
             e.setFilters(nf);
         } else {
@@ -3954,7 +3958,7 @@
             final int horizontalPadding = getCompoundPaddingLeft();
             final int verticalPadding = getExtendedPaddingTop() + getVerticalOffset(true);
 
-            if (getEditor().mCursorCount == 0) {
+            if (mEditor.mCursorCount == 0) {
                 synchronized (TEMP_RECTF) {
                     /*
                      * The reason for this concern about the thickness of the
@@ -3981,8 +3985,8 @@
                             (int) FloatMath.ceil(verticalPadding + TEMP_RECTF.bottom + thick));
                 }
             } else {
-                for (int i = 0; i < getEditor().mCursorCount; i++) {
-                    Rect bounds = getEditor().mCursorDrawable[i].getBounds();
+                for (int i = 0; i < mEditor.mCursorCount; i++) {
+                    Rect bounds = mEditor.mCursorDrawable[i].getBounds();
                     invalidate(bounds.left + horizontalPadding, bounds.top + verticalPadding,
                             bounds.right + horizontalPadding, bounds.bottom + verticalPadding);
                 }
@@ -4035,8 +4039,8 @@
 
                 // mEditor can be null in case selection is set programmatically.
                 if (invalidateCursor && mEditor != null) {
-                    for (int i = 0; i < getEditor().mCursorCount; i++) {
-                        Rect bounds = getEditor().mCursorDrawable[i].getBounds();
+                    for (int i = 0; i < mEditor.mCursorCount; i++) {
+                        Rect bounds = mEditor.mCursorDrawable[i].getBounds();
                         top = Math.min(top, bounds.top);
                         bottom = Math.max(bottom, bounds.bottom);
                     }
@@ -4086,8 +4090,8 @@
              */
             int curs = getSelectionEnd();
             // Do not create the controller if it is not already created.
-            if (mEditor != null && getEditor().mSelectionModifierCursorController != null &&
-                    getEditor().mSelectionModifierCursorController.isSelectionStartDragged()) {
+            if (mEditor != null && mEditor.mSelectionModifierCursorController != null &&
+                    mEditor.mSelectionModifierCursorController.isSelectionStartDragged()) {
                 curs = getSelectionStart();
             }
 
@@ -4110,16 +4114,16 @@
         // This has to be checked here since:
         // - onFocusChanged cannot start it when focus is given to a view with selected text (after
         //   a screen rotation) since layout is not yet initialized at that point.
-        if (mEditor != null && getEditor().mCreatedWithASelection) {
-            getEditor().startSelectionActionMode();
-            getEditor().mCreatedWithASelection = false;
+        if (mEditor != null && mEditor.mCreatedWithASelection) {
+            mEditor.startSelectionActionMode();
+            mEditor.mCreatedWithASelection = false;
         }
 
         // Phone specific code (there is no ExtractEditText on tablets).
         // ExtractEditText does not call onFocus when it is displayed, and mHasSelectionOnFocus can
         // not be set. Do the test here instead.
         if (this instanceof ExtractEditText && hasSelection() && mEditor != null) {
-            getEditor().startSelectionActionMode();
+            mEditor.startSelectionActionMode();
         }
 
         getViewTreeObserver().removeOnPreDrawListener(this);
@@ -4133,11 +4137,11 @@
         super.onAttachedToWindow();
 
         mTemporaryDetach = false;
-        
+
         // Resolve drawables as the layout direction has been resolved
         resolveDrawables();
 
-        if (mEditor != null) getEditor().onAttachedToWindow();
+        if (mEditor != null) mEditor.onAttachedToWindow();
     }
 
     @Override
@@ -4151,13 +4155,13 @@
 
         resetResolvedDrawables();
 
-        if (mEditor != null) getEditor().onDetachedFromWindow();
+        if (mEditor != null) mEditor.onDetachedFromWindow();
     }
 
     @Override
     public void onScreenStateChanged(int screenState) {
         super.onScreenStateChanged(screenState);
-        if (mEditor != null) getEditor().onScreenStateChanged(screenState);
+        if (mEditor != null) mEditor.onScreenStateChanged(screenState);
     }
 
     @Override
@@ -4308,7 +4312,7 @@
      * @attr ref android.R.styleable#TextView_textIsSelectable
      */
     public boolean isTextSelectable() {
-        return mEditor == null ? false : getEditor().mTextIsSelectable;
+        return mEditor == null ? false : mEditor.mTextIsSelectable;
     }
 
     /**
@@ -4327,9 +4331,9 @@
         if (!selectable && mEditor == null) return; // false is default value with no edit data
 
         createEditorIfNeeded("setTextIsSelectable");
-        if (getEditor().mTextIsSelectable == selectable) return;
+        if (mEditor.mTextIsSelectable == selectable) return;
 
-        getEditor().mTextIsSelectable = selectable;
+        mEditor.mTextIsSelectable = selectable;
         setFocusableInTouchMode(selectable);
         setFocusable(selectable);
         setClickable(selectable);
@@ -4341,7 +4345,7 @@
         setText(getText(), selectable ? BufferType.SPANNABLE : BufferType.NORMAL);
 
         // Called by setText above, but safer in case of future code changes
-        getEditor().prepareCursorControllers();
+        mEditor.prepareCursorControllers();
     }
 
     @Override
@@ -4382,14 +4386,14 @@
         final int selEnd = getSelectionEnd();
         if (mMovement != null && (isFocused() || isPressed()) && selStart >= 0) {
             if (selStart == selEnd) {
-                if (mEditor != null && getEditor().isCursorVisible() &&
-                        (SystemClock.uptimeMillis() - getEditor().mShowCursor) %
+                if (mEditor != null && mEditor.isCursorVisible() &&
+                        (SystemClock.uptimeMillis() - mEditor.mShowCursor) %
                         (2 * Editor.BLINK) < Editor.BLINK) {
                     if (mHighlightPathBogus) {
                         if (mHighlightPath == null) mHighlightPath = new Path();
                         mHighlightPath.reset();
                         mLayout.getCursorPath(selStart, mHighlightPath, mText);
-                        getEditor().updateCursorsPositions();
+                        mEditor.updateCursorsPositions();
                         mHighlightPathBogus = false;
                     }
 
@@ -4469,8 +4473,8 @@
             // Make sure to update invalidateDrawable() when changing this code.
             if (dr.mDrawableTop != null) {
                 canvas.save();
-                canvas.translate(scrollX + compoundPaddingLeft + (hspace - dr.mDrawableWidthTop) / 2,
-                        scrollY + mPaddingTop);
+                canvas.translate(scrollX + compoundPaddingLeft +
+                        (hspace - dr.mDrawableWidthTop) / 2, scrollY + mPaddingTop);
                 dr.mDrawableTop.draw(canvas);
                 canvas.restore();
             }
@@ -4563,7 +4567,7 @@
 
         Path highlight = getUpdatedHighlightPath();
         if (mEditor != null) {
-            getEditor().onDraw(canvas, layout, highlight, mHighlightPaint, cursorOffsetVertical);
+            mEditor.onDraw(canvas, layout, highlight, mHighlightPaint, cursorOffsetVertical);
         } else {
             layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);
         }
@@ -4695,7 +4699,7 @@
         if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) {
             voffset = getVerticalOffset(true);
         }
-        
+
         if (offsetRequired) voffset += getTopPaddingOffset();
 
         return getExtendedPaddingTop() + voffset;
@@ -4712,7 +4716,7 @@
     @Override
     public boolean onKeyPreIme(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_BACK) {
-            boolean isInSelectionMode = mEditor != null && getEditor().mSelectionActionMode != null;
+            boolean isInSelectionMode = mEditor != null && mEditor.mSelectionActionMode != null;
 
             if (isInSelectionMode) {
                 if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
@@ -4762,7 +4766,7 @@
         }
 
         repeatCount--;
-        
+
         // We are going to dispatch the remaining events to either the input
         // or movement method.  To do this, we will just send a repeated stream
         // of down and up events until we have done the complete repeatCount.
@@ -4770,11 +4774,11 @@
         // but adding that is a more complicated change.
         KeyEvent up = KeyEvent.changeAction(event, KeyEvent.ACTION_UP);
         if (which == 1) {
-            // mEditor and getEditor().mInput are not null from doKeyDown
-            getEditor().mKeyListener.onKeyUp(this, (Editable)mText, keyCode, up);
+            // mEditor and mEditor.mInput are not null from doKeyDown
+            mEditor.mKeyListener.onKeyUp(this, (Editable)mText, keyCode, up);
             while (--repeatCount > 0) {
-                getEditor().mKeyListener.onKeyDown(this, (Editable)mText, keyCode, down);
-                getEditor().mKeyListener.onKeyUp(this, (Editable)mText, keyCode, up);
+                mEditor.mKeyListener.onKeyDown(this, (Editable)mText, keyCode, down);
+                mEditor.mKeyListener.onKeyUp(this, (Editable)mText, keyCode, up);
             }
             hideErrorIfUnchanged();
 
@@ -4805,8 +4809,9 @@
             return true;
         }
 
-        if (mEditor != null && (getEditor().mInputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) {
-            int variation = getEditor().mInputType & EditorInfo.TYPE_MASK_VARIATION;
+        if (mEditor != null &&
+                (mEditor.mInputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) {
+            int variation = mEditor.mInputType & EditorInfo.TYPE_MASK_VARIATION;
             if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
                     || variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT) {
                 return true;
@@ -4821,13 +4826,12 @@
      * of inserting the character.  Insert tabs only in multi-line editors.
      */
     private boolean shouldAdvanceFocusOnTab() {
-        if (getKeyListener() != null && !mSingleLine) {
-            if (mEditor != null && (getEditor().mInputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) {
-                int variation = getEditor().mInputType & EditorInfo.TYPE_MASK_VARIATION;
-                if (variation == EditorInfo.TYPE_TEXT_FLAG_IME_MULTI_LINE
-                        || variation == EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) {
-                    return false;
-                }
+        if (getKeyListener() != null && !mSingleLine && mEditor != null &&
+                (mEditor.mInputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) {
+            int variation = mEditor.mInputType & EditorInfo.TYPE_MASK_VARIATION;
+            if (variation == EditorInfo.TYPE_TEXT_FLAG_IME_MULTI_LINE
+                    || variation == EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) {
+                return false;
             }
         }
         return true;
@@ -4845,13 +4849,13 @@
                     // running in a "modern" cupcake environment, so don't need
                     // to worry about the application trying to capture
                     // enter key events.
-                    if (mEditor != null && getEditor().mInputContentType != null) {
+                    if (mEditor != null && mEditor.mInputContentType != null) {
                         // If there is an action listener, given them a
                         // chance to consume the event.
-                        if (getEditor().mInputContentType.onEditorActionListener != null &&
-                                getEditor().mInputContentType.onEditorActionListener.onEditorAction(
+                        if (mEditor.mInputContentType.onEditorActionListener != null &&
+                                mEditor.mInputContentType.onEditorActionListener.onEditorAction(
                                 this, EditorInfo.IME_NULL, event)) {
-                            getEditor().mInputContentType.enterDown = true;
+                            mEditor.mInputContentType.enterDown = true;
                             // We are consuming the enter key for them.
                             return -1;
                         }
@@ -4869,7 +4873,7 @@
                     }
                 }
                 break;
-                
+
             case KeyEvent.KEYCODE_DPAD_CENTER:
                 if (event.hasNoModifiers()) {
                     if (shouldAdvanceFocusOnEnter()) {
@@ -4888,21 +4892,22 @@
 
                 // Has to be done on key down (and not on key up) to correctly be intercepted.
             case KeyEvent.KEYCODE_BACK:
-                if (mEditor != null && getEditor().mSelectionActionMode != null) {
+                if (mEditor != null && mEditor.mSelectionActionMode != null) {
                     stopSelectionActionMode();
                     return -1;
                 }
                 break;
         }
 
-        if (mEditor != null && getEditor().mKeyListener != null) {
+        if (mEditor != null && mEditor.mKeyListener != null) {
             resetErrorChangedFlag();
 
             boolean doDown = true;
             if (otherEvent != null) {
                 try {
                     beginBatchEdit();
-                    final boolean handled = getEditor().mKeyListener.onKeyOther(this, (Editable) mText, otherEvent);
+                    final boolean handled = mEditor.mKeyListener.onKeyOther(this, (Editable) mText,
+                            otherEvent);
                     hideErrorIfUnchanged();
                     doDown = false;
                     if (handled) {
@@ -4915,10 +4920,11 @@
                     endBatchEdit();
                 }
             }
-            
+
             if (doDown) {
                 beginBatchEdit();
-                final boolean handled = getEditor().mKeyListener.onKeyDown(this, (Editable) mText, keyCode, event);
+                final boolean handled = mEditor.mKeyListener.onKeyDown(this, (Editable) mText,
+                        keyCode, event);
                 endBatchEdit();
                 hideErrorIfUnchanged();
                 if (handled) return 1;
@@ -4964,14 +4970,14 @@
          * that error showing.  Otherwise, we take down whatever
          * error was showing when the user types something.
          */
-        if (mEditor != null) getEditor().mErrorWasChanged = false;
+        if (mEditor != null) mEditor.mErrorWasChanged = false;
     }
 
     /**
      * @hide
      */
     public void hideErrorIfUnchanged() {
-        if (mEditor != null && getEditor().mError != null && !getEditor().mErrorWasChanged) {
+        if (mEditor != null && mEditor.mError != null && !mEditor.mErrorWasChanged) {
             setError(null, null);
         }
     }
@@ -5009,11 +5015,11 @@
 
             case KeyEvent.KEYCODE_ENTER:
                 if (event.hasNoModifiers()) {
-                    if (mEditor != null && getEditor().mInputContentType != null
-                            && getEditor().mInputContentType.onEditorActionListener != null
-                            && getEditor().mInputContentType.enterDown) {
-                        getEditor().mInputContentType.enterDown = false;
-                        if (getEditor().mInputContentType.onEditorActionListener.onEditorAction(
+                    if (mEditor != null && mEditor.mInputContentType != null
+                            && mEditor.mInputContentType.onEditorActionListener != null
+                            && mEditor.mInputContentType.enterDown) {
+                        mEditor.mInputContentType.enterDown = false;
+                        if (mEditor.mInputContentType.onEditorActionListener.onEditorAction(
                                 this, EditorInfo.IME_NULL, event)) {
                             return true;
                         }
@@ -5064,8 +5070,8 @@
                 break;
         }
 
-        if (mEditor != null && getEditor().mKeyListener != null)
-            if (getEditor().mKeyListener.onKeyUp(this, (Editable) mText, keyCode, event))
+        if (mEditor != null && mEditor.mKeyListener != null)
+            if (mEditor.mKeyListener.onKeyUp(this, (Editable) mText, keyCode, event))
                 return true;
 
         if (mMovement != null && mLayout != null)
@@ -5077,20 +5083,20 @@
 
     @Override
     public boolean onCheckIsTextEditor() {
-        return mEditor != null && getEditor().mInputType != EditorInfo.TYPE_NULL;
+        return mEditor != null && mEditor.mInputType != EditorInfo.TYPE_NULL;
     }
 
     @Override
     public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
         if (onCheckIsTextEditor() && isEnabled()) {
-            getEditor().createInputMethodStateIfNeeded();
+            mEditor.createInputMethodStateIfNeeded();
             outAttrs.inputType = getInputType();
-            if (getEditor().mInputContentType != null) {
-                outAttrs.imeOptions = getEditor().mInputContentType.imeOptions;
-                outAttrs.privateImeOptions = getEditor().mInputContentType.privateImeOptions;
-                outAttrs.actionLabel = getEditor().mInputContentType.imeActionLabel;
-                outAttrs.actionId = getEditor().mInputContentType.imeActionId;
-                outAttrs.extras = getEditor().mInputContentType.extras;
+            if (mEditor.mInputContentType != null) {
+                outAttrs.imeOptions = mEditor.mInputContentType.imeOptions;
+                outAttrs.privateImeOptions = mEditor.mInputContentType.privateImeOptions;
+                outAttrs.actionLabel = mEditor.mInputContentType.imeActionLabel;
+                outAttrs.actionId = mEditor.mInputContentType.imeActionId;
+                outAttrs.extras = mEditor.mInputContentType.extras;
             } else {
                 outAttrs.imeOptions = EditorInfo.IME_NULL;
             }
@@ -5138,7 +5144,7 @@
      */
     public boolean extractText(ExtractedTextRequest request, ExtractedText outText) {
         createEditorIfNeeded("extractText");
-        return getEditor().extractText(request, outText);
+        return mEditor.extractText(request, outText);
     }
 
     /**
@@ -5177,7 +5183,7 @@
                 content.replace(start, end, text.text);
             }
         }
-        
+
         // Now set the selection position...  make sure it is in range, to
         // avoid crashes.  If this is a partial update, it is possible that
         // the underlying text may have changed, causing us problems here.
@@ -5191,7 +5197,7 @@
         if (end < 0) end = 0;
         else if (end > N) end = N;
         Selection.setSelection(sp, start, end);
-        
+
         // Finally, update the selection mode.
         if ((text.flags&ExtractedText.FLAG_SELECTING) != 0) {
             MetaKeyKeyListener.startSelecting(this, sp);
@@ -5204,13 +5210,13 @@
      * @hide
      */
     public void setExtracting(ExtractedTextRequest req) {
-        if (getEditor().mInputMethodState != null) {
-            getEditor().mInputMethodState.mExtractedTextRequest = req;
+        if (mEditor.mInputMethodState != null) {
+            mEditor.mInputMethodState.mExtractedTextRequest = req;
         }
         // This would stop a possible selection mode, but no such mode is started in case
         // extracted mode will start. Some text is selected though, and will trigger an action mode
         // in the extracted view.
-        getEditor().hideControllers();
+        mEditor.hideControllers();
     }
 
     /**
@@ -5236,17 +5242,17 @@
      * @param info The auto correct info about the text that was corrected.
      */
     public void onCommitCorrection(CorrectionInfo info) {
-        if (mEditor != null) getEditor().onCommitCorrection(info);
+        if (mEditor != null) mEditor.onCommitCorrection(info);
     }
 
     public void beginBatchEdit() {
-        if (mEditor != null) getEditor().beginBatchEdit();
+        if (mEditor != null) mEditor.beginBatchEdit();
     }
-    
+
     public void endBatchEdit() {
-        if (mEditor != null) getEditor().endBatchEdit();
+        if (mEditor != null) mEditor.endBatchEdit();
     }
-    
+
     /**
      * Called by the framework in response to a request to begin a batch
      * of edit operations through a call to link {@link #beginBatchEdit()}.
@@ -5262,7 +5268,7 @@
     public void onEndBatchEdit() {
         // intentionally empty
     }
-    
+
     /**
      * Called by the framework in response to a private command from the
      * current method, provided by it calling
@@ -5290,7 +5296,7 @@
         mBoring = mHintBoring = null;
 
         // Since it depends on the value of mLayout
-        if (mEditor != null) getEditor().prepareCursorControllers();
+        if (mEditor != null) mEditor.prepareCursorControllers();
     }
 
     /**
@@ -5511,7 +5517,7 @@
         }
 
         // CursorControllers need a non-null mLayout
-        if (mEditor != null) getEditor().prepareCursorControllers();
+        if (mEditor != null) mEditor.prepareCursorControllers();
     }
 
     private Layout makeSingleLayout(int wantWidth, BoringLayout.Metrics boring, int ellipsisWidth,
@@ -5587,7 +5593,7 @@
 
     private boolean compressText(float width) {
         if (isHardwareAccelerated()) return false;
-        
+
         // Only compress the text if it hasn't been compressed by the previous pass
         if (width > 0.0f && mLayout != null && getLineCount() == 1 && !mUserSetTextScaleX &&
                 mTextPaint.getTextScaleX() == 1.0f) {
@@ -5953,7 +5959,7 @@
                     invalidate();
                     return;
                 }
-    
+
                 // Dynamic height, but height has stayed the same,
                 // so use our new text layout.
                 if (mLayout.getHeight() == oldht &&
@@ -5979,7 +5985,7 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        if (changed && mEditor != null) getEditor().invalidateTextDisplayList();
+        if (changed && mEditor != null) mEditor.invalidateTextDisplayList();
     }
 
     private boolean isShowingHint() {
@@ -6246,9 +6252,9 @@
         if (start != end) {
             return false;
         }
-        
+
         // First: make sure the line is visible on screen:
-        
+
         int line = mLayout.getLineForOffset(start);
 
         final int top = mLayout.getLineTop(line);
@@ -6264,14 +6270,14 @@
         } else if (bottom > (vspace+vs-vslack)) {
             line = mLayout.getLineForVertical(vspace+vs-vslack-(bottom-top));
         }
-        
+
         // Next: make sure the character is visible on screen:
-        
+
         final int hspace = mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight();
         final int hs = mScrollX;
         final int leftChar = mLayout.getOffsetForHorizontal(line, hs);
         final int rightChar = mLayout.getOffsetForHorizontal(line, hspace+hs);
-        
+
         // line might contain bidirectional text
         final int lowChar = leftChar < rightChar ? leftChar : rightChar;
         final int highChar = leftChar > rightChar ? leftChar : rightChar;
@@ -6282,12 +6288,12 @@
         } else if (newStart > highChar) {
             newStart = highChar;
         }
-        
+
         if (newStart != start) {
             Selection.setSelection((Spannable)mText, newStart);
             return true;
         }
-        
+
         return false;
     }
 
@@ -6436,11 +6442,12 @@
      * @param singleLine
      */
     private void setInputTypeSingleLine(boolean singleLine) {
-        if (mEditor != null && (getEditor().mInputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) {
+        if (mEditor != null &&
+                (mEditor.mInputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) {
             if (singleLine) {
-                getEditor().mInputType &= ~EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
+                mEditor.mInputType &= ~EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
             } else {
-                getEditor().mInputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
+                mEditor.mInputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
             }
         }
     }
@@ -6520,7 +6527,7 @@
     @android.view.RemotableViewMethod
     public void setSelectAllOnFocus(boolean selectAllOnFocus) {
         createEditorIfNeeded("setSelectAllOnFocus");
-        getEditor().mSelectAllOnFocus = selectAllOnFocus;
+        mEditor.mSelectAllOnFocus = selectAllOnFocus;
 
         if (selectAllOnFocus && !(mText instanceof Spannable)) {
             setText(mText, BufferType.SPANNABLE);
@@ -6536,14 +6543,14 @@
     public void setCursorVisible(boolean visible) {
         if (visible && mEditor == null) return; // visible is the default value with no edit data
         createEditorIfNeeded("setCursorVisible");
-        if (getEditor().mCursorVisible != visible) {
-            getEditor().mCursorVisible = visible;
+        if (mEditor.mCursorVisible != visible) {
+            mEditor.mCursorVisible = visible;
             invalidate();
 
-            getEditor().makeBlink();
+            mEditor.makeBlink();
 
             // InsertionPointCursorController depends on mCursorVisible
-            getEditor().prepareCursorControllers();
+            mEditor.prepareCursorControllers();
         }
     }
 
@@ -6628,7 +6635,7 @@
     /**
      * This method is called when the selection has changed, in case any
      * subclasses would like to know.
-     * 
+     *
      * @param selStart The new selection start location.
      * @param selEnd The new selection end location.
      */
@@ -6712,7 +6719,7 @@
             }
         }
 
-        if (mEditor != null) getEditor().sendOnTextChanged(start, after);
+        if (mEditor != null) mEditor.sendOnTextChanged(start, after);
     }
 
     /**
@@ -6739,7 +6746,7 @@
 
         if (curs >= 0) {
             mHighlightPathBogus = true;
-            if (mEditor != null) getEditor().makeBlink();
+            if (mEditor != null) mEditor.makeBlink();
             bringPointIntoView(curs);
         }
 
@@ -6751,7 +6758,7 @@
      * through a thunk.
      */
     void handleTextChanged(CharSequence buffer, int start, int before, int after) {
-        final Editor.InputMethodState ims = mEditor == null ? null : getEditor().mInputMethodState;
+        final Editor.InputMethodState ims = mEditor == null ? null : mEditor.mInputMethodState;
         if (ims == null || ims.mBatchEditNesting == 0) {
             updateAfterEdit();
         }
@@ -6782,7 +6789,7 @@
         boolean selChanged = false;
         int newSelStart=-1, newSelEnd=-1;
 
-        final Editor.InputMethodState ims = mEditor == null ? null : getEditor().mInputMethodState;
+        final Editor.InputMethodState ims = mEditor == null ? null : mEditor.mInputMethodState;
 
         if (what == Selection.SELECTION_END) {
             selChanged = true;
@@ -6791,7 +6798,7 @@
             if (oldStart >= 0 || newStart >= 0) {
                 invalidateCursor(Selection.getSelectionStart(buf), oldStart, newStart);
                 registerForPreDraw();
-                if (mEditor != null) getEditor().makeBlink();
+                if (mEditor != null) mEditor.makeBlink();
             }
         }
 
@@ -6807,7 +6814,7 @@
 
         if (selChanged) {
             mHighlightPathBogus = true;
-            if (mEditor != null && !isFocused()) getEditor().mSelectionMoved = true;
+            if (mEditor != null && !isFocused()) mEditor.mSelectionMoved = true;
 
             if ((buf.getSpanFlags(what)&Spanned.SPAN_INTERMEDIATE) == 0) {
                 if (newSelStart < 0) {
@@ -6830,8 +6837,8 @@
                 ims.mContentChanged = true;
             }
             if (mEditor != null) {
-                if (oldStart >= 0) getEditor().invalidateTextDisplayList(mLayout, oldStart, oldEnd);
-                if (newStart >= 0) getEditor().invalidateTextDisplayList(mLayout, newStart, newEnd);
+                if (oldStart >= 0) mEditor.invalidateTextDisplayList(mLayout, oldStart, oldEnd);
+                if (newStart >= 0) mEditor.invalidateTextDisplayList(mLayout, newStart, newEnd);
             }
         }
 
@@ -6880,8 +6887,9 @@
             }
         }
 
-        if (mEditor != null && getEditor().mSpellChecker != null && newStart < 0 && what instanceof SpellCheckSpan) {
-            getEditor().mSpellChecker.removeSpellCheckSpan((SpellCheckSpan) what);
+        if (mEditor != null && mEditor.mSpellChecker != null && newStart < 0 &&
+                what instanceof SpellCheckSpan) {
+            mEditor.mSpellChecker.removeSpellCheckSpan((SpellCheckSpan) what);
         }
     }
 
@@ -6905,7 +6913,7 @@
         // Because of View recycling in ListView, there is no easy way to know when a TextView with
         // selection becomes visible again. Until a better solution is found, stop text selection
         // mode (if any) as soon as this TextView is recycled.
-        if (mEditor != null) getEditor().hideControllers();
+        if (mEditor != null) mEditor.hideControllers();
     }
 
     @Override
@@ -6924,7 +6932,7 @@
             return;
         }
 
-        if (mEditor != null) getEditor().onFocusChanged(focused, direction);
+        if (mEditor != null) mEditor.onFocusChanged(focused, direction);
 
         if (focused) {
             if (mText instanceof Spannable) {
@@ -6946,7 +6954,7 @@
     public void onWindowFocusChanged(boolean hasWindowFocus) {
         super.onWindowFocusChanged(hasWindowFocus);
 
-        if (mEditor != null) getEditor().onWindowFocusChanged(hasWindowFocus);
+        if (mEditor != null) mEditor.onWindowFocusChanged(hasWindowFocus);
 
         startStopMarquee(hasWindowFocus);
     }
@@ -6955,7 +6963,7 @@
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
         if (mEditor != null && visibility != VISIBLE) {
-            getEditor().hideControllers();
+            mEditor.hideControllers();
         }
     }
 
@@ -6969,7 +6977,7 @@
             BaseInputConnection.removeComposingSpans((Spannable)mText);
         }
     }
-    
+
     @Override
     public void setSelected(boolean selected) {
         boolean wasSelected = isSelected();
@@ -6989,7 +6997,7 @@
     public boolean onTouchEvent(MotionEvent event) {
         final int action = event.getActionMasked();
 
-        if (mEditor != null) getEditor().onTouchEvent(event);
+        if (mEditor != null) mEditor.onTouchEvent(event);
 
         final boolean superResult = super.onTouchEvent(event);
 
@@ -6998,13 +7006,13 @@
          * move the selection away from whatever the menu action was
          * trying to affect.
          */
-        if (mEditor != null && getEditor().mDiscardNextActionUp && action == MotionEvent.ACTION_UP) {
-            getEditor().mDiscardNextActionUp = false;
+        if (mEditor != null && mEditor.mDiscardNextActionUp && action == MotionEvent.ACTION_UP) {
+            mEditor.mDiscardNextActionUp = false;
             return superResult;
         }
 
         final boolean touchIsFinished = (action == MotionEvent.ACTION_UP) &&
-                (mEditor == null || !getEditor().mIgnoreActionUpEvent) && isFocused();
+                (mEditor == null || !mEditor.mIgnoreActionUpEvent) && isFocused();
 
          if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()
                 && mText instanceof Spannable && mLayout != null) {
@@ -7037,7 +7045,7 @@
                 }
 
                 // The above condition ensures that the mEditor is not null
-                getEditor().onTouchUpEvent(event);
+                mEditor.onTouchUpEvent(event);
 
                 handled = true;
             }
@@ -7081,13 +7089,13 @@
      * of interest, in an editable text view.
      */
     public boolean didTouchFocusSelect() {
-        return mEditor != null && getEditor().mTouchFocusSelected;
+        return mEditor != null && mEditor.mTouchFocusSelected;
     }
-    
+
     @Override
     public void cancelLongPress() {
         super.cancelLongPress();
-        if (mEditor != null) getEditor().mIgnoreActionUpEvent = true;
+        if (mEditor != null) mEditor.mIgnoreActionUpEvent = true;
     }
 
     @Override
@@ -7281,16 +7289,17 @@
     /**
      * Unlike {@link #textCanBeSelected()}, this method is based on the <i>current</i> state of the
      * TextView. {@link #textCanBeSelected()} has to be true (this is one of the conditions to have
-     * a selection controller (see {@link Editor#prepareCursorControllers()}), but this is not sufficient.
+     * a selection controller (see {@link Editor#prepareCursorControllers()}), but this is not
+     * sufficient.
      */
     private boolean canSelectText() {
-        return mText.length() != 0 && mEditor != null && getEditor().hasSelectionController();
+        return mText.length() != 0 && mEditor != null && mEditor.hasSelectionController();
     }
 
     /**
      * Test based on the <i>intrinsic</i> charateristics of the TextView.
      * The text must be spannable and the movement method must allow for arbitary selection.
-     * 
+     *
      * See also {@link #canSelectText()}.
      */
     boolean textCanBeSelected() {
@@ -7298,7 +7307,8 @@
         // If you change this condition, make sure prepareCursorController is called anywhere
         // the value of this condition might be changed.
         if (mMovement == null || !mMovement.canSelectArbitrarily()) return false;
-        return isTextEditable() || (isTextSelectable() && mText instanceof Spannable && isEnabled());
+        return isTextEditable() ||
+                (isTextSelectable() && mText instanceof Spannable && isEnabled());
     }
 
     /**
@@ -7322,7 +7332,7 @@
 
     void onLocaleChanged() {
         // Will be re-created on demand in getWordIterator with the proper new locale
-        getEditor().mWordIterator = null;
+        mEditor.mWordIterator = null;
     }
 
     /**
@@ -7331,8 +7341,8 @@
      * @hide
      */
     public WordIterator getWordIterator() {
-        if (getEditor() != null) {
-            return mEditor.getWordIterator(); 
+        if (mEditor != null) {
+            return mEditor.getWordIterator();
         } else {
             return null;
         }
@@ -7423,7 +7433,7 @@
         InputMethodManager imm = InputMethodManager.peekInstance();
         return imm != null && imm.isActive(this);
     }
-    
+
     static final int ID_SELECT_ALL = android.R.id.selectAll;
     static final int ID_CUT = android.R.id.cut;
     static final int ID_COPY = android.R.id.copy;
@@ -7486,12 +7496,12 @@
         }
 
         if (mEditor != null) {
-            handled |= getEditor().performLongClick(handled);
+            handled |= mEditor.performLongClick(handled);
         }
 
         if (handled) {
             performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-            if (mEditor != null) getEditor().mDiscardNextActionUp = true;
+            if (mEditor != null) mEditor.mDiscardNextActionUp = true;
         }
 
         return handled;
@@ -7501,7 +7511,7 @@
     protected void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) {
         super.onScrollChanged(horiz, vert, oldHoriz, oldVert);
         if (mEditor != null) {
-            getEditor().onScrollChanged();
+            mEditor.onScrollChanged();
         }
     }
 
@@ -7529,10 +7539,12 @@
      */
     public boolean isSuggestionsEnabled() {
         if (mEditor == null) return false;
-        if ((getEditor().mInputType & InputType.TYPE_MASK_CLASS) != InputType.TYPE_CLASS_TEXT) return false;
-        if ((getEditor().mInputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) > 0) return false;
+        if ((mEditor.mInputType & InputType.TYPE_MASK_CLASS) != InputType.TYPE_CLASS_TEXT) {
+            return false;
+        }
+        if ((mEditor.mInputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) > 0) return false;
 
-        final int variation = getEditor().mInputType & EditorInfo.TYPE_MASK_VARIATION;
+        final int variation = mEditor.mInputType & EditorInfo.TYPE_MASK_VARIATION;
         return (variation == EditorInfo.TYPE_TEXT_VARIATION_NORMAL ||
                 variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT ||
                 variation == EditorInfo.TYPE_TEXT_VARIATION_LONG_MESSAGE ||
@@ -7566,7 +7578,7 @@
      */
     public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
         createEditorIfNeeded("custom selection action mode set");
-        getEditor().mCustomSelectionActionModeCallback = actionModeCallback;
+        mEditor.mCustomSelectionActionModeCallback = actionModeCallback;
     }
 
     /**
@@ -7575,14 +7587,14 @@
      * @return The current custom selection callback.
      */
     public ActionMode.Callback getCustomSelectionActionModeCallback() {
-        return mEditor == null ? null : getEditor().mCustomSelectionActionModeCallback;
+        return mEditor == null ? null : mEditor.mCustomSelectionActionModeCallback;
     }
 
     /**
      * @hide
      */
     protected void stopSelectionActionMode() {
-        getEditor().stopSelectionActionMode();
+        mEditor.stopSelectionActionMode();
     }
 
     boolean canCut() {
@@ -7590,7 +7602,8 @@
             return false;
         }
 
-        if (mText.length() > 0 && hasSelection() && mText instanceof Editable && mEditor != null && getEditor().mKeyListener != null) {
+        if (mText.length() > 0 && hasSelection() && mText instanceof Editable && mEditor != null &&
+                mEditor.mKeyListener != null) {
             return true;
         }
 
@@ -7611,7 +7624,7 @@
 
     boolean canPaste() {
         return (mText instanceof Editable &&
-                mEditor != null && getEditor().mKeyListener != null &&
+                mEditor != null && mEditor.mKeyListener != null &&
                 getSelectionStart() >= 0 &&
                 getSelectionEnd() >= 0 &&
                 ((ClipboardManager)getContext().getSystemService(Context.CLIPBOARD_SERVICE)).
@@ -7755,7 +7768,7 @@
     public boolean onDragEvent(DragEvent event) {
         switch (event.getAction()) {
             case DragEvent.ACTION_DRAG_STARTED:
-                return mEditor != null && getEditor().hasInsertionController();
+                return mEditor != null && mEditor.hasInsertionController();
 
             case DragEvent.ACTION_DRAG_ENTERED:
                 TextView.this.requestFocus();
@@ -7767,7 +7780,7 @@
                 return true;
 
             case DragEvent.ACTION_DROP:
-                if (mEditor != null) getEditor().onDrop(event);
+                if (mEditor != null) mEditor.onDrop(event);
                 return true;
 
             case DragEvent.ACTION_DRAG_ENDED:
@@ -7779,11 +7792,11 @@
 
     boolean isInBatchEditMode() {
         if (mEditor == null) return false;
-        final Editor.InputMethodState ims = getEditor().mInputMethodState;
+        final Editor.InputMethodState ims = mEditor.mInputMethodState;
         if (ims != null) {
             return ims.mBatchEditNesting > 0;
         }
-        return getEditor().mInBatchEditControllers;
+        return mEditor.mInBatchEditControllers;
     }
 
     @Override
@@ -7938,7 +7951,7 @@
     private void createEditorIfNeeded(String reason) {
         if (mEditor == null) {
             if (!(this instanceof EditText)) {
-                Log.e(LOG_TAG + " EDITOR", "Creating Editor on TextView. " + reason);
+                Log.e(LOG_TAG + " EDITOR", "Creating an Editor on a regular TextView. " + reason);
             }
             mEditor = new Editor(this);
         } else {
@@ -7948,14 +7961,6 @@
         }
     }
 
-    private Editor getEditor() {
-        if (mEditor == null) {
-            //createEditorIfNeeded("Problem: mEditor is not initialized!");
-            Log.e(LOG_TAG, "mEditor not initialized. Please send a bug report to debunne@");
-        }
-        return mEditor;
-    }
-
     /**
      * User interface state that is stored by TextView for implementing
      * {@link View#onSaveInstanceState}.
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index f2b6e45..624dea8 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -27,7 +27,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
 import android.os.Vibrator;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -142,6 +141,7 @@
     private int mTargetResourceId;
     private int mTargetDescriptionsResourceId;
     private int mDirectionDescriptionsResourceId;
+    private boolean mAlwaysTrackFinger;
 
     public MultiWaveView(Context context) {
         this(context, null);
@@ -168,6 +168,7 @@
         mTapRadius = mHandleDrawable.getWidth()/2;
         mOuterRing = new TargetDrawable(res,
                 a.peekValue(R.styleable.MultiWaveView_waveDrawable).resourceId);
+        mAlwaysTrackFinger = a.getBoolean(R.styleable.MultiWaveView_alwaysTrackFinger, false);
 
         // Read chevron animation drawables
         final int chevrons[] = { R.styleable.MultiWaveView_leftChevronDrawable,
@@ -634,7 +635,6 @@
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         final int action = event.getAction();
-
         boolean handled = false;
         switch (action) {
             case MotionEvent.ACTION_DOWN:
@@ -805,7 +805,7 @@
         final float y = event.getY();
         final float dx = x - mWaveCenterX;
         final float dy = y - mWaveCenterY;
-        if (dist2(dx,dy) <= getScaledTapRadiusSquared()) {
+        if (mAlwaysTrackFinger || dist2(dx,dy) <= getScaledTapRadiusSquared()) {
             if (DEBUG) Log.v(TAG, "** Handle HIT");
             switchToState(STATE_FIRST_TOUCH, x, y);
             moveHandleTo(x, y, false);
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index a97c710..684cc87 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -550,6 +550,10 @@
         return;
     }
 
+    // To be filled in later
+    for (size_t i = 0; i < count; i++) {
+        outAdvances->add(0);
+    }
     UErrorCode error = U_ZERO_ERROR;
     bool useNormalizedString = false;
     for (ssize_t i = count - 1; i >= 0; --i) {
@@ -691,23 +695,11 @@
 
         logGlyphs(mShaperItem);
 #endif
-        if (isRTL) {
-            endScriptRun = startScriptRun;
-#if DEBUG_GLYPHS
-            ALOGD("Updated endScriptRun = %d", int(endScriptRun));
-#endif
-        } else {
-            startScriptRun = endScriptRun;
-#if DEBUG_GLYPHS
-            ALOGD("Updated startScriptRun = %d", int(startScriptRun));
-#endif
-        }
 
         if (mShaperItem.advances == NULL || mShaperItem.num_glyphs == 0) {
 #if DEBUG_GLYPHS
             ALOGD("Advances array is empty or num_glypth = 0");
 #endif
-            outAdvances->insertAt(0, outAdvances->size(), countScriptRun);
             continue;
         }
 
@@ -721,15 +713,13 @@
         // Get Advances and their total
         jfloat currentAdvance = HBFixedToFloat(mShaperItem.advances[mShaperItem.log_clusters[0]]);
         jfloat totalFontRunAdvance = currentAdvance;
-        outAdvances->add(currentAdvance);
+        outAdvances->replaceAt(currentAdvance, startScriptRun);
         for (size_t i = 1; i < countScriptRun; i++) {
             size_t clusterPrevious = mShaperItem.log_clusters[i - 1];
             size_t cluster = mShaperItem.log_clusters[i];
-            if (cluster == clusterPrevious) {
-                outAdvances->add(0);
-            } else {
+            if (cluster != clusterPrevious) {
                 currentAdvance = HBFixedToFloat(mShaperItem.advances[mShaperItem.log_clusters[i]]);
-                outAdvances->add(currentAdvance);
+                outAdvances->replaceAt(currentAdvance, startScriptRun + i);
             }
         }
         // TODO: can be removed and go back in the previous loop when Harfbuzz log clusters are fixed
@@ -746,6 +736,7 @@
                     (*outAdvances)[i], mShaperItem.log_clusters[i], totalFontRunAdvance);
         }
 #endif
+
         // Get Glyphs and reverse them in place if RTL
         if (outGlyphs) {
             size_t countGlyphs = mShaperItem.num_glyphs;
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 31b914a..a60467b 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -316,6 +316,19 @@
     return Surface::isValid(surface) ? JNI_TRUE : JNI_FALSE;
 }
 
+static jboolean Surface_isConsumerRunningBehind(JNIEnv* env, jobject clazz)
+{
+    int value = 0;
+    const sp<Surface>& surface(getSurface(env, clazz));
+    if (!Surface::isValid(surface)) {
+        doThrowIAE(env);
+        return 0;
+    }
+    ANativeWindow* anw = static_cast<ANativeWindow *>(surface.get());
+    anw->query(anw, NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value);
+    return (jboolean)value;
+}
+
 static inline SkBitmap::Config convertPixelFormat(PixelFormat format)
 {
     /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
@@ -875,6 +888,7 @@
     {"setFreezeTint",       "(I)V",  (void*)Surface_setFreezeTint },
     {"readFromParcel",      "(Landroid/os/Parcel;)V", (void*)Surface_readFromParcel },
     {"writeToParcel",       "(Landroid/os/Parcel;I)V", (void*)Surface_writeToParcel },
+    {"isConsumerRunningBehind", "()Z", (void*)Surface_isConsumerRunningBehind },
 };
 
 void nativeClassInit(JNIEnv* env, jclass clazz)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e522371..e1b9d55 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -732,14 +732,22 @@
         android:description="@string/permdesc_expandStatusBar" />
 
     <!-- Allows an application to get information about the currently
-         or recently running tasks: a thumbnail representation of the tasks,
-         what activities are running in it, etc. -->
+         or recently running tasks. -->
     <permission android:name="android.permission.GET_TASKS"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="dangerous"
         android:label="@string/permlab_getTasks"
         android:description="@string/permdesc_getTasks" />
 
+    <!-- Allows an application to get full detailed information about
+         recently running tasks, with full fidelity to the real state.
+         @hide -->
+    <permission android:name="android.permission.GET_DETAILED_TASKS"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signature"
+        android:label="@string/permlab_getDetailedTasks"
+        android:description="@string/permdesc_getDetailedTasks" />
+
     <!-- Allows an application to change the Z-order of tasks -->
     <permission android:name="android.permission.REORDER_TASKS"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
diff --git a/core/res/res/anim/activity_close_enter.xml b/core/res/res/anim/activity_close_enter.xml
index c759a83..84e4a19 100644
--- a/core/res/res/anim/activity_close_enter.xml
+++ b/core/res/res/anim/activity_close_enter.xml
@@ -20,12 +20,5 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android" android:zAdjustment="normal">
     <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:duration="@android:integer/config_shortAnimTime"/>
-    <scale android:fromXScale=".95" android:toXScale="1.0"
-            android:fromYScale=".95" android:toYScale="1.0"
-            android:pivotX="50%p" android:pivotY="50%p"
-            android:interpolator="@interpolator/accelerate_quint"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:duration="@android:integer/config_shortAnimTime"/>
-
+            android:duration="300"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/activity_close_exit.xml b/core/res/res/anim/activity_close_exit.xml
index 384810f2..32f6d38 100644
--- a/core/res/res/anim/activity_close_exit.xml
+++ b/core/res/res/anim/activity_close_exit.xml
@@ -22,11 +22,11 @@
     <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
             android:interpolator="@interpolator/decelerate_cubic"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:duration="@android:integer/config_shortAnimTime"/>
-    <scale android:fromXScale="1.0" android:toXScale="1.1"
-            android:fromYScale="1.0" android:toYScale="1.1"
+            android:duration="300"/>
+    <scale android:fromXScale="1.0" android:toXScale=".8"
+            android:fromYScale="1.0" android:toYScale=".8"
             android:pivotX="50%p" android:pivotY="50%p"
-            android:interpolator="@interpolator/decelerate_quint"
+            android:interpolator="@interpolator/decelerate_cubic"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:duration="@android:integer/config_shortAnimTime"/>
+            android:duration="300"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/activity_open_enter.xml b/core/res/res/anim/activity_open_enter.xml
index 744153d..c92f000 100644
--- a/core/res/res/anim/activity_open_enter.xml
+++ b/core/res/res/anim/activity_open_enter.xml
@@ -24,12 +24,12 @@
             android:interpolator="@interpolator/decelerate_cubic"
             android:fillEnabled="true"
             android:fillBefore="false" android:fillAfter="false"
-            android:duration="@android:integer/config_shortAnimTime"/>
-    <scale android:fromXScale="1.1" android:toXScale="1.0"
-            android:fromYScale="1.1" android:toYScale="1.0"
+            android:duration="300"/>
+    <scale android:fromXScale=".8" android:toXScale="1.0"
+            android:fromYScale=".8" android:toYScale="1.0"
             android:pivotX="50%p" android:pivotY="50%p"
-            android:interpolator="@interpolator/decelerate_quint"
+            android:interpolator="@interpolator/decelerate_cubic"
             android:fillEnabled="true"
             android:fillBefore="false" android:fillAfter="false"
-            android:duration="@android:integer/config_shortAnimTime"/>
+            android:duration="300"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/activity_open_exit.xml b/core/res/res/anim/activity_open_exit.xml
index 58e8816..d7bfe82 100644
--- a/core/res/res/anim/activity_open_exit.xml
+++ b/core/res/res/anim/activity_open_exit.xml
@@ -18,15 +18,8 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android" android:zAdjustment="normal">
-    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
             android:fillEnabled="true" android:fillBefore="false" android:fillAfter="false"
-            android:duration="@android:integer/config_shortAnimTime"/>
-    <scale android:fromXScale="1.0" android:toXScale=".95"
-            android:fromYScale="1.0" android:toYScale=".95"
-            android:pivotX="50%p" android:pivotY="50%p"
             android:interpolator="@interpolator/decelerate_quint"
-            android:fillEnabled="true"
-            android:fillBefore="false" android:fillAfter="false"
-            android:duration="@android:integer/config_shortAnimTime"/>
-
+            android:duration="300"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/lock_screen_behind_enter.xml b/core/res/res/anim/lock_screen_behind_enter.xml
index 78b7d29..cb47b3c 100644
--- a/core/res/res/anim/lock_screen_behind_enter.xml
+++ b/core/res/res/anim/lock_screen_behind_enter.xml
@@ -19,14 +19,6 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
     android:background="#ff000000" android:shareInterpolator="false">
-    <scale
-        android:fromXScale="0.90" android:toXScale="1.0"
-        android:fromYScale="0.90" android:toYScale="1.0"
-        android:pivotX="50%p" android:pivotY="50%p"
-        android:fillEnabled="true" android:fillBefore="true"
-        android:interpolator="@interpolator/decelerate_cubic"
-        android:startOffset="@android:integer/config_shortAnimTime"
-        android:duration="@android:integer/config_shortAnimTime" />
     <alpha
         android:fromAlpha="0.0" android:toAlpha="1.0"
         android:fillEnabled="true" android:fillBefore="true"
diff --git a/core/res/res/anim/lock_screen_exit.xml b/core/res/res/anim/lock_screen_exit.xml
index a186126..37383d9 100644
--- a/core/res/res/anim/lock_screen_exit.xml
+++ b/core/res/res/anim/lock_screen_exit.xml
@@ -22,8 +22,8 @@
     android:zAdjustment="top"
     android:shareInterpolator="false">
     <scale
-        android:fromXScale="1.0" android:toXScale="1.15"
-        android:fromYScale="1.0" android:toYScale="1.15"
+        android:fromXScale="1.0" android:toXScale="1.10"
+        android:fromYScale="1.0" android:toYScale="1.10"
         android:pivotX="50%p" android:pivotY="50%p"
         android:fillEnabled="true" android:fillAfter="true"
         android:interpolator="@interpolator/accelerate_quint"
diff --git a/core/res/res/anim/lock_screen_wallpaper_behind_enter.xml b/core/res/res/anim/lock_screen_wallpaper_behind_enter.xml
index a354fae..c29fd1a 100644
--- a/core/res/res/anim/lock_screen_wallpaper_behind_enter.xml
+++ b/core/res/res/anim/lock_screen_wallpaper_behind_enter.xml
@@ -19,14 +19,6 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
     android:detachWallpaper="true" android:shareInterpolator="false">
-    <scale
-        android:fromXScale="0.95" android:toXScale="1.0"
-        android:fromYScale="0.95" android:toYScale="1.0"
-        android:pivotX="50%p" android:pivotY="50%p"
-        android:fillEnabled="true" android:fillBefore="true"
-        android:interpolator="@interpolator/decelerate_cubic"
-        android:startOffset="@android:integer/config_shortAnimTime"
-        android:duration="@android:integer/config_shortAnimTime" />
     <alpha
         android:fromAlpha="0.0" android:toAlpha="1.0"
         android:fillEnabled="true" android:fillBefore="true"
diff --git a/core/res/res/anim/task_close_enter.xml b/core/res/res/anim/task_close_enter.xml
index b39d551..dad8c1f 100644
--- a/core/res/res/anim/task_close_enter.xml
+++ b/core/res/res/anim/task_close_enter.xml
@@ -19,16 +19,21 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
-    <scale android:fromXScale="0.95" android:toXScale="1.0"
-            android:fromYScale="0.95" android:toYScale="1.0"
+    <alpha android:fromAlpha="0" android:toAlpha="1"
+            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+            android:interpolator="@interpolator/decelerate_cubic"
+            android:startOffset="600"
+            android:duration="200"/>
+    <scale android:fromXScale="0.6" android:toXScale="1.0"
+            android:fromYScale="0.6" android:toYScale="1.0"
             android:pivotX="50%p" android:pivotY="50%p"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:startOffset="200"
-            android:duration="300" />
-    <alpha android:fromAlpha="0" android:toAlpha="1.0"
+            android:interpolator="@interpolator/decelerate_cubic"
+            android:startOffset="350"
+            android:duration="400" />
+    <translate android:fromYDelta="-100%" android:toYDelta="0"
             android:interpolator="@interpolator/decelerate_cubic"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:startOffset="200"
-            android:duration="300"/>
+            android:startOffset="350"
+            android:duration="400"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml
index ffbd38a..485c91d 100644
--- a/core/res/res/anim/task_close_exit.xml
+++ b/core/res/res/anim/task_close_exit.xml
@@ -19,17 +19,18 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
-        <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-                android:interpolator="@interpolator/accelerate_cubic"
-                android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-                android:duration="200" />
-        <scale android:fromXScale="1.0" android:toXScale="1.2"
-                android:fromYScale="1.0" android:toYScale="0.8"
-                android:pivotX="50%p" android:pivotY="50%p"
-                android:interpolator="@interpolator/accelerate_quint"
-                android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-                android:duration="200" />
-        <!-- This is needed to keep the animation running while task_close_enter completes -->
-        <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-                android:duration="500" />
+    <scale android:fromXScale="1.0" android:toXScale=".8"
+            android:fromYScale="1.0" android:toYScale=".8"
+            android:pivotX="50%p" android:pivotY="50%p"
+            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+            android:interpolator="@interpolator/decelerate_cubic"
+            android:duration="300" />
+    <alpha android:fromAlpha="1.0" android:toAlpha="0"
+            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+            android:interpolator="@interpolator/decelerate_cubic"
+            android:duration="300"/>
+
+    <!-- This is needed to keep the animation running while task_close_enter completes -->
+    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+            android:duration="600" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index d64f856..8341806 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -19,16 +19,16 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
-    <scale android:fromXScale="1.2" android:toXScale="1.0"
+    <scale android:fromXScale=".8" android:toXScale="1.0"
             android:fromYScale=".8" android:toYScale="1.0"
             android:pivotX="50%p" android:pivotY="50%p"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:startOffset="300"
-            android:duration="240" />
+            android:interpolator="@interpolator/decelerate_quad"
+            android:startOffset="400"
+            android:duration="300" />
     <alpha android:fromAlpha="0" android:toAlpha="1.0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="300"
+            android:startOffset="400"
             android:duration="300"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml
index 19f92c0..af1a4a9 100644
--- a/core/res/res/anim/task_open_exit.xml
+++ b/core/res/res/anim/task_open_exit.xml
@@ -22,14 +22,19 @@
     <alpha android:fromAlpha="1.0" android:toAlpha="0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_cubic"
-            android:duration="200"/>
-    <scale android:fromXScale="1.0" android:toXScale="0.95"
-            android:fromYScale="1.0" android:toYScale="0.95"
+            android:duration="300"/>
+    <scale android:fromXScale="1.0" android:toXScale="0.6"
+            android:fromYScale="1.0" android:toYScale="0.6"
             android:pivotX="50%p" android:pivotY="50%p"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:duration="300" />
+            android:interpolator="@interpolator/accelerate_quad"
+            android:duration="500" />
+    <translate android:fromYDelta="0" android:toYDelta="-100%"
+            android:interpolator="@interpolator/accelerate_quad"
+            android:duration="500"/>
+
     <!-- This is needed to keep the animation running while task_open_enter completes -->
     <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-            android:duration="540" />
+            android:interpolator="@interpolator/accelerate_quad"
+            android:duration="700" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/wallpaper_close_enter.xml b/core/res/res/anim/wallpaper_close_enter.xml
index 1ca5c0c..981923a 100644
--- a/core/res/res/anim/wallpaper_close_enter.xml
+++ b/core/res/res/anim/wallpaper_close_enter.xml
@@ -19,16 +19,14 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:shareInterpolator="false" android:zAdjustment="top">
-    <scale android:fromXScale="1.2" android:toXScale="1.0"
-            android:fromYScale=".8" android:toYScale="1.0"
+    <scale android:fromXScale=".2" android:toXScale="1.0"
+            android:fromYScale=".2" android:toYScale="1.0"
             android:pivotX="50%p" android:pivotY="50%p"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:startOffset="300"
-            android:duration="240" />
+            android:interpolator="@interpolator/decelerate_cubic"
+            android:duration="300" />
     <alpha android:fromAlpha="0" android:toAlpha="1.0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="300"
+            android:interpolator="@interpolator/decelerate_cubic"
             android:duration="300"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/wallpaper_close_exit.xml b/core/res/res/anim/wallpaper_close_exit.xml
index 987fd89..a91eb49 100644
--- a/core/res/res/anim/wallpaper_close_exit.xml
+++ b/core/res/res/anim/wallpaper_close_exit.xml
@@ -19,17 +19,6 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:detachWallpaper="true" android:shareInterpolator="false" android:zAdjustment="normal">
-    <alpha android:fromAlpha="1.0" android:toAlpha="0"
-            android:fillEnabled="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_cubic"
-            android:duration="200"/>
-    <scale android:fromXScale="1.0" android:toXScale="0.95"
-            android:fromYScale="1.0" android:toYScale="0.95"
-            android:pivotX="50%p" android:pivotY="50%p"
-            android:fillEnabled="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:duration="300" />
-    <!-- This is needed to keep the animation running while wallpaper_close_enter completes -->
     <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-            android:duration="600" />
+            android:duration="300" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/wallpaper_open_enter.xml b/core/res/res/anim/wallpaper_open_enter.xml
index 6fdbd40..ee7ab60 100644
--- a/core/res/res/anim/wallpaper_open_enter.xml
+++ b/core/res/res/anim/wallpaper_open_enter.xml
@@ -19,16 +19,7 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:detachWallpaper="true" android:shareInterpolator="false" android:zAdjustment="normal">
-    <scale android:fromXScale="0.95" android:toXScale="1.0"
-            android:fromYScale="0.95" android:toYScale="1.0"
-            android:pivotX="50%p" android:pivotY="50%p"
+    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
             android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:startOffset="200"
-            android:duration="300" />
-    <alpha android:fromAlpha="0" android:toAlpha="1.0"
-            android:interpolator="@interpolator/decelerate_cubic"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:startOffset="200"
             android:duration="300"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/wallpaper_open_exit.xml b/core/res/res/anim/wallpaper_open_exit.xml
index 1804fa8..8a2582e 100644
--- a/core/res/res/anim/wallpaper_open_exit.xml
+++ b/core/res/res/anim/wallpaper_open_exit.xml
@@ -20,16 +20,13 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:shareInterpolator="false" android:zAdjustment="top">
         <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-                android:interpolator="@interpolator/accelerate_cubic"
+                android:interpolator="@interpolator/decelerate_cubic"
                 android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
                 android:duration="200" />
-        <scale android:fromXScale="1.0" android:toXScale="1.2"
-                android:fromYScale="1.0" android:toYScale="0.8"
+        <scale android:fromXScale="1.0" android:toXScale="0.4"
+                android:fromYScale="1.0" android:toYScale="0.4"
                 android:pivotX="50%p" android:pivotY="50%p"
-                android:interpolator="@interpolator/accelerate_quint"
+                android:interpolator="@interpolator/decelerate_cubic"
                 android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-                android:duration="200" />
-        <!-- This is needed to keep the animation running while wallpaper_open_enter completes -->
-        <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-                android:duration="500" />
+                android:duration="300" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_google_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_google_activated.png
new file mode 100644
index 0000000..2c4847c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_google_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_google_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_google_focused.png
new file mode 100644
index 0000000..d98557d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_google_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_google_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_google_normal.png
new file mode 100644
index 0000000..656f3ba
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_google_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_google_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_google_activated.png
new file mode 100644
index 0000000..32a68e0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_google_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_google_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_google_focused.png
new file mode 100644
index 0000000..3f96d03
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_google_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_google_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_google_normal.png
new file mode 100644
index 0000000..2f7efcf
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_google_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_google_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_google_activated.png
new file mode 100644
index 0000000..d643f83
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_google_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_google_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_google_focused.png
new file mode 100644
index 0000000..51863f4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_google_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_google_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_google_normal.png
new file mode 100644
index 0000000..9a9bf68
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_google_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_search_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_search_activated.png
deleted file mode 100644
index c625a36..0000000
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_search_activated.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_search_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_search_normal.png
deleted file mode 100644
index c625a36..0000000
--- a/core/res/res/drawable-xhdpi/ic_lockscreen_search_normal.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/ic_lockscreen_search.xml b/core/res/res/drawable/ic_lockscreen_search.xml
index b103922..2c0091a 100644
--- a/core/res/res/drawable/ic_lockscreen_search.xml
+++ b/core/res/res/drawable/ic_lockscreen_search.xml
@@ -19,12 +19,12 @@
         android:state_enabled="true"
         android:state_active="false"
         android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_search_normal" />
+        android:drawable="@drawable/ic_lockscreen_google_normal" />
 
     <item
         android:state_enabled="true"
         android:state_active="true"
         android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_search_activated" />
+        android:drawable="@drawable/ic_lockscreen_google_activated" />
 
 </selector>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0ac381d..9fa666e 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5383,6 +5383,9 @@
 
         <!-- Used to shift center of pattern horizontally. -->
         <attr name="horizontalOffset" format="dimension" />
+
+        <!-- Used when the handle shouldn't wait to be hit before following the finger -->
+        <attr name="alwaysTrackFinger" format="boolean" />
     </declare-styleable>
 
     <!-- =============================== -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a589015..213f692 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -542,6 +542,13 @@
         information about currently and recently running tasks. Malicious apps may 
         discover private information about other apps.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=50] -->
+    <string name="permlab_getDetailedTasks">retrieve details of running apps</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_getDetailedTasks">Allows the app to retrieve
+        detailed information about currently and recently running tasks. Malicious apps may 
+        discover private information about other apps.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_reorderTasks">reorder running apps</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/packages/InputDevices/res/raw/keyboard_layout_french.kcm b/packages/InputDevices/res/raw/keyboard_layout_french.kcm
new file mode 100644
index 0000000..89e83da
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_french.kcm
@@ -0,0 +1,336 @@
+# Copyright (C) 2012 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.
+
+#
+# French keyboard layout, AZERTY style.
+#
+
+type OVERLAY
+
+map key 16 A
+map key 17 Z
+map key 30 Q
+map key 39 M
+map key 44 W
+map key 50 COMMA
+map key 51 SEMICOLON
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+    label:                              '\u00b2'
+    base:                               '\u00b2'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '&'
+    shift:                              '1'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '\u00e9'
+    shift:                              '2'
+    ralt:                               '~'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '"'
+    shift:                              '3'
+    ralt:                               '#'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '\''
+    shift:                              '4'
+    ralt:                               '{'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '('
+    shift:                              '5'
+    ralt:                               '['
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '-'
+    shift:                              '6'
+    ralt:                               '|'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '\u00e8'
+    shift:                              '7'
+    ralt:                               '`'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '_'
+    shift:                              '8'
+    ralt:                               '\\'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '\u00e7'
+    shift:                              '9'
+    ralt:                               '^'
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '\u00e0'
+    shift:                              '0'
+    ralt:                               '@'
+}
+
+key MINUS {
+    label:                              ')'
+    base:                               ')'
+    shift:                              '\u00b0'
+    ralt:                               ']'
+}
+
+key EQUALS {
+    label:                              '='
+    base:                               '='
+    shift:                              '+'
+    ralt:                               '}'
+}
+
+### ROW 2
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+}
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+    ralt:                               '\u20ac'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift, capslock:                    'O'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '\u02c6'
+    base:                               '\u0302'
+    shift:                              '\u0308'
+}
+
+key RIGHT_BRACKET {
+    label:                              '$'
+    base:                               '$'
+    shift:                              '\u00a3'
+    ralt:                               '\u00a4'
+}
+
+### ROW 3
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+}
+
+key APOSTROPHE {
+    label:                              '\u00f9'
+    base:                               '\u00f9'
+    shift:                              '%'
+}
+
+key BACKSLASH {
+    label:                              '*'
+    base:                               '*'
+    shift:                              '\u00b5'
+}
+
+### ROW 4
+
+key PLUS {
+    label:                              '<'
+    base:                               '<'
+    shift:                              '>'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              '?'
+}
+
+key SEMICOLON {
+    label:                              ';'
+    base:                               ';'
+    shift:                              '.'
+}
+
+key PERIOD {
+    label:                              ':'
+    base:                               ':'
+    shift:                              '/'
+}
+
+key SLASH {
+    label:                              '!'
+    base:                               '!'
+    shift:                              '\u00a7'
+}
diff --git a/packages/InputDevices/res/raw/keyboard_layout_french_ca.kcm b/packages/InputDevices/res/raw/keyboard_layout_french_ca.kcm
new file mode 100644
index 0000000..55ddd60
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_french_ca.kcm
@@ -0,0 +1,339 @@
+# Copyright (C) 2012 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.
+
+#
+# French (Canada) keyboard layout.
+#
+
+type OVERLAY
+
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+    label:                              '#'
+    base:                               '#'
+    shift:                              '|'
+    ralt:                               '\\'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '!'
+    ralt:                               '\u00b1'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '"'
+    ralt:                               '@'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '/'
+    ralt:                               '\u00a3'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              '$'
+    ralt:                               '\u00a2'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              '%'
+    ralt:                               '\u00a4'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              '?'
+    ralt:                               '\u00ac'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '&'
+    ralt:                               '\u00a6'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              '*'
+    ralt:                               '\u00b2'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              '('
+    ralt:                               '\u00b3'
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              ')'
+    ralt:                               '\u00bc'
+}
+
+key MINUS {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+    ralt:                               '\u00bd'
+}
+
+key EQUALS {
+    label:                              '='
+    base:                               '='
+    shift:                              '+'
+    ralt:                               '\u00be'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift, capslock:                    'O'
+    ralt:                               '\u00a7'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+    ralt:                               '\u00b6'
+}
+
+key LEFT_BRACKET {
+    label:                              '\u02c6'
+    base:                               '\u0302'
+    ralt:                               '['
+}
+
+key RIGHT_BRACKET {
+    label:                              '\u00b8'
+    base:                               '\u0327'
+    shift:                              '\u0308'
+    ralt:                               ']'
+}
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+}
+
+key SEMICOLON {
+    label:                              ';'
+    base:                               ';'
+    shift:                              ':'
+    ralt:                               '~'
+}
+
+key APOSTROPHE {
+    label:                              '\u02cb'
+    base:                               '\u0300'
+    ralt:                               '{'
+}
+
+key BACKSLASH {
+    label:                              '<'
+    base:                               '<'
+    shift:                              '>'
+    ralt:                               '}'
+}
+
+### ROW 4
+
+key PLUS {
+    label:                              '\u00ab'
+    base:                               '\u00ab'
+    shift:                              '\u00bb'
+    ralt:                               '\u00b0'
+}
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+    ralt:                               '\u00b5'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              '\''
+    ralt:                               '_'
+}
+
+key PERIOD {
+    label:                              '.'
+    base:                               '.'
+    ralt:                               '-'
+}
+
+key SLASH {
+    label:                              '\u00c9'
+    base:                               '\u00e9'
+    shift, capslock:                    '\u00c9'
+    ralt:                               '\u0301'
+}
diff --git a/packages/InputDevices/res/raw/keyboard_layout_german.kcm b/packages/InputDevices/res/raw/keyboard_layout_german.kcm
index 9c75973..d9caa32 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_german.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_german.kcm
@@ -178,7 +178,7 @@
 key LEFT_BRACKET {
     label:                              '\u00dc'
     base:                               '\u00fc'
-    shift:                              '\u00dc'
+    shift, capslock:                    '\u00dc'
 }
 
 key RIGHT_BRACKET {
@@ -247,13 +247,13 @@
 key SEMICOLON {
     label:                              '\u00d6'
     base:                               '\u00f6'
-    shift:                              '\u00d6'
+    shift, capslock:                    '\u00d6'
 }
 
 key APOSTROPHE {
     label:                              '\u00c4'
     base:                               '\u00e4'
-    shift:                              '\u00c4'
+    shift, capslock:                    '\u00c4'
 }
 
 key BACKSLASH {
diff --git a/packages/InputDevices/res/raw/keyboard_layout_russian.kcm b/packages/InputDevices/res/raw/keyboard_layout_russian.kcm
new file mode 100644
index 0000000..73646d2
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_russian.kcm
@@ -0,0 +1,396 @@
+# Copyright (C) 2012 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.
+
+#
+# Russian keyboard layout.
+# This is a typical Russian PC keyboard layout.
+# English characters are accessible using ralt (Alt Gr).
+#
+
+type OVERLAY
+
+map key 86 BACKSLASH
+
+### ROW 1
+
+key GRAVE {
+    label:                              '\u0401'
+    base:                               '\u0451'
+    shift, capslock:                    '\u0401'
+    ralt:                               '`'
+    ralt+shift:                         '~'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '!'
+    ralt:                               '!'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '"'
+    ralt:                               '@'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '\u2116'
+    ralt:                               '#'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              ';'
+    ralt:                               '$'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              '%'
+    ralt:                               '%'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              ':'
+    ralt:                               '^'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '?'
+    ralt:                               '&'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              '*'
+    ralt:                               '*'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              '('
+    ralt:                               '('
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              ')'
+    ralt:                               ')'
+}
+
+key MINUS {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+    ralt:                               '-'
+    ralt+shift:                         '_'
+}
+
+key EQUALS {
+    label:                              '='
+    base:                               '='
+    shift:                              '+'
+    ralt:                               '='
+    ralt+shift:                         '+'
+}
+
+### ROW 2
+
+key Q {
+    label:                              '\u0419'
+    base:                               '\u0439'
+    shift, capslock:                    '\u0419'
+    ralt:                               'q'
+    ralt+shift, ralt+capslock:          'Q'
+}
+
+key W {
+    label:                              '\u0426'
+    base:                               '\u0446'
+    shift, capslock:                    '\u0426'
+    ralt:                               'w'
+    ralt+shift, ralt+capslock:          'W'
+}
+
+key E {
+    label:                              '\u0423'
+    base:                               '\u0443'
+    shift, capslock:                    '\u0423'
+    ralt:                               'e'
+    ralt+shift, ralt+capslock:          'E'
+}
+
+key R {
+    label:                              '\u041a'
+    base:                               '\u043a'
+    shift, capslock:                    '\u041a'
+    ralt:                               'r'
+    ralt+shift, ralt+capslock:          'R'
+}
+
+key T {
+    label:                              '\u0415'
+    base:                               '\u0435'
+    shift, capslock:                    '\u0415'
+    ralt:                               't'
+    ralt+shift, ralt+capslock:          'T'
+}
+
+key Y {
+    label:                              '\u041d'
+    base:                               '\u043d'
+    shift, capslock:                    '\u041d'
+    ralt:                               'y'
+    ralt+shift, ralt+capslock:          'Y'
+}
+
+key U {
+    label:                              '\u0413'
+    base:                               '\u0433'
+    shift, capslock:                    '\u0413'
+    ralt:                               'u'
+    ralt+shift, ralt+capslock:          'U'
+}
+
+key I {
+    label:                              '\u0428'
+    base:                               '\u0448'
+    shift, capslock:                    '\u0428'
+    ralt:                               'i'
+    ralt+shift, ralt+capslock:          'I'
+}
+
+key O {
+    label:                              '\u0429'
+    base:                               '\u0449'
+    shift, capslock:                    '\u0429'
+    ralt:                               'o'
+    ralt+shift, ralt+capslock:          'O'
+}
+
+key P {
+    label:                              '\u0417'
+    base:                               '\u0437'
+    shift, capslock:                    '\u0417'
+    ralt:                               'p'
+    ralt+shift, ralt+capslock:          'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '\u0425'
+    base:                               '\u0445'
+    shift, capslock:                    '\u0425'
+    ralt:                               '['
+    ralt+shift:                         '{'
+}
+
+key RIGHT_BRACKET {
+    label:                              '\u042a'
+    base:                               '\u044a'
+    shift, capslock:                    '\u042a'
+    ralt:                               ']'
+    ralt+shift:                         '}'
+}
+
+### ROW 3
+
+key A {
+    label:                              '\u0424'
+    base:                               '\u0444'
+    shift, capslock:                    '\u0424'
+    ralt:                               'a'
+    ralt+shift, ralt+capslock:          'A'
+}
+
+key S {
+    label:                              '\u042b'
+    base:                               '\u044b'
+    shift, capslock:                    '\u042b'
+    ralt:                               's'
+    ralt+shift, ralt+capslock:          'S'
+}
+
+key D {
+    label:                              '\u0412'
+    base:                               '\u0432'
+    shift, capslock:                    '\u0412'
+    ralt:                               'd'
+    ralt+shift, ralt+capslock:          'D'
+}
+
+key F {
+    label:                              '\u0410'
+    base:                               '\u0430'
+    shift, capslock:                    '\u0410'
+    ralt:                               'f'
+    ralt+shift, ralt+capslock:          'F'
+}
+
+key G {
+    label:                              '\u041f'
+    base:                               '\u043f'
+    shift, capslock:                    '\u041f'
+    ralt:                               'g'
+    ralt+shift, ralt+capslock:          'G'
+}
+
+key H {
+    label:                              '\u0420'
+    base:                               '\u0440'
+    shift, capslock:                    '\u0420'
+    ralt:                               'h'
+    ralt+shift, ralt+capslock:          'H'
+}
+
+key J {
+    label:                              '\u041e'
+    base:                               '\u043e'
+    shift, capslock:                    '\u041e'
+    ralt:                               'j'
+    ralt+shift, ralt+capslock:          'J'
+}
+
+key K {
+    label:                              '\u041b'
+    base:                               '\u043b'
+    shift, capslock:                    '\u041b'
+    ralt:                               'k'
+    ralt+shift, ralt+capslock:          'K'
+}
+
+key L {
+    label:                              '\u0414'
+    base:                               '\u0434'
+    shift, capslock:                    '\u0414'
+    ralt:                               'l'
+    ralt+shift, ralt+capslock:          'L'
+}
+
+key SEMICOLON {
+    label:                              '\u0416'
+    base:                               '\u0436'
+    shift, capslock:                    '\u0416'
+    ralt:                               ';'
+    ralt+shift:                         ':'
+}
+
+key APOSTROPHE {
+    label:                              '\u042d'
+    base:                               '\u044d'
+    shift, capslock:                    '\u042d'
+    ralt:                               '\''
+    ralt+shift:                         '"'
+}
+
+key BACKSLASH {
+    label:                              '\\'
+    base:                               '\\'
+    shift:                              '/'
+    ralt:                               '|'
+}
+
+### ROW 4
+
+key Z {
+    label:                              '\u042f'
+    base:                               '\u044f'
+    shift, capslock:                    '\u042f'
+    ralt:                               'z'
+    ralt+shift, ralt+capslock:          'Z'
+}
+
+key X {
+    label:                              '\u0427'
+    base:                               '\u0447'
+    shift, capslock:                    '\u0427'
+    ralt:                               'x'
+    ralt+shift, ralt+capslock:          'X'
+}
+
+key C {
+    label:                              '\u0421'
+    base:                               '\u0441'
+    shift, capslock:                    '\u0421'
+    ralt:                               'c'
+    ralt+shift, ralt+capslock:          'C'
+}
+
+key V {
+    label:                              '\u041c'
+    base:                               '\u043c'
+    shift, capslock:                    '\u041c'
+    ralt:                               'v'
+    ralt+shift, ralt+capslock:          'V'
+}
+
+key B {
+    label:                              '\u0418'
+    base:                               '\u0438'
+    shift, capslock:                    '\u0418'
+    ralt:                               'b'
+    ralt+shift, ralt+capslock:          'B'
+}
+
+key N {
+    label:                              '\u0422'
+    base:                               '\u0442'
+    shift, capslock:                    '\u0422'
+    ralt:                               'n'
+    ralt+shift, ralt+capslock:          'N'
+}
+
+key M {
+    label:                              '\u042c'
+    base:                               '\u044c'
+    shift, capslock:                    '\u042c'
+    ralt:                               'm'
+    ralt+shift, ralt+capslock:          'M'
+}
+
+key COMMA {
+    label:                              '\u0411'
+    base:                               '\u0431'
+    shift, capslock:                    '\u0411'
+    ralt:                               ','
+    ralt+shift:                         '<'
+}
+
+key PERIOD {
+    label:                              '\u042e'
+    base:                               '\u044e'
+    shift, capslock:                    '\u042e'
+    ralt:                               '.'
+    ralt+shift:                         '>'
+}
+
+key SLASH {
+    label:                              '.'
+    base:                               '.'
+    shift:                              ','
+    ralt:                               '/'
+    ralt+shift:                         '?'
+}
diff --git a/packages/InputDevices/res/raw/keyboard_layout_russian_apple.kcm b/packages/InputDevices/res/raw/keyboard_layout_russian_apple.kcm
new file mode 100644
index 0000000..18893fe
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_russian_apple.kcm
@@ -0,0 +1,407 @@
+# Copyright (C) 2012 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.
+
+#
+# Russian keyboard layout.
+# This is a variant of the typical Russian PC keyboard layout that is presented
+# on Apple keyboards.  In contrast with the standard layout, some of the symbols and
+# punctuation characters have been rearranged.
+# English characters are accessible using ralt (Alt Gr).
+#
+
+type OVERLAY
+
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+    label:                              '>'
+    base:                               '>'
+    shift:                              '<'
+    ralt:                               '\u00a7'
+    ralt+shift:                         '\u00b1'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '!'
+    ralt:                               '!'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '"'
+    ralt:                               '@'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '\u2116'
+    ralt:                               '#'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              '%'
+    ralt:                               '$'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              ':'
+    ralt:                               '%'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              ','
+    ralt:                               '^'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '.'
+    ralt:                               '&'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              ';'
+    ralt:                               '*'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              '('
+    ralt:                               '('
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              ')'
+    ralt:                               ')'
+}
+
+key MINUS {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+    ralt:                               '-'
+    ralt+shift:                         '_'
+}
+
+key EQUALS {
+    label:                              '='
+    base:                               '='
+    shift:                              '+'
+    ralt:                               '='
+    ralt+shift:                         '+'
+}
+
+### ROW 2
+
+key Q {
+    label:                              '\u0419'
+    base:                               '\u0439'
+    shift, capslock:                    '\u0419'
+    ralt:                               'q'
+    ralt+shift, ralt+capslock:          'Q'
+}
+
+key W {
+    label:                              '\u0426'
+    base:                               '\u0446'
+    shift, capslock:                    '\u0426'
+    ralt:                               'w'
+    ralt+shift, ralt+capslock:          'W'
+}
+
+key E {
+    label:                              '\u0423'
+    base:                               '\u0443'
+    shift, capslock:                    '\u0423'
+    ralt:                               'e'
+    ralt+shift, ralt+capslock:          'E'
+}
+
+key R {
+    label:                              '\u041a'
+    base:                               '\u043a'
+    shift, capslock:                    '\u041a'
+    ralt:                               'r'
+    ralt+shift, ralt+capslock:          'R'
+}
+
+key T {
+    label:                              '\u0415'
+    base:                               '\u0435'
+    shift, capslock:                    '\u0415'
+    ralt:                               't'
+    ralt+shift, ralt+capslock:          'T'
+}
+
+key Y {
+    label:                              '\u041d'
+    base:                               '\u043d'
+    shift, capslock:                    '\u041d'
+    ralt:                               'y'
+    ralt+shift, ralt+capslock:          'Y'
+}
+
+key U {
+    label:                              '\u0413'
+    base:                               '\u0433'
+    shift, capslock:                    '\u0413'
+    ralt:                               'u'
+    ralt+shift, ralt+capslock:          'U'
+}
+
+key I {
+    label:                              '\u0428'
+    base:                               '\u0448'
+    shift, capslock:                    '\u0428'
+    ralt:                               'i'
+    ralt+shift, ralt+capslock:          'I'
+}
+
+key O {
+    label:                              '\u0429'
+    base:                               '\u0449'
+    shift, capslock:                    '\u0429'
+    ralt:                               'o'
+    ralt+shift, ralt+capslock:          'O'
+}
+
+key P {
+    label:                              '\u0417'
+    base:                               '\u0437'
+    shift, capslock:                    '\u0417'
+    ralt:                               'p'
+    ralt+shift, ralt+capslock:          'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '\u0425'
+    base:                               '\u0445'
+    shift, capslock:                    '\u0425'
+    ralt:                               '['
+    ralt+shift:                         '{'
+}
+
+key RIGHT_BRACKET {
+    label:                              '\u042a'
+    base:                               '\u044a'
+    shift, capslock:                    '\u042a'
+    ralt:                               ']'
+    ralt+shift:                         '}'
+}
+
+### ROW 3
+
+key A {
+    label:                              '\u0424'
+    base:                               '\u0444'
+    shift, capslock:                    '\u0424'
+    ralt:                               'a'
+    ralt+shift, ralt+capslock:          'A'
+}
+
+key S {
+    label:                              '\u042b'
+    base:                               '\u044b'
+    shift, capslock:                    '\u042b'
+    ralt:                               's'
+    ralt+shift, ralt+capslock:          'S'
+}
+
+key D {
+    label:                              '\u0412'
+    base:                               '\u0432'
+    shift, capslock:                    '\u0412'
+    ralt:                               'd'
+    ralt+shift, ralt+capslock:          'D'
+}
+
+key F {
+    label:                              '\u0410'
+    base:                               '\u0430'
+    shift, capslock:                    '\u0410'
+    ralt:                               'f'
+    ralt+shift, ralt+capslock:          'F'
+}
+
+key G {
+    label:                              '\u041f'
+    base:                               '\u043f'
+    shift, capslock:                    '\u041f'
+    ralt:                               'g'
+    ralt+shift, ralt+capslock:          'G'
+}
+
+key H {
+    label:                              '\u0420'
+    base:                               '\u0440'
+    shift, capslock:                    '\u0420'
+    ralt:                               'h'
+    ralt+shift, ralt+capslock:          'H'
+}
+
+key J {
+    label:                              '\u041e'
+    base:                               '\u043e'
+    shift, capslock:                    '\u041e'
+    ralt:                               'j'
+    ralt+shift, ralt+capslock:          'J'
+}
+
+key K {
+    label:                              '\u041b'
+    base:                               '\u043b'
+    shift, capslock:                    '\u041b'
+    ralt:                               'k'
+    ralt+shift, ralt+capslock:          'K'
+}
+
+key L {
+    label:                              '\u0414'
+    base:                               '\u0434'
+    shift, capslock:                    '\u0414'
+    ralt:                               'l'
+    ralt+shift, ralt+capslock:          'L'
+}
+
+key SEMICOLON {
+    label:                              '\u0416'
+    base:                               '\u0436'
+    shift, capslock:                    '\u0416'
+    ralt:                               ';'
+    ralt+shift:                         ':'
+}
+
+key APOSTROPHE {
+    label:                              '\u042d'
+    base:                               '\u044d'
+    shift, capslock:                    '\u042d'
+    ralt:                               '\''
+    ralt+shift:                         '"'
+}
+
+key BACKSLASH {
+    label:                              '\u0401'
+    base:                               '\u0451'
+    shift, capslock:                    '\u0401'
+    ralt:                               '\\'
+    ralt+shift:                         '|'
+}
+
+### ROW 4
+
+key PLUS {
+    label:                              '['
+    base:                               '['
+    shift:                              ']'
+    ralt:                               '`'
+    ralt+shift:                         '~'
+}
+
+key Z {
+    label:                              '\u042f'
+    base:                               '\u044f'
+    shift, capslock:                    '\u042f'
+    ralt:                               'z'
+    ralt+shift, ralt+capslock:          'Z'
+}
+
+key X {
+    label:                              '\u0427'
+    base:                               '\u0447'
+    shift, capslock:                    '\u0427'
+    ralt:                               'x'
+    ralt+shift, ralt+capslock:          'X'
+}
+
+key C {
+    label:                              '\u0421'
+    base:                               '\u0441'
+    shift, capslock:                    '\u0421'
+    ralt:                               'c'
+    ralt+shift, ralt+capslock:          'C'
+}
+
+key V {
+    label:                              '\u041c'
+    base:                               '\u043c'
+    shift, capslock:                    '\u041c'
+    ralt:                               'v'
+    ralt+shift, ralt+capslock:          'V'
+}
+
+key B {
+    label:                              '\u0418'
+    base:                               '\u0438'
+    shift, capslock:                    '\u0418'
+    ralt:                               'b'
+    ralt+shift, ralt+capslock:          'B'
+}
+
+key N {
+    label:                              '\u0422'
+    base:                               '\u0442'
+    shift, capslock:                    '\u0422'
+    ralt:                               'n'
+    ralt+shift, ralt+capslock:          'N'
+}
+
+key M {
+    label:                              '\u042c'
+    base:                               '\u044c'
+    shift, capslock:                    '\u042c'
+    ralt:                               'm'
+    ralt+shift, ralt+capslock:          'M'
+}
+
+key COMMA {
+    label:                              '\u0411'
+    base:                               '\u0431'
+    shift, capslock:                    '\u0411'
+    ralt:                               ','
+    ralt+shift:                         '<'
+}
+
+key PERIOD {
+    label:                              '\u042e'
+    base:                               '\u044e'
+    shift, capslock:                    '\u042e'
+    ralt:                               '.'
+    ralt+shift:                         '>'
+}
+
+key SLASH {
+    label:                              '/'
+    base:                               '/'
+    shift:                              '?'
+    ralt:                               '/'
+    ralt+shift:                         '?'
+}
diff --git a/packages/InputDevices/res/raw/keyboard_layout_spanish.kcm b/packages/InputDevices/res/raw/keyboard_layout_spanish.kcm
new file mode 100644
index 0000000..da9159b
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_spanish.kcm
@@ -0,0 +1,329 @@
+# Copyright (C) 2012 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.
+
+#
+# Spanish (Spain) keyboard layout.
+#
+
+type OVERLAY
+
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+    label:                              '\u00ba'
+    base:                               '\u00ba'
+    shift:                              '\u00aa'
+    ralt:                               '\\'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '!'
+    ralt:                               '|'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '"'
+    ralt:                               '@'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '\u00b7'
+    ralt:                               '#'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              '$'
+    ralt:                               '\u0303'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              '%'
+    ralt:                               '\u20ac'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              '&'
+    ralt:                               '\u00ac'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '/'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              '('
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              ')'
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              '='
+}
+
+key MINUS {
+    label:                              '\''
+    base:                               '\''
+    shift:                              '?'
+}
+
+key EQUALS {
+    label:                              '\u00a1'
+    base:                               '\u00a1'
+    shift:                              '\u00bf'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+    ralt:                               '\u20ac'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift, capslock:                    'O'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '\u02cb'
+    base:                               '\u0300'
+    shift:                              '\u0302'
+    ralt:                               '['
+}
+
+key RIGHT_BRACKET {
+    label:                              '+'
+    base:                               '+'
+    shift:                              '*'
+    ralt:                               ']'
+}
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+}
+
+key SEMICOLON {
+    label:                              '\u00d1'
+    base:                               '\u00f1'
+    shift, capslock:                    '\u00d1'
+}
+
+key APOSTROPHE {
+    label:                              '\u00b4'
+    base:                               '\u0301'
+    shift:                              '\u0308'
+    ralt:                               '{'
+}
+
+key BACKSLASH {
+    label:                              '\u00c7'
+    base:                               '\u00e7'
+    shift, capslock:                    '\u00c7'
+    ralt:                               '}'
+}
+
+### ROW 4
+
+key PLUS {
+    label:                              '<'
+    base:                               '<'
+    shift:                              '>'
+}
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              ';'
+}
+
+key PERIOD {
+    label:                              '.'
+    base:                               '.'
+    shift:                              ':'
+}
+
+key SLASH {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+}
diff --git a/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm b/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm
new file mode 100644
index 0000000..a75d154
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm
@@ -0,0 +1,334 @@
+# Copyright (C) 2012 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.
+
+#
+# Swiss French keyboard layout.
+# Same as Swiss German except in the placement of the umlaut / accented keys.
+#
+
+type OVERLAY
+
+map key 21 Z
+map key 44 Y
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+    label:                              '\u00a7'
+    base:                               '\u00a7'
+    shift:                              '\u00b0'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '+'
+    ralt:                               '\u00a6'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '"'
+    ralt:                               '@'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '*'
+    ralt:                               '#'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              '\u00e7'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              '%'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              '&'
+    ralt:                               '\u00ac'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '/'
+    ralt:                               '|'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              '('
+    ralt:                               '\u00a2'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              ')'
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              '='
+}
+
+key MINUS {
+    label:                              '\''
+    base:                               '\''
+    shift:                              '?'
+    ralt:                               '\u0301'
+}
+
+key EQUALS {
+    label:                              '\u02c6'
+    base:                               '\u0302'
+    shift:                              '\u0300'
+    ralt:                               '\u0303'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+    ralt:                               '\u20ac'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift, capslock:                    'O'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '\u00e8'
+    base:                               '\u00e8'
+    shift:                              '\u00fc'
+    ralt:                               '['
+}
+
+key RIGHT_BRACKET {
+    label:                              '\u00a8'
+    base:                               '\u0308'
+    shift:                              '!'
+    ralt:                               ']'
+}
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+}
+
+key SEMICOLON {
+    label:                              '\u00e9'
+    base:                               '\u00e9'
+    shift:                              '\u00f6'
+}
+
+key APOSTROPHE {
+    label:                              '\u00e0'
+    base:                               '\u00e0'
+    shift:                              '\u00e4'
+    ralt:                               '{'
+}
+
+key BACKSLASH {
+    label:                              '$'
+    base:                               '$'
+    shift:                              '\u00a3'
+    ralt:                               '}'
+}
+
+### ROW 4
+
+key PLUS {
+    label:                              '<'
+    base:                               '<'
+    shift:                              '>'
+    ralt:                               '\\'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              ';'
+}
+
+key PERIOD {
+    label:                              '.'
+    base:                               '.'
+    shift:                              ':'
+}
+
+key SLASH {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+}
diff --git a/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm b/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm
new file mode 100644
index 0000000..ae93f4b
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm
@@ -0,0 +1,334 @@
+# Copyright (C) 2012 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.
+
+#
+# Swiss German keyboard layout.
+# Same as Swiss French except in the placement of the umlaut / accented keys.
+#
+
+type OVERLAY
+
+map key 21 Z
+map key 44 Y
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+    label:                              '\u00a7'
+    base:                               '\u00a7'
+    shift:                              '\u00b0'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '+'
+    ralt:                               '\u00a6'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '"'
+    ralt:                               '@'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '*'
+    ralt:                               '#'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              '\u00e7'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              '%'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              '&'
+    ralt:                               '\u00ac'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '/'
+    ralt:                               '|'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              '('
+    ralt:                               '\u00a2'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              ')'
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              '='
+}
+
+key MINUS {
+    label:                              '\''
+    base:                               '\''
+    shift:                              '?'
+    ralt:                               '\u0301'
+}
+
+key EQUALS {
+    label:                              '\u02c6'
+    base:                               '\u0302'
+    shift:                              '\u0300'
+    ralt:                               '\u0303'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+    ralt:                               '\u20ac'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift, capslock:                    'O'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '\u00fc'
+    base:                               '\u00fc'
+    shift:                              '\u00e8'
+    ralt:                               '['
+}
+
+key RIGHT_BRACKET {
+    label:                              '\u00a8'
+    base:                               '\u0308'
+    shift:                              '!'
+    ralt:                               ']'
+}
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+}
+
+key SEMICOLON {
+    label:                              '\u00f6'
+    base:                               '\u00f6'
+    shift:                              '\u00e9'
+}
+
+key APOSTROPHE {
+    label:                              '\u00e4'
+    base:                               '\u00e4'
+    shift:                              '\u00e0'
+    ralt:                               '{'
+}
+
+key BACKSLASH {
+    label:                              '$'
+    base:                               '$'
+    shift:                              '\u00a3'
+    ralt:                               '}'
+}
+
+### ROW 4
+
+key PLUS {
+    label:                              '<'
+    base:                               '<'
+    shift:                              '>'
+    ralt:                               '\\'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              ';'
+}
+
+key PERIOD {
+    label:                              '.'
+    base:                               '.'
+    shift:                              ':'
+}
+
+key SLASH {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+}
diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml
index 6d5ee98..b44bc5c 100644
--- a/packages/InputDevices/res/values/strings.xml
+++ b/packages/InputDevices/res/values/strings.xml
@@ -11,4 +11,25 @@
 
     <!-- German keyboard layout label. [CHAR LIMIT=35] -->
     <string name="keyboard_layout_german_label">German</string>
+
+    <!-- French keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_french_label">French</string>
+
+    <!-- Canadian French keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_french_ca_label">French (Canada)</string>
+
+    <!-- Russian keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_russian_label">Russian</string>
+
+    <!-- Russian (Apple style) keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_russian_apple_label">Russian, Apple</string>
+
+    <!-- Spanish keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_spanish_label">Spanish</string>
+
+    <!-- Swiss French keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_swiss_french_label">Swiss French</string>
+
+    <!-- Swiss German keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_swiss_german_label">Swiss German</string>
 </resources>
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index 459a0e4..58920dc 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -11,4 +11,32 @@
     <keyboard-layout android:name="keyboard_layout_german"
             android:label="@string/keyboard_layout_german_label"
             android:kcm="@raw/keyboard_layout_german" />
+
+    <keyboard-layout android:name="keyboard_layout_french"
+            android:label="@string/keyboard_layout_french_label"
+            android:kcm="@raw/keyboard_layout_french" />
+
+    <keyboard-layout android:name="keyboard_layout_french_ca"
+            android:label="@string/keyboard_layout_french_ca_label"
+            android:kcm="@raw/keyboard_layout_french_ca" />
+
+    <keyboard-layout android:name="keyboard_layout_russian"
+            android:label="@string/keyboard_layout_russian_label"
+            android:kcm="@raw/keyboard_layout_russian" />
+
+    <keyboard-layout android:name="keyboard_layout_russian_apple"
+            android:label="@string/keyboard_layout_russian_apple_label"
+            android:kcm="@raw/keyboard_layout_russian_apple" />
+
+    <keyboard-layout android:name="keyboard_layout_spanish"
+            android:label="@string/keyboard_layout_spanish_label"
+            android:kcm="@raw/keyboard_layout_spanish" />
+
+    <keyboard-layout android:name="keyboard_layout_swiss_french"
+            android:label="@string/keyboard_layout_swiss_french_label"
+            android:kcm="@raw/keyboard_layout_swiss_french" />
+
+    <keyboard-layout android:name="keyboard_layout_swiss_german"
+            android:label="@string/keyboard_layout_swiss_german_label"
+            android:kcm="@raw/keyboard_layout_swiss_german" />
 </keyboard-layouts>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index f200f43..a31c264 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -29,6 +29,7 @@
 
     <!-- ActivityManager -->
     <uses-permission android:name="android.permission.GET_TASKS" />
+    <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
     <uses-permission android:name="android.permission.REORDER_TASKS" />
     <uses-permission android:name="android.permission.REMOVE_TASKS" />
     <uses-permission android:name="android.permission.STOP_APP_SWITCHES" />
@@ -37,6 +38,7 @@
 
     <!-- WindowManager -->
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
     <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
     <uses-permission android:name="android.permission.SET_ORIENTATION" />
diff --git a/packages/SystemUI/res/drawable/navbar_search_bg_scrim.png b/packages/SystemUI/res/drawable/navbar_search_bg_scrim.png
new file mode 100644
index 0000000..d595ed2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/navbar_search_bg_scrim.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/navbar_search_handle.xml b/packages/SystemUI/res/drawable/navbar_search_handle.xml
new file mode 100644
index 0000000..e40fa2c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/navbar_search_handle.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="false"
+        android:drawable="@*android:drawable/ic_lockscreen_handle_pressed" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="true"
+        android:state_focused="false"
+        android:drawable="@*android:drawable/ic_lockscreen_handle_pressed" />
+
+</selector>
diff --git a/packages/SystemUI/res/drawable/navbar_search_outerring.xml b/packages/SystemUI/res/drawable/navbar_search_outerring.xml
new file mode 100644
index 0000000..37b6c1c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/navbar_search_outerring.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <size android:height="@dimen/navbar_search_outerring_diameter"
+        android:width="@dimen/navbar_search_outerring_diameter" />
+    <solid android:color="#00000000" />
+    <stroke android:color="#1affffff" android:width="2dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/status_bar_search_panel.xml b/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
new file mode 100644
index 0000000..2adee33
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2012, 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.SearchPanelView
+    xmlns:prvandroid="http://schemas.android.com/apk/prv/res/android"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/search_panel_container"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:paddingBottom="0dip">
+
+    <RelativeLayout
+        android:id="@+id/search_bg_protect"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginBottom="0dip">
+
+        <RelativeLayout
+            android:id="@+id/search_panel_container"
+            android:layout_width="230dip"
+            android:layout_height="match_parent"
+            android:layout_alignParentRight="true">
+
+            <com.android.internal.widget.multiwaveview.MultiWaveView
+                android:id="@+id/multi_wave_view"
+                android:orientation="vertical"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_alignParentBottom="true"
+                android:background="@drawable/navbar_search_bg_scrim"
+
+                prvandroid:targetDrawables="@array/navbar_search_targets"
+                prvandroid:targetDescriptions="@array/navbar_search_target_descriptions"
+                prvandroid:directionDescriptions="@array/navbar_search_direction_descriptions"
+                prvandroid:handleDrawable="@drawable/navbar_search_handle"
+                prvandroid:waveDrawable="@drawable/navbar_search_outerring"
+                prvandroid:outerRadius="@dimen/navbar_search_target_placement_radius"
+                prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
+                prvandroid:hitRadius="@dimen/navbar_search_hit_radius"
+                prvandroid:verticalOffset="0dip"
+                prvandroid:horizontalOffset="60dip"
+                prvandroid:feedbackCount="0"
+                prvandroid:vibrationDuration="0"
+                prvandroid:alwaysTrackFinger="true"/>
+
+        </RelativeLayout>
+
+    </RelativeLayout>
+
+</com.android.systemui.SearchPanelView>
diff --git a/packages/SystemUI/res/layout-port/status_bar_search_panel.xml b/packages/SystemUI/res/layout-port/status_bar_search_panel.xml
new file mode 100644
index 0000000..463fa04
--- /dev/null
+++ b/packages/SystemUI/res/layout-port/status_bar_search_panel.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2012, 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.SearchPanelView
+    xmlns:prvandroid="http://schemas.android.com/apk/prv/res/android"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/search_panel_container"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:paddingBottom="0dip">
+
+    <RelativeLayout
+        android:id="@+id/search_bg_protect"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginBottom="0dip">
+
+        <RelativeLayout
+            android:id="@+id/search_panel_container"
+            android:layout_width="match_parent"
+            android:layout_height="230dip"
+            android:layout_alignParentBottom="true">
+
+            <com.android.internal.widget.multiwaveview.MultiWaveView
+                android:id="@+id/multi_wave_view"
+                android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_alignParentBottom="true"
+                android:background="@drawable/navbar_search_bg_scrim"
+
+                prvandroid:targetDrawables="@array/navbar_search_targets"
+                prvandroid:targetDescriptions="@array/navbar_search_target_descriptions"
+                prvandroid:directionDescriptions="@array/navbar_search_direction_descriptions"
+                prvandroid:handleDrawable="@drawable/navbar_search_handle"
+                prvandroid:waveDrawable="@drawable/navbar_search_outerring"
+                prvandroid:outerRadius="@dimen/navbar_search_target_placement_radius"
+                prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
+                prvandroid:hitRadius="@dimen/navbar_search_hit_radius"
+                prvandroid:horizontalOffset="0dip"
+                prvandroid:verticalOffset="60dip"
+                prvandroid:feedbackCount="0"
+                prvandroid:vibrationDuration="0"
+                prvandroid:alwaysTrackFinger="true"/>
+
+        </RelativeLayout>
+
+    </RelativeLayout>
+
+</com.android.systemui.SearchPanelView>
diff --git a/packages/SystemUI/res/values-land/arrays.xml b/packages/SystemUI/res/values-land/arrays.xml
new file mode 100644
index 0000000..53f374d
--- /dev/null
+++ b/packages/SystemUI/res/values-land/arrays.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2012, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <array name="navbar_search_targets">
+        <item>@null</item>
+        <item>@null</item>
+        <item>@*android:drawable/ic_lockscreen_search</item>
+        <item>@null</item>
+    </array>
+
+    <array name="navbar_search_target_descriptions">
+        <item>@null</item>
+        <item>@null</item>
+        <item>@*android:string/description_target_search</item>
+        <item>@null</item>
+    </array>
+
+    <array name="navbar_search_direction_descriptions">
+        <item>@null</item>
+        <item>@null</item>
+        <item>@*android:string/description_direction_left</item>
+        <item>@null</item>
+    </array>
+
+</resources>
diff --git a/packages/SystemUI/res/values-port/arrays.xml b/packages/SystemUI/res/values-port/arrays.xml
new file mode 100644
index 0000000..f8b1620
--- /dev/null
+++ b/packages/SystemUI/res/values-port/arrays.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2012, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    
+    <array name="navbar_search_targets">
+        <item>@null</item>
+        <item>@*android:drawable/ic_lockscreen_search</item>
+        <item>@null</item>
+        <item>@null</item>
+    </array>
+
+    <array name="navbar_search_target_descriptions">
+        <item>@null</item>
+        <item>@*android:string/description_target_search</item>
+        <item>@null</item>
+        <item>@null</item>
+    </array>
+
+    <array name="navbar_search_direction_descriptions">
+        <item>@null</item>
+        <item>@*android:string/description_direction_up</item>
+        <item>@null</item>
+        <item>@null</item>
+    </array>
+
+</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b8e8fe4..531f154 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -105,4 +105,17 @@
 
     <!-- The width of the view containing the menu status bar icon -->
     <dimen name="navigation_menu_key_width">40dip</dimen>
+
+    <!-- Default target placement radius for navigation bar search target -->
+    <dimen name="navbar_search_target_placement_radius">150dip</dimen>
+
+    <!-- Default distance beyond which snaps to the target radius -->
+    <dimen name="navbar_search_snap_margin">20dip</dimen>
+
+    <!-- Default distance from each snap target considers a "hit" -->
+    <dimen name="navbar_search_hit_radius">60dip</dimen>
+
+    <!-- Diameter of outer shape drawable shown in navbar search-->
+    <dimen name="navbar_search_outerring_diameter">300dip</dimen>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
new file mode 100644
index 0000000..369a093
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2012 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;
+
+import android.animation.Animator;
+import android.animation.LayoutTransition;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.speech.RecognizerIntent;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.internal.widget.multiwaveview.MultiWaveView;
+import com.android.internal.widget.multiwaveview.MultiWaveView.OnTriggerListener;
+import com.android.systemui.R;
+import com.android.systemui.recent.StatusBarTouchProxy;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.tablet.StatusBarPanel;
+import com.android.systemui.statusbar.tablet.TabletStatusBar;
+
+public class SearchPanelView extends FrameLayout implements
+        StatusBarPanel, Animator.AnimatorListener {
+    static final String TAG = "SearchPanelView";
+    static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
+    private Context mContext;
+    private BaseStatusBar mBar;
+    private StatusBarTouchProxy mStatusBarTouchProxy;
+
+    private boolean mShowing;
+    private View mSearchTargetsContainer;
+    private MultiWaveView mMultiWaveView;
+
+
+    public SearchPanelView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SearchPanelView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mContext = context;
+    }
+
+    final MultiWaveView.OnTriggerListener mMultiWaveViewListener
+            = new MultiWaveView.OnTriggerListener() {
+
+        public void onGrabbed(View v, int handle) {
+        }
+
+        public void onReleased(View v, int handle) {
+        }
+
+        public void onGrabbedStateChange(View v, int handle) {
+            if (OnTriggerListener.NO_HANDLE == handle) {
+                mBar.hideSearchPanel();
+            }
+        }
+
+        public void onTrigger(View v, int target) {
+            final int resId = mMultiWaveView.getResourceIdForTarget(target);
+            switch (resId) {
+                case com.android.internal.R.drawable.ic_lockscreen_search:
+                    Intent intent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
+                    intent.setFlags(
+                            Intent.FLAG_ACTIVITY_NEW_TASK
+                            | Intent.FLAG_ACTIVITY_SINGLE_TOP
+                            | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                    try {
+                        mContext.startActivity(intent);
+                    } catch (ActivityNotFoundException e) {
+                        Log.w(TAG, "Application not found for action " + intent.getAction());
+                    }
+                    mBar.hideSearchPanel();
+                break;
+            }
+        }
+    };
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mSearchTargetsContainer = (ViewGroup) findViewById(R.id.search_panel_container);
+        mStatusBarTouchProxy = (StatusBarTouchProxy) findViewById(R.id.status_bar_touch_proxy);
+        // TODO: fetch views
+        mMultiWaveView = (MultiWaveView) findViewById(R.id.multi_wave_view);
+        mMultiWaveView.setOnTriggerListener(mMultiWaveViewListener);
+    }
+
+    private boolean pointInside(int x, int y, View v) {
+        final int l = v.getLeft();
+        final int r = v.getRight();
+        final int t = v.getTop();
+        final int b = v.getBottom();
+        return x >= l && x < r && y >= t && y < b;
+    }
+
+    public boolean isInContentArea(int x, int y) {
+        if (pointInside(x, y, mSearchTargetsContainer)) {
+            return true;
+        } else if (mStatusBarTouchProxy != null &&
+                pointInside(x, y, mStatusBarTouchProxy)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public void show(boolean show, boolean animate) {
+        if (animate) {
+            if (mShowing != show) {
+                mShowing = show;
+                // TODO: start animating ring
+            }
+        } else {
+            mShowing = show;
+            onAnimationEnd(null);
+        }
+        setVisibility(show ? View.VISIBLE : View.GONE);
+        if (show) {
+            setFocusable(true);
+            setFocusableInTouchMode(true);
+            requestFocus();
+        }
+    }
+
+    public void hide(boolean animate) {
+        if (!animate) {
+            setVisibility(View.GONE);
+        }
+        if (mBar != null) {
+            // This will indirectly cause show(false, ...) to get called
+            mBar.animateCollapse();
+        }
+    }
+
+    public void onAnimationCancel(Animator animation) {
+    }
+
+    public void onAnimationEnd(Animator animation) {
+        if (mShowing) {
+            final LayoutTransition transitioner = new LayoutTransition();
+            ((ViewGroup)mSearchTargetsContainer).setLayoutTransition(transitioner);
+            createCustomAnimations(transitioner);
+        } else {
+            ((ViewGroup)mSearchTargetsContainer).setLayoutTransition(null);
+        }
+    }
+
+    public void onAnimationRepeat(Animator animation) {
+    }
+
+    public void onAnimationStart(Animator animation) {
+    }
+
+    /**
+     * We need to be aligned at the bottom.  LinearLayout can't do this, so instead,
+     * let LinearLayout do all the hard work, and then shift everything down to the bottom.
+     */
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        // setPanelHeight(mSearchTargetsContainer.getHeight());
+    }
+
+    @Override
+    public boolean dispatchHoverEvent(MotionEvent event) {
+        // Ignore hover events outside of this panel bounds since such events
+        // generate spurious accessibility events with the panel content when
+        // tapping outside of it, thus confusing the user.
+        final int x = (int) event.getX();
+        final int y = (int) event.getY();
+        if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
+            return super.dispatchHoverEvent(event);
+        }
+        return true;
+    }
+
+    /**
+     * Whether the panel is showing, or, if it's animating, whether it will be
+     * when the animation is done.
+     */
+    public boolean isShowing() {
+        return mShowing;
+    }
+
+    public void setBar(BaseStatusBar bar) {
+        mBar = bar;
+    }
+
+    public void setStatusBarView(final View statusBarView) {
+        if (mStatusBarTouchProxy != null) {
+            mStatusBarTouchProxy.setStatusBar(statusBarView);
+//            mMultiWaveView.setOnTouchListener(new OnTouchListener() {
+//                public boolean onTouch(View v, MotionEvent event) {
+//                    return statusBarView.onTouchEvent(event);
+//                }
+//            });
+        }
+    }
+
+    private void createCustomAnimations(LayoutTransition transitioner) {
+        transitioner.setDuration(200);
+        transitioner.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
+        transitioner.setAnimator(LayoutTransition.DISAPPEARING, null);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 19306a9..4dd96fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -55,6 +55,7 @@
 import com.android.internal.statusbar.StatusBarIconList;
 import com.android.internal.statusbar.StatusBarNotification;
 import com.android.internal.widget.SizeAdaptiveLayout;
+import com.android.systemui.SearchPanelView;
 import com.android.systemui.SystemUI;
 import com.android.systemui.recent.RecentsPanelView;
 import com.android.systemui.recent.RecentTasksLoader;
@@ -73,6 +74,8 @@
     protected static final int MSG_CLOSE_RECENTS_PANEL = 1021;
     protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
     protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
+    protected static final int MSG_OPEN_SEARCH_PANEL = 1024;
+    protected static final int MSG_CLOSE_SEARCH_PANEL = 1025;
 
     protected CommandQueue mCommandQueue;
     protected IStatusBarService mBarService;
@@ -81,6 +84,9 @@
     // used to notify status bar for suppressing notification LED
     protected boolean mPanelSlightlyVisible;
 
+    // Search panel
+    protected SearchPanelView mSearchPanelView;
+
     // Recent apps
     protected RecentsPanelView mRecentsPanel;
     protected RecentTasksLoader mRecentTasksLoader;
@@ -278,12 +284,29 @@
     }
 
     @Override
+    public void showSearchPanel() {
+        int msg = MSG_OPEN_SEARCH_PANEL;
+        mHandler.removeMessages(msg);
+        mHandler.sendEmptyMessage(msg);
+    }
+
+    @Override
+    public void hideSearchPanel() {
+        int msg = MSG_CLOSE_SEARCH_PANEL;
+        mHandler.removeMessages(msg);
+        mHandler.sendEmptyMessage(msg);
+    }
+
+    @Override
     public void onRecentsPanelVisibilityChanged(boolean visible) {
     }
 
     protected abstract WindowManager.LayoutParams getRecentsLayoutParams(
             LayoutParams layoutParams);
 
+    protected abstract WindowManager.LayoutParams getSearchLayoutParams(
+            LayoutParams layoutParams);
+
     protected void updateRecentsPanel(int recentsResId) {
         // Recents Panel
         boolean visible = false;
@@ -319,6 +342,31 @@
 
     }
 
+    protected void updateSearchPanel() {
+        // Search Panel
+        boolean visible = false;
+        if (mSearchPanelView != null) {
+            visible = mSearchPanelView.isShowing();
+            WindowManagerImpl.getDefault().removeView(mSearchPanelView);
+        }
+
+        // Provide SearchPanel with a temporary parent to allow layout params to work.
+        LinearLayout tmpRoot = new LinearLayout(mContext);
+        mSearchPanelView = (SearchPanelView) LayoutInflater.from(mContext).inflate(
+                 R.layout.status_bar_search_panel, tmpRoot, false);
+        mSearchPanelView.setOnTouchListener(
+                 new TouchOutsideListener(MSG_CLOSE_SEARCH_PANEL, mSearchPanelView));
+        mSearchPanelView.setVisibility(View.GONE);
+
+        WindowManager.LayoutParams lp = getSearchLayoutParams(mSearchPanelView.getLayoutParams());
+
+        WindowManagerImpl.getDefault().addView(mSearchPanelView, lp);
+        mSearchPanelView.setBar(this);
+        if (visible) {
+            mSearchPanelView.show(true, false);
+        }
+    }
+
     protected H createHandler() {
          return new H();
     }
@@ -346,6 +394,18 @@
                   if (DEBUG) Slog.d(TAG, "cancel preloading recents");
                   mRecentsPanel.clearRecentTasksList();
                   break;
+             case MSG_OPEN_SEARCH_PANEL:
+                 if (DEBUG) Slog.d(TAG, "opening search panel");
+                 if (mSearchPanelView != null) {
+                     mSearchPanelView.show(true, true);
+                 }
+                 break;
+             case MSG_CLOSE_SEARCH_PANEL:
+                 if (DEBUG) Slog.d(TAG, "closing search panel");
+                 if (mSearchPanelView != null && mSearchPanelView.isShowing()) {
+                     mSearchPanelView.show(false, true);
+                 }
+                 break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index f88a3cc9..4209354 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -59,7 +59,7 @@
     private static final int MSG_TOP_APP_WINDOW_CHANGED = 8 << MSG_SHIFT;
     private static final int MSG_SHOW_IME_BUTTON        = 9 << MSG_SHIFT;
     private static final int MSG_SET_HARD_KEYBOARD_STATUS = 10 << MSG_SHIFT;
-    
+
     private static final int MSG_TOGGLE_RECENT_APPS       = 11 << MSG_SHIFT;
     private static final int MSG_PRELOAD_RECENT_APPS      = 12 << MSG_SHIFT;
     private static final int MSG_CANCEL_PRELOAD_RECENT_APPS       = 13 << MSG_SHIFT;
@@ -95,6 +95,8 @@
         public void setHardKeyboardStatus(boolean available, boolean enabled);
         public void toggleRecentApps();
         public void preloadRecentApps();
+        public void showSearchPanel();
+        public void hideSearchPanel();
         public void cancelPreloadRecentApps();
         public void setNavigationIconHints(int hints);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
new file mode 100644
index 0000000..f725724
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2010 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.statusbar;
+
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.VelocityTracker;
+import android.view.View;
+
+public class DelegateViewHelper {
+    private static final int VELOCITY_THRESHOLD = 1000;
+    private VelocityTracker mVelocityTracker;
+    private View mDelegateView;
+    private View mSourceView;
+    private BaseStatusBar mBar;
+    private int[] mTempPoint = new int[2];
+    private int mOrientation;
+
+    public DelegateViewHelper(View sourceView) {
+        mSourceView = sourceView;
+    }
+
+    public void setDelegateView(View view) {
+        mDelegateView = view;
+    }
+
+    public void setBar(BaseStatusBar phoneStatusBar) {
+        mBar = phoneStatusBar;
+    }
+
+    public void setOrientation(int orientation) {
+        mOrientation = orientation;
+    }
+
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                mVelocityTracker = VelocityTracker.obtain();
+                break;
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                mVelocityTracker.recycle();
+                mVelocityTracker = null;
+                break;
+        }
+        if (mVelocityTracker != null) {
+            if (mDelegateView != null && mDelegateView.getVisibility() != View.VISIBLE) {
+                mVelocityTracker.addMovement(event);
+                mVelocityTracker.computeCurrentVelocity(1000);
+                final boolean isVertical = (mOrientation == Surface.ROTATION_90
+                        || mOrientation == Surface.ROTATION_270);
+                float velocity = isVertical ? - mVelocityTracker.getXVelocity()
+                        : - mVelocityTracker.getYVelocity();
+                if (velocity > VELOCITY_THRESHOLD) {
+                    if (mDelegateView != null && mDelegateView.getVisibility() != View.VISIBLE) {
+                        mBar.showSearchPanel();
+                    }
+                }
+            }
+        }
+        if (mDelegateView != null) {
+            mSourceView.getLocationOnScreen(mTempPoint);
+            float deltaX = mTempPoint[0];
+            float deltaY = mTempPoint[1];
+
+            mDelegateView.getLocationOnScreen(mTempPoint);
+            deltaX -= mTempPoint[0];
+            deltaY -= mTempPoint[1];
+
+            event.offsetLocation(deltaX, deltaY);
+            mDelegateView.dispatchTouchEvent(event);
+            event.offsetLocation(-deltaX, -deltaY);
+        }
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 11e067f..73c5d3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -31,10 +31,12 @@
 import android.view.animation.AccelerateInterpolator;
 import android.view.Display;
 import android.view.MotionEvent;
+import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Surface;
 import android.view.WindowManager;
+import android.view.WindowManagerImpl;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
@@ -43,8 +45,9 @@
 import java.lang.StringBuilder;
 
 import com.android.internal.statusbar.IStatusBarService;
-
 import com.android.systemui.R;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.DelegateViewHelper;
 
 public class NavigationBarView extends LinearLayout {
     final static boolean DEBUG = false;
@@ -68,6 +71,8 @@
     int mDisabledFlags = 0;
     int mNavigationIconHints = 0;
 
+    private DelegateViewHelper mDelegateHelper;
+
     // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
     final static boolean WORKAROUND_INVALID_LAYOUT = true;
     final static int MSG_CHECK_INVALID_LAYOUT = 8686;
@@ -95,6 +100,19 @@
         }
     }
 
+    public void setDelegateView(View view) {
+        mDelegateHelper.setDelegateView(view);
+    }
+
+    public void setBar(BaseStatusBar phoneStatusBar) {
+        mDelegateHelper.setBar(phoneStatusBar);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        return mDelegateHelper.onInterceptTouchEvent(event);
+    }
+
     private H mHandler = new H();
 
     public View getRecentsButton() {
@@ -127,6 +145,7 @@
         mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
         mVertical = false;
         mShowMenu = false;
+        mDelegateHelper = new DelegateViewHelper(this);
     }
 
     View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
@@ -411,4 +430,5 @@
                 );
         pw.println("    }");
     }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 61500e9..80ee64f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -258,7 +258,7 @@
     // ================================================================================
     // Constructing the view
     // ================================================================================
-    protected View makeStatusBarView() {
+    protected PhoneStatusBarView makeStatusBarView() {
         final Context context = mContext;
 
         Resources res = context.getResources();
@@ -294,6 +294,7 @@
                     (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
 
                 mNavigationBarView.setDisabledFlags(mDisabled);
+                mNavigationBarView.setBar(this);
             }
         } catch (RemoteException ex) {
             // no window manager? good luck with that
@@ -389,6 +390,32 @@
         return lp;
     }
 
+    @Override
+    protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) {
+        boolean opaque = false;
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+                | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+                (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
+        if (ActivityManager.isHighEndGfx(mDisplay)) {
+            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+        } else {
+            lp.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+            lp.dimAmount = 0.7f;
+        }
+        lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
+        lp.setTitle("SearchPanel");
+        // TODO: Define custom animation for Search panel
+        lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
+        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
+        | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
+        return lp;
+    }
+
     protected void updateRecentsPanel() {
         super.updateRecentsPanel(R.layout.status_bar_recent_panel);
         // Make .03 alpha the minimum so you always see the item a bit-- slightly below
@@ -397,6 +424,33 @@
         mRecentsPanel.setMinSwipeAlpha(0.03f);
     }
 
+    @Override
+    protected void updateSearchPanel() {
+        super.updateSearchPanel();
+        mSearchPanelView.setStatusBarView(mStatusBarView);
+        mNavigationBarView.setDelegateView(mSearchPanelView);
+    }
+
+    @Override
+    public void showSearchPanel() {
+        super.showSearchPanel();
+        WindowManager.LayoutParams lp =
+            (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
+        lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+        lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY;
+        WindowManagerImpl.getDefault().updateViewLayout(mNavigationBarView, lp);
+    }
+
+    @Override
+    public void hideSearchPanel() {
+        super.hideSearchPanel();
+        WindowManager.LayoutParams lp =
+            (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
+        lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+        lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
+        WindowManagerImpl.getDefault().updateViewLayout(mNavigationBarView, lp);
+    }
+
     protected int getStatusBarGravity() {
         return Gravity.TOP | Gravity.FILL_HORIZONTAL;
     }
@@ -412,12 +466,30 @@
         }
     };
     private StatusBarNotification mCurrentlyIntrudingNotification;
+    View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() {
+        public boolean onTouch(View v, MotionEvent event) {
+            switch(event.getAction()) {
+                case MotionEvent.ACTION_DOWN:
+                    Slog.d(TAG, "showing search panel");
+                    showSearchPanel();
+                break;
+
+                case MotionEvent.ACTION_UP:
+                    Slog.d(TAG, "hiding search panel");
+                    hideSearchPanel();
+                break;
+            }
+            return false;
+        }
+    };
 
     private void prepareNavigationBarView() {
         mNavigationBarView.reorient();
 
         mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
         mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
+        updateSearchPanel();
+//        mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
     }
 
     // For small-screen devices (read: phones) that lack hardware navigation buttons
@@ -528,7 +600,7 @@
             Slog.d(TAG, "Presenting high-priority notification");
             // special new transient ticker mode
             // 1. Populate mIntruderAlertView
-            
+
             if (notification.notification.intruderView == null) {
                 Slog.e(TAG, notification.notification.toString() + " wanted to intrude but intruderView was null");
                 return;
@@ -544,7 +616,7 @@
             mIntruderAlertView.applyIntruderContent(notification.notification.intruderView, listener);
 
             mCurrentlyIntrudingNotification = notification;
-            
+
             // 2. Animate mIntruderAlertView in
             mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
 
@@ -698,7 +770,7 @@
 
             // Recalculate the position of the sliding windows and the titles.
             updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-            
+
             if (ENABLE_INTRUDERS && old == mCurrentlyIntrudingNotification) {
                 mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
             }
@@ -1672,7 +1744,7 @@
         addStatusBarWindow();
         addExpandedWindow();
     }
-    
+
     private void addStatusBarWindow() {
         // Put up the view
         final int height = getStatusBarHeight();
@@ -1697,9 +1769,10 @@
         lp.gravity = getStatusBarGravity();
         lp.setTitle("StatusBar");
         lp.packageName = mContext.getPackageName();
-        WindowManagerImpl.getDefault().addView(makeStatusBarView(), lp);
+        mStatusBarView = makeStatusBarView();
+        WindowManagerImpl.getDefault().addView(mStatusBarView, lp);
     }
-    
+
     void addExpandedWindow() {
         WindowManager.LayoutParams lp;
         int pixelFormat;
@@ -1780,11 +1853,11 @@
                 panelh = disph;
             }
         }
-        
+
         // catch orientation changes and other peculiar cases
         if (panelh > disph || (panelh < disph && !mTracking && !mAnimating))
             panelh = disph;
-        
+
         mTrackingPosition = panelh;
         // XXX: this is all very WIP
         //mNotificationPanel.setY(panelh);
@@ -1796,9 +1869,9 @@
         final float frac = (float)panelh / disph;
         final int color = ((int)(0xB0 * frac * frac)) << 24;
         mExpandedWindowView.setBackgroundColor(color);
-        
+
 //        Slog.d(TAG, String.format("updateExpanded: pos=%d frac=%.2f col=0x%08x", pos, frac, color));
-        
+
 //        if (mExpandedParams != null) {
 //            if (mCloseView.getWindowVisibility() == View.VISIBLE) {
 //                mCloseView.getLocationInWindow(mPositionTmp);
@@ -2060,7 +2133,7 @@
             // oh well
         }
     }
-    
+
     /**
      * Reload some of our resources when the configuration changes.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 7b3b745..3bdefcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -18,6 +18,7 @@
 
 import android.animation.LayoutTransition;
 import android.animation.ObjectAnimator;
+import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.Notification;
 import android.app.PendingIntent;
@@ -174,7 +175,7 @@
     KeyEvent mSpaceBarKeyEvent = null;
 
     View mCompatibilityHelpDialog = null;
-    
+
     // for disabling the status bar
     int mDisabled = 0;
 
@@ -192,7 +193,7 @@
         addStatusBarWindow();
         addPanelWindows();
     }
-    
+
     private void addStatusBarWindow() {
         final View sb = makeStatusBarView();
 
@@ -328,6 +329,10 @@
         mRecentTasksLoader = new RecentTasksLoader(context);
         updateRecentsPanel();
 
+        // Search Panel
+        mStatusBarView.setBar(this);
+        updateSearchPanel();
+
         // Input methods Panel
         mInputMethodsPanel = (InputMethodsPanel) View.inflate(context,
                 R.layout.system_bar_input_methods_panel, null);
@@ -350,7 +355,7 @@
         lp.windowAnimations = R.style.Animation_RecentPanel;
 
         WindowManagerImpl.getDefault().addView(mInputMethodsPanel, lp);
-        
+
         // Compatibility mode selector panel
         mCompatModePanel = (CompatModePanel) View.inflate(context,
                 R.layout.system_bar_compat_mode_panel, null);
@@ -373,7 +378,7 @@
         lp.windowAnimations = android.R.style.Animation_Dialog;
 
         WindowManagerImpl.getDefault().addView(mCompatModePanel, lp);
-        
+
         mRecentButton.setOnTouchListener(mRecentsPanel);
 
         mPile = (NotificationRowLayout)mNotificationPanel.findViewById(R.id.content);
@@ -646,11 +651,64 @@
         return lp;
     }
 
+    @Override
+    protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) {
+        boolean opaque = false;
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+                (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
+        if (ActivityManager.isHighEndGfx(mDisplay)) {
+            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+        } else {
+            lp.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+            lp.dimAmount = 0.7f;
+        }
+        lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
+        lp.setTitle("SearchPanel");
+        // TODO: Define custom animation for Search panel
+        lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
+        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
+                | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
+        return lp;
+    }
+
     protected void updateRecentsPanel() {
         super.updateRecentsPanel(R.layout.system_bar_recent_panel);
         mRecentsPanel.setStatusBarView(mStatusBarView);
     }
 
+    @Override
+    protected void updateSearchPanel() {
+        super.updateSearchPanel();
+        mSearchPanelView.setStatusBarView(mStatusBarView);
+        mStatusBarView.setDelegateView(mSearchPanelView);
+    }
+
+    @Override
+    public void showSearchPanel() {
+        super.showSearchPanel();
+        WindowManager.LayoutParams lp =
+            (android.view.WindowManager.LayoutParams) mStatusBarView.getLayoutParams();
+        lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+        lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY;
+        WindowManagerImpl.getDefault().updateViewLayout(mStatusBarView, lp);
+    }
+
+    @Override
+    public void hideSearchPanel() {
+        super.hideSearchPanel();
+        WindowManager.LayoutParams lp =
+            (android.view.WindowManager.LayoutParams) mStatusBarView.getLayoutParams();
+        lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+        lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
+        WindowManagerImpl.getDefault().updateViewLayout(mStatusBarView, lp);
+    }
+
     public int getStatusBarHeight() {
         return mStatusBarView != null ? mStatusBarView.getHeight()
                 : mContext.getResources().getDimensionPixelSize(
@@ -1191,7 +1249,7 @@
         if (mCompatibilityHelpDialog != null) {
             return;
         }
-        
+
         mCompatibilityHelpDialog = View.inflate(mContext, R.layout.compat_mode_help, null);
         View button = mCompatibilityHelpDialog.findViewById(R.id.button);
 
@@ -1227,7 +1285,7 @@
             mCompatibilityHelpDialog = null;
         }
     }
-    
+
     public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
         mInputMethodSwitchButton.setImeWindowStatus(token,
                 (vis & InputMethodService.IME_ACTIVE) != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
index 877a40e..a6fc396 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.statusbar.tablet;
 
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.DelegateViewHelper;
+
 import android.content.Context;
 import android.os.Handler;
 import android.util.AttributeSet;
@@ -31,13 +34,24 @@
     private final View[] mIgnoreChildren = new View[MAX_PANELS];
     private final View[] mPanels = new View[MAX_PANELS];
     private final int[] mPos = new int[2];
+    private DelegateViewHelper mDelegateHelper;
 
     public TabletStatusBarView(Context context) {
         super(context);
+        mDelegateHelper = new DelegateViewHelper(this);
     }
 
     public TabletStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mDelegateHelper = new DelegateViewHelper(this);
+    }
+
+    public void setDelegateView(View view) {
+        mDelegateHelper.setDelegateView(view);
+    }
+
+    public void setBar(BaseStatusBar phoneStatusBar) {
+        mDelegateHelper.setBar(phoneStatusBar);
     }
 
     @Override
@@ -72,6 +86,9 @@
         if (TabletStatusBar.DEBUG) {
             Slog.d(TabletStatusBar.TAG, "TabletStatusBarView not intercepting event");
         }
+        if (mDelegateHelper != null) {
+            return mDelegateHelper.onInterceptTouchEvent(ev);
+        }
         return super.onInterceptTouchEvent(ev);
     }
 
@@ -97,7 +114,7 @@
 
     /**
      * Let the status bar know that if you tap on ignore while panel is showing, don't do anything.
-     * 
+     *
      * Debounces taps on, say, a popup's trigger when the popup is already showing.
      */
     public void setIgnoreChildren(int index, View ignore, View panel) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index cc663c2..96eaa28 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -131,6 +131,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
 import android.view.WindowManagerImpl;
 import android.view.WindowManagerPolicy;
@@ -216,16 +217,18 @@
     static final int SYSTEM_OVERLAY_LAYER = 18;
     // the navigation bar, if available, shows atop most things
     static final int NAVIGATION_BAR_LAYER = 19;
+    // some panels (e.g. search) need to show on top of the navigation bar
+    static final int NAVIGATION_BAR_PANEL_LAYER = 20;
     // system-level error dialogs
-    static final int SYSTEM_ERROR_LAYER = 20;
+    static final int SYSTEM_ERROR_LAYER = 21;
     // the drag layer: input for drag-and-drop is associated with this window,
     // which sits above all other focusable windows
-    static final int DRAG_LAYER = 21;
-    static final int SECURE_SYSTEM_OVERLAY_LAYER = 22;
-    static final int BOOT_PROGRESS_LAYER = 23;
+    static final int DRAG_LAYER = 22;
+    static final int SECURE_SYSTEM_OVERLAY_LAYER = 23;
+    static final int BOOT_PROGRESS_LAYER = 24;
     // the (mouse) pointer layer
-    static final int POINTER_LAYER = 24;
-    static final int HIDDEN_NAV_CONSUMER_LAYER = 25;
+    static final int POINTER_LAYER = 25;
+    static final int HIDDEN_NAV_CONSUMER_LAYER = 26;
 
     static final int APPLICATION_MEDIA_SUBLAYER = -2;
     static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
@@ -306,7 +309,6 @@
     WindowState mStatusBar = null;
     boolean mHasSystemNavBar;
     int mStatusBarHeight;
-    final ArrayList<WindowState> mStatusBarSubPanels = new ArrayList<WindowState>();
     WindowState mNavigationBar = null;
     boolean mHasNavigationBar = false;
     boolean mCanHideNavigationBar = false;
@@ -1335,6 +1337,8 @@
             return POINTER_LAYER;
         case TYPE_NAVIGATION_BAR:
             return NAVIGATION_BAR_LAYER;
+        case TYPE_NAVIGATION_BAR_PANEL:
+            return NAVIGATION_BAR_PANEL_LAYER;
         case TYPE_BOOT_PROGRESS:
             return BOOT_PROGRESS_LAYER;
         case TYPE_HIDDEN_NAV_CONSUMER:
@@ -1577,6 +1581,11 @@
                 mNavigationBar = win;
                 if (DEBUG_LAYOUT) Log.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
                 break;
+            case TYPE_NAVIGATION_BAR_PANEL:
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.STATUS_BAR_SERVICE,
+                        "PhoneWindowManager");
+                break;
             case TYPE_STATUS_BAR_PANEL:
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.STATUS_BAR_SERVICE,
@@ -1586,7 +1595,6 @@
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.STATUS_BAR_SERVICE,
                         "PhoneWindowManager");
-                mStatusBarSubPanels.add(win);
                 break;
             case TYPE_KEYGUARD:
                 if (mKeyguard != null) {
@@ -1606,8 +1614,6 @@
             mKeyguard = null;
         } else if (mNavigationBar == win) {
             mNavigationBar = null;
-        } else {
-            mStatusBarSubPanels.remove(win);
         }
     }
 
@@ -2480,7 +2486,8 @@
                                     "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
                                     pf.left, pf.top, pf.right, pf.bottom));
                     }
-                } else if (attrs.type == TYPE_NAVIGATION_BAR) {
+                } else if (attrs.type == TYPE_NAVIGATION_BAR
+                        || attrs.type == TYPE_NAVIGATION_BAR_PANEL) {
                     // The navigation bar has Real Ultimate Power.
                     pf.left = df.left = mUnrestrictedScreenLeft;
                     pf.top = df.top = mUnrestrictedScreenTop;
@@ -2778,25 +2785,6 @@
             // behind it.
             return false;
         }
-        if (mStatusBar != null && mStatusBar.isVisibleLw()) {
-            RectF rect = new RectF(mStatusBar.getShownFrameLw());
-            for (int i=mStatusBarSubPanels.size()-1; i>=0; i--) {
-                WindowState w = mStatusBarSubPanels.get(i);
-                if (w.isVisibleLw()) {
-                    rect.union(w.getShownFrameLw());
-                }
-            }
-            final int insetw = mRestrictedScreenWidth/10;
-            final int inseth = mRestrictedScreenHeight/10;
-            if (rect.contains(insetw, inseth, mRestrictedScreenWidth-insetw,
-                        mRestrictedScreenHeight-inseth)) {
-                // All of the status bar windows put together cover the
-                // screen, so the app can't be seen.  (Note this test doesn't
-                // work if the rects of these windows are at odd offsets or
-                // sizes, causing gaps in the rect union we have computed.)
-                return false;
-            }
-        }
         return true;
     }
 
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 6022f10..c6b701f 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -3143,7 +3143,7 @@
             mOrientedRanges.distance.min =
                     mRawPointerAxes.distance.minValue * mDistanceScale;
             mOrientedRanges.distance.max =
-                    mRawPointerAxes.distance.minValue * mDistanceScale;
+                    mRawPointerAxes.distance.maxValue * mDistanceScale;
             mOrientedRanges.distance.flat = 0;
             mOrientedRanges.distance.fuzz =
                     mRawPointerAxes.distance.fuzz * mDistanceScale;
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index e980ccc..b9404f3 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1149,10 +1149,10 @@
             AccessibilityNodeInfo next = null;
             switch (gestureId) {
                 case AccessibilityService.GESTURE_SWIPE_UP: {
-                    next = current.focusSearch(View.ACCESSIBILITY_FOCUS_OUT);
+                    // TODO:
                 } break;
                 case AccessibilityService.GESTURE_SWIPE_DOWN: {
-                    next = current.focusSearch(View.ACCESSIBILITY_FOCUS_IN);
+                    // TODO:
                 } break;
                 case AccessibilityService.GESTURE_SWIPE_LEFT: {
                     // TODO: Implement the RTL support.
@@ -1694,6 +1694,7 @@
     final class SecurityPolicy {
         private static final int VALID_ACTIONS =
             AccessibilityNodeInfo.ACTION_CLICK
+            | AccessibilityNodeInfo.ACTION_LONG_CLICK
             | AccessibilityNodeInfo.ACTION_FOCUS
             | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS
             | AccessibilityNodeInfo.ACTION_SELECT
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 77bec41..6c99cdb 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4116,6 +4116,10 @@
     public void dismissKeyguardOnNextActivity() {
         enforceNotIsolatedCaller("dismissKeyguardOnNextActivity");
         synchronized (this) {
+            if (mLockScreenShown) {
+                mLockScreenShown = false;
+                comeOutOfSleepIfNeededLocked();
+            }
             mMainStack.dismissKeyguardOnNextActivityLocked();
         }
     }
@@ -5489,6 +5493,9 @@
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.GET_TASKS,
                     "getRecentTasks()");
+            final boolean detailed = checkCallingPermission(
+                    android.Manifest.permission.GET_DETAILED_TASKS)
+                    == PackageManager.PERMISSION_GRANTED;
 
             IPackageManager pm = AppGlobals.getPackageManager();
             
@@ -5517,6 +5524,9 @@
                     rti.persistentId = tr.taskId;
                     rti.baseIntent = new Intent(
                             tr.intent != null ? tr.intent : tr.affinityIntent);
+                    if (!detailed) {
+                        rti.baseIntent.replaceExtras((Bundle)null);
+                    }
                     rti.origActivity = tr.origActivity;
                     rti.description = tr.lastDescription;
                     
@@ -13398,7 +13408,8 @@
     @Override
     public boolean targetTaskAffinityMatchesActivity(IBinder token, String destAffinity) {
         ActivityRecord srec = ActivityRecord.forToken(token);
-        return srec.task.affinity != null && srec.task.affinity.equals(destAffinity);
+        return srec != null && srec.task.affinity != null &&
+                srec.task.affinity.equals(destAffinity);
     }
 
     public boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode,
@@ -13407,6 +13418,9 @@
 
         synchronized (this) {
             ActivityRecord srec = ActivityRecord.forToken(token);
+            if (srec == null) {
+                return false;
+            }
             ArrayList<ActivityRecord> history = srec.stack.mHistory;
             final int start = history.indexOf(srec);
             if (start < 0) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
old mode 100644
new mode 100755
index 24bab99..c8e015b
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1378,7 +1378,10 @@
         // If we are sleeping, and there is no resumed activity, and the top
         // activity is paused, well that is the state we want.
         if ((mService.mSleeping || mService.mShuttingDown)
-                && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
+                && mLastPausedActivity == next
+                && (next.state == ActivityState.PAUSED
+                    || next.state == ActivityState.STOPPED
+                    || next.state == ActivityState.STOPPING)) {
             // Make sure we have executed any pending transitions, since there
             // should be nothing left to do at this point.
             mService.mWindowManager.executeAppTransition();
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 52d5019..f873b6c 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1665,20 +1665,9 @@
             updateRulesForAppLocked(appId);
         }
 
-        // and catch system UIDs
-        // TODO: keep in sync with android_filesystem_config.h
-        for (int uid = 1000; uid <= 1025; uid++) {
-            updateRulesForUidLocked(uid);
-        }
-        for (int uid = 2000; uid <= 2002; uid++) {
-            updateRulesForUidLocked(uid);
-        }
-        for (int uid = 3000; uid <= 3007; uid++) {
-            updateRulesForUidLocked(uid);
-        }
-        for (int uid = 9998; uid <= 9999; uid++) {
-            updateRulesForUidLocked(uid);
-        }
+        // limit data usage for some internal system services
+        updateRulesForUidLocked(android.os.Process.MEDIA_UID);
+        updateRulesForUidLocked(android.os.Process.DRM_UID);
     }
 
     private void updateRulesForAppLocked(int appId) {
@@ -1688,7 +1677,19 @@
         }
     }
 
+    private static boolean isUidValidForRules(int uid) {
+        // allow rules on specific system services, and any apps
+        if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID
+                || UserId.isApp(uid)) {
+            return true;
+        }
+
+        return false;
+    }
+
     private void updateRulesForUidLocked(int uid) {
+        if (!isUidValidForRules(uid)) return;
+
         final int appId = UserId.getAppId(uid);
         final int appPolicy = getAppPolicy(appId);
         final boolean uidForeground = isUidForeground(uid);
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 6891b76..00d86e3 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -2737,7 +2737,7 @@
                     }
                 }
 
-                if (pi != null && !list.append(pi)) {
+                if (pi != null && list.append(pi)) {
                     break;
                 }
             }
@@ -2787,7 +2787,7 @@
                     }
                 }
 
-                if (ai != null && !list.append(ai)) {
+                if (ai != null && list.append(ai)) {
                     break;
                 }
             }
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java
index 6964137..d635e8c 100644
--- a/services/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/java/com/android/server/wm/AppWindowAnimator.java
@@ -54,7 +54,7 @@
 
     public void setAnimation(Animation anim, boolean initialized) {
         if (WindowManagerService.localLOGV) Slog.v(
-            TAG, "Setting animation in " + this + ": " + anim);
+            TAG, "Setting animation in " + mAppToken + ": " + anim);
         animation = anim;
         animating = false;
         animInitialized = initialized;
@@ -81,7 +81,7 @@
     public void setDummyAnimation() {
         if (animation == null) {
             if (WindowManagerService.localLOGV) Slog.v(
-                TAG, "Setting dummy animation in " + this);
+                TAG, "Setting dummy animation in " + mAppToken);
             animation = sDummyAnimation;
             animInitialized = false;
         }
@@ -165,12 +165,12 @@
         transformation.clear();
         final boolean more = animation.getTransformation(currentTime, transformation);
         if (WindowManagerService.DEBUG_ANIM) Slog.v(
-            TAG, "Stepped animation in " + this + ": more=" + more + ", xform=" + transformation);
+            TAG, "Stepped animation in " + mAppToken + ": more=" + more + ", xform=" + transformation);
         if (!more) {
             animation = null;
             clearThumbnail();
             if (WindowManagerService.DEBUG_ANIM) Slog.v(
-                TAG, "Finished animation in " + this + " @ " + currentTime);
+                TAG, "Finished animation in " + mAppToken + " @ " + currentTime);
         }
         hasTransformation = more;
         return more;
@@ -195,7 +195,7 @@
                     && animation != null) {
                 if (!animating) {
                     if (WindowManagerService.DEBUG_ANIM) Slog.v(
-                        TAG, "Starting animation in " + this +
+                        TAG, "Starting animation in " + mAppToken +
                         " @ " + currentTime + ": dw=" + dw + " dh=" + dh
                         + " scale=" + mService.mTransitionAnimationScale
                         + " allDrawn=" + mAppToken.allDrawn + " animating=" + animating);
@@ -248,7 +248,7 @@
         }
 
         if (WindowManagerService.DEBUG_ANIM) Slog.v(
-                TAG, "Animation done in " + this
+                TAG, "Animation done in " + mAppToken
                 + ": reportedVisible=" + mAppToken.reportedVisible);
 
         transformation.clear();
diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java
index c1dbb36..9fca4183 100644
--- a/services/java/com/android/server/wm/DimSurface.java
+++ b/services/java/com/android/server/wm/DimSurface.java
@@ -33,10 +33,17 @@
     DimSurface(SurfaceSession session) {
         if (mDimSurface == null) {
             try {
-                mDimSurface = new Surface(session, 0,
+                if (WindowManagerService.DEBUG_SURFACE_TRACE) {
+                    mDimSurface = new WindowStateAnimator.SurfaceTrace(session, 0,
                         "DimSurface",
                         -1, 16, 16, PixelFormat.OPAQUE,
                         Surface.FX_SURFACE_DIM);
+                } else {
+                    mDimSurface = new Surface(session, 0,
+                        "DimSurface",
+                        -1, 16, 16, PixelFormat.OPAQUE,
+                        Surface.FX_SURFACE_DIM);
+                }
                 if (WindowManagerService.SHOW_TRANSACTIONS ||
                         WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
                                 "  DIM " + mDimSurface + ": CREATE");
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index f1ad539..e5b1f2c 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -451,9 +451,9 @@
         Surface.openTransaction();
 
         try {
-            testWallpaperAndBackgroundLocked();
             updateWindowsAppsAndRotationAnimationsLocked();
             performAnimationsLocked();
+            testWallpaperAndBackgroundLocked();
 
             // THIRD LOOP: Update the surfaces of all windows.
 
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index defe824..32700cb 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -130,6 +130,7 @@
 import android.view.animation.Interpolator;
 import android.view.animation.ScaleAnimation;
 import android.view.animation.Transformation;
+import android.view.animation.TranslateAnimation;
 
 import java.io.BufferedWriter;
 import java.io.DataInputStream;
@@ -3129,13 +3130,13 @@
                         com.android.internal.R.integer.config_shortAnimTime);
                 break;
             default:
-                duration = 500;
+                duration = 300;
                 break;
         }
         if (enter) {
             // Entering app zooms out from the center of the initial rect.
-            float scaleW = mNextAppTransitionStartWidth/(float)mAppDisplayWidth;
-            float scaleH = mNextAppTransitionStartHeight/(float)mAppDisplayHeight;
+            float scaleW = mNextAppTransitionStartWidth / (float) mAppDisplayWidth;
+            float scaleH = mNextAppTransitionStartHeight / (float) mAppDisplayHeight;
             Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
                     computePivot(mNextAppTransitionStartX, scaleW),
                     computePivot(mNextAppTransitionStartY, scaleH));
@@ -3152,7 +3153,7 @@
         }
         a.setFillAfter(true);
         final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext,
-                com.android.internal.R.interpolator.decelerate_quad);
+                com.android.internal.R.interpolator.decelerate_cubic);
         a.setInterpolator(interpolator);
         a.initialize(mAppDisplayWidth, mAppDisplayHeight,
                 mAppDisplayWidth, mAppDisplayHeight);
@@ -3177,7 +3178,7 @@
                         com.android.internal.R.integer.config_shortAnimTime);
                 break;
             default:
-                duration = 500;
+                duration = 300;
                 break;
         }
         if (thumb) {