Merge "Fix a typo and choose a reasonable default for crypto-mode (0 would be unencrypted)"
diff --git a/api/current.txt b/api/current.txt
index fef1c83..d8387c1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1999,17 +1999,30 @@
     method protected void onGesture(int);
     method public abstract void onInterrupt();
     method protected void onServiceConnected();
+    method public final boolean performGlobalAction(int);
     method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
     field public static final int GESTURE_CLOCKWISE_CIRCLE = 9; // 0x9
     field public static final int GESTURE_COUNTER_CLOCKWISE_CIRCLE = 10; // 0xa
     field public static final int GESTURE_SWIPE_DOWN = 2; // 0x2
+    field public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 17; // 0x11
+    field public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 18; // 0x12
     field public static final int GESTURE_SWIPE_DOWN_AND_UP = 8; // 0x8
     field public static final int GESTURE_SWIPE_LEFT = 3; // 0x3
+    field public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 12; // 0xc
     field public static final int GESTURE_SWIPE_LEFT_AND_RIGHT = 5; // 0x5
+    field public static final int GESTURE_SWIPE_LEFT_AND_UP = 11; // 0xb
     field public static final int GESTURE_SWIPE_RIGHT = 4; // 0x4
+    field public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 14; // 0xe
     field public static final int GESTURE_SWIPE_RIGHT_AND_LEFT = 6; // 0x6
+    field public static final int GESTURE_SWIPE_RIGHT_AND_UP = 13; // 0xd
     field public static final int GESTURE_SWIPE_UP = 1; // 0x1
     field public static final int GESTURE_SWIPE_UP_AND_DOWN = 7; // 0x7
+    field public static final int GESTURE_SWIPE_UP_AND_LEFT = 15; // 0xf
+    field public static final int GESTURE_SWIPE_UP_AND_RIGHT = 16; // 0x10
+    field public static final int GLOBAL_ACTION_BACK = 1; // 0x1
+    field public static final int GLOBAL_ACTION_HOME = 2; // 0x2
+    field public static final int GLOBAL_ACTION_NOTIFICATIONS = 4; // 0x4
+    field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3
     field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
     field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
   }
@@ -25006,12 +25019,13 @@
     method public void setSource(android.view.View, int);
     method public void setText(java.lang.CharSequence);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final int ACTION_ACCESSIBILITY_FOCUS = 16; // 0x10
-    field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 32; // 0x20
+    field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+    field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
     field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
     field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
-    field public static final int ACTION_CLICK = 64; // 0x40
+    field public static final int ACTION_CLICK = 16; // 0x10
     field public static final int ACTION_FOCUS = 1; // 0x1
+    field public static final int ACTION_LONG_CLICK = 32; // 0x20
     field public static final int ACTION_SELECT = 4; // 0x4
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 3da35d3..eed8aa6 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -259,13 +259,51 @@
     public static final int GESTURE_COUNTER_CLOCKWISE_CIRCLE = 10;
 
     /**
+     * The user has performed a left and up gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_LEFT_AND_UP = 11;
+
+    /**
+     * The user has performed a left and down gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 12;
+
+    /**
+     * The user has performed a right and up gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_RIGHT_AND_UP = 13;
+
+    /**
+     * The user has performed a right and down gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 14;
+
+    /**
+     * The user has performed an up and left gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_UP_AND_LEFT = 15;
+
+    /**
+     * The user has performed an up and right gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_UP_AND_RIGHT = 16;
+
+    /**
+     * The user has performed an down and left gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 17;
+
+    /**
+     * The user has performed an down and right gesture on the touch screen.
+     */
+    public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 18;
+
+    /**
      * The {@link Intent} that must be declared as handled by the service.
      */
     public static final String SERVICE_INTERFACE =
         "android.accessibilityservice.AccessibilityService";
 
-    private static final int UNDEFINED = -1;
-
     /**
      * Name under which an AccessibilityService component publishes information
      * about itself. This meta-data must reference an XML resource containing an
@@ -284,6 +322,28 @@
      */
     public static final String SERVICE_META_DATA = "android.accessibilityservice";
 
+    /**
+     * Action to go back.
+     */
+    public static final int GLOBAL_ACTION_BACK = 1;
+
+    /**
+     * Action to go home.
+     */
+    public static final int GLOBAL_ACTION_HOME = 2;
+
+    /**
+     * Action to open the recents.
+     */
+    public static final int GLOBAL_ACTION_RECENTS = 3;
+
+    /**
+     * Action to open the notifications.
+     */
+    public static final int GLOBAL_ACTION_NOTIFICATIONS = 4;
+
+    private static final int UNDEFINED = -1;
+
     private static final String LOG_TAG = "AccessibilityService";
 
     interface Callbacks {
@@ -344,6 +404,22 @@
     protected void onGesture(int gestureId) {
         // TODO: Describe the default gesture processing in the javaDoc once it is finalized.
 
+        // Global actions.
+        switch (gestureId) {
+            case GESTURE_SWIPE_DOWN_AND_LEFT: {
+                performGlobalAction(GLOBAL_ACTION_BACK);
+            } return;
+            case GESTURE_SWIPE_DOWN_AND_RIGHT: {
+                performGlobalAction(GLOBAL_ACTION_HOME);
+            } return;
+            case GESTURE_SWIPE_UP_AND_LEFT: {
+                performGlobalAction(GLOBAL_ACTION_RECENTS);
+            } return;
+            case GESTURE_SWIPE_UP_AND_RIGHT: {
+                performGlobalAction(GLOBAL_ACTION_NOTIFICATIONS);
+            } return;
+        }
+
         // Cache the id to avoid locking
         final int connectionId = mConnectionId;
         if (connectionId == UNDEFINED) {
@@ -357,10 +433,12 @@
         if (root == null) {
             return;
         }
-        AccessibilityNodeInfo current = root.findFocus(View.FOCUS_ACCESSIBILITY);
+        AccessibilityNodeInfo current = root.findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
         if (current == null) {
             current = root;
         }
+
+        // Local actions.
         AccessibilityNodeInfo next = null;
         switch (gestureId) {
             case GESTURE_SWIPE_UP: {
@@ -402,6 +480,33 @@
     }
 
     /**
+     * Performs a global action. Such an action can be performed
+     * at any moment regardless of the current application or user
+     * location in that application. For example going back, going
+     * home, opening recents, etc.
+     *
+     * @param action The action to perform.
+     * @return Whether the action was successfully performed.
+     *
+     * @see #GLOBAL_ACTION_BACK
+     * @see #GLOBAL_ACTION_HOME
+     * @see #GLOBAL_ACTION_NOTIFICATIONS
+     * @see #GLOBAL_ACTION_RECENTS
+     */
+    public final boolean performGlobalAction(int action) {
+        IAccessibilityServiceConnection connection =
+            AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
+        if (connection != null) {
+            try {
+                return connection.perfromGlobalAction(action);
+            } catch (RemoteException re) {
+                Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
+            }
+        }
+        return false;
+    }
+
+    /**
      * Gets the an {@link AccessibilityServiceInfo} describing this
      * {@link AccessibilityService}. This method is useful if one wants
      * to change some of the dynamically configurable properties at
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 30da9db..1bd5387 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -160,4 +160,12 @@
      * @return The associated accessibility service info.
      */
     AccessibilityServiceInfo getServiceInfo();
+
+    /**
+     * Performs a global action, such as going home, going back, etc.
+     *
+     * @param action The action to perform.
+     * @return Whether the action was performed.
+     */
+    boolean perfromGlobalAction(int action);
 }
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 6c1a6bf..54c62ee 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -52,13 +52,16 @@
     private ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList =
         new ArrayList<AccessibilityNodeInfo>();
 
-    private final Handler mHandler = new PrivateHandler();
+    private final Handler mHandler;
 
     private final ViewRootImpl mViewRootImpl;
 
     private final AccessibilityNodePrefetcher mPrefetcher;
 
     public AccessibilityInteractionController(ViewRootImpl viewRootImpl) {
+        // mView is never null - the caller has already checked.
+        Looper looper = viewRootImpl.mView.mContext.getMainLooper();
+        mHandler = new PrivateHandler(looper);
         mViewRootImpl = viewRootImpl;
         mPrefetcher = new AccessibilityNodePrefetcher();
     }
@@ -846,8 +849,8 @@
         private final static int MSG_FIND_FOCUS = 5;
         private final static int MSG_FOCUS_SEARCH = 6;
 
-        public PrivateHandler() {
-            super(Looper.getMainLooper());
+        public PrivateHandler(Looper looper) {
+            super(looper);
         }
 
         @Override
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index 12d7b12..d8d5185 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -135,6 +135,163 @@
      */
     public static final int MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED = 1;
 
+    /*
+     * This bit will be set in the return value of {@link #get(int, int)} if the
+     * key is a "dead key."
+     */
+    public static final int COMBINING_ACCENT = 0x80000000;
+
+    /**
+     * Mask the return value from {@link #get(int, int)} with this value to get
+     * a printable representation of the accent character of a "dead key."
+     */
+    public static final int COMBINING_ACCENT_MASK = 0x7FFFFFFF;
+
+    /* Characters used to display placeholders for dead keys. */
+    private static final int ACCENT_ACUTE = '\u00B4';
+    private static final int ACCENT_GRAVE = '\u02CB';
+    private static final int ACCENT_CIRCUMFLEX = '\u02C6';
+    private static final int ACCENT_TILDE = '\u02DC';
+    private static final int ACCENT_UMLAUT = '\u00A8';
+
+    /* Legacy dead key display characters used in previous versions of the API.
+     * We still support these characters by mapping them to their non-legacy version. */
+    private static final int ACCENT_GRAVE_LEGACY = '`';
+    private static final int ACCENT_CIRCUMFLEX_LEGACY = '^';
+    private static final int ACCENT_TILDE_LEGACY = '~';
+
+    /**
+     * Maps Unicode combining diacritical to display-form dead key
+     * (display character shifted left 16 bits).
+     */
+    private static final SparseIntArray COMBINING = new SparseIntArray();
+    static {
+        COMBINING.put('\u0300', ACCENT_GRAVE);
+        COMBINING.put('\u0301', ACCENT_ACUTE);
+        COMBINING.put('\u0302', ACCENT_CIRCUMFLEX);
+        COMBINING.put('\u0303', ACCENT_TILDE);
+        COMBINING.put('\u0308', ACCENT_UMLAUT);
+    }
+
+    /**
+     * Maps combinations of (display-form) dead key and second character
+     * to combined output character.
+     */
+    private static final SparseIntArray DEAD = new SparseIntArray();
+    static {
+        addDeadChar(ACCENT_ACUTE, 'A', '\u00C1');
+        addDeadChar(ACCENT_ACUTE, 'C', '\u0106');
+        addDeadChar(ACCENT_ACUTE, 'E', '\u00C9');
+        addDeadChar(ACCENT_ACUTE, 'G', '\u01F4');
+        addDeadChar(ACCENT_ACUTE, 'I', '\u00CD');
+        addDeadChar(ACCENT_ACUTE, 'K', '\u1E30');
+        addDeadChar(ACCENT_ACUTE, 'L', '\u0139');
+        addDeadChar(ACCENT_ACUTE, 'M', '\u1E3E');
+        addDeadChar(ACCENT_ACUTE, 'N', '\u0143');
+        addDeadChar(ACCENT_ACUTE, 'O', '\u00D3');
+        addDeadChar(ACCENT_ACUTE, 'P', '\u1E54');
+        addDeadChar(ACCENT_ACUTE, 'R', '\u0154');
+        addDeadChar(ACCENT_ACUTE, 'S', '\u015A');
+        addDeadChar(ACCENT_ACUTE, 'U', '\u00DA');
+        addDeadChar(ACCENT_ACUTE, 'W', '\u1E82');
+        addDeadChar(ACCENT_ACUTE, 'Y', '\u00DD');
+        addDeadChar(ACCENT_ACUTE, 'Z', '\u0179');
+        addDeadChar(ACCENT_ACUTE, 'a', '\u00E1');
+        addDeadChar(ACCENT_ACUTE, 'c', '\u0107');
+        addDeadChar(ACCENT_ACUTE, 'e', '\u00E9');
+        addDeadChar(ACCENT_ACUTE, 'g', '\u01F5');
+        addDeadChar(ACCENT_ACUTE, 'i', '\u00ED');
+        addDeadChar(ACCENT_ACUTE, 'k', '\u1E31');
+        addDeadChar(ACCENT_ACUTE, 'l', '\u013A');
+        addDeadChar(ACCENT_ACUTE, 'm', '\u1E3F');
+        addDeadChar(ACCENT_ACUTE, 'n', '\u0144');
+        addDeadChar(ACCENT_ACUTE, 'o', '\u00F3');
+        addDeadChar(ACCENT_ACUTE, 'p', '\u1E55');
+        addDeadChar(ACCENT_ACUTE, 'r', '\u0155');
+        addDeadChar(ACCENT_ACUTE, 's', '\u015B');
+        addDeadChar(ACCENT_ACUTE, 'u', '\u00FA');
+        addDeadChar(ACCENT_ACUTE, 'w', '\u1E83');
+        addDeadChar(ACCENT_ACUTE, 'y', '\u00FD');
+        addDeadChar(ACCENT_ACUTE, 'z', '\u017A');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'A', '\u00C2');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'C', '\u0108');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'E', '\u00CA');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'G', '\u011C');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'H', '\u0124');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'I', '\u00CE');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'J', '\u0134');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'O', '\u00D4');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'S', '\u015C');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'U', '\u00DB');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'W', '\u0174');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'Y', '\u0176');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'Z', '\u1E90');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'a', '\u00E2');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'c', '\u0109');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'e', '\u00EA');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'g', '\u011D');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'h', '\u0125');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'i', '\u00EE');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'j', '\u0135');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'o', '\u00F4');
+        addDeadChar(ACCENT_CIRCUMFLEX, 's', '\u015D');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'u', '\u00FB');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'w', '\u0175');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'y', '\u0177');
+        addDeadChar(ACCENT_CIRCUMFLEX, 'z', '\u1E91');
+        addDeadChar(ACCENT_GRAVE, 'A', '\u00C0');
+        addDeadChar(ACCENT_GRAVE, 'E', '\u00C8');
+        addDeadChar(ACCENT_GRAVE, 'I', '\u00CC');
+        addDeadChar(ACCENT_GRAVE, 'N', '\u01F8');
+        addDeadChar(ACCENT_GRAVE, 'O', '\u00D2');
+        addDeadChar(ACCENT_GRAVE, 'U', '\u00D9');
+        addDeadChar(ACCENT_GRAVE, 'W', '\u1E80');
+        addDeadChar(ACCENT_GRAVE, 'Y', '\u1EF2');
+        addDeadChar(ACCENT_GRAVE, 'a', '\u00E0');
+        addDeadChar(ACCENT_GRAVE, 'e', '\u00E8');
+        addDeadChar(ACCENT_GRAVE, 'i', '\u00EC');
+        addDeadChar(ACCENT_GRAVE, 'n', '\u01F9');
+        addDeadChar(ACCENT_GRAVE, 'o', '\u00F2');
+        addDeadChar(ACCENT_GRAVE, 'u', '\u00F9');
+        addDeadChar(ACCENT_GRAVE, 'w', '\u1E81');
+        addDeadChar(ACCENT_GRAVE, 'y', '\u1EF3');
+        addDeadChar(ACCENT_TILDE, 'A', '\u00C3');
+        addDeadChar(ACCENT_TILDE, 'E', '\u1EBC');
+        addDeadChar(ACCENT_TILDE, 'I', '\u0128');
+        addDeadChar(ACCENT_TILDE, 'N', '\u00D1');
+        addDeadChar(ACCENT_TILDE, 'O', '\u00D5');
+        addDeadChar(ACCENT_TILDE, 'U', '\u0168');
+        addDeadChar(ACCENT_TILDE, 'V', '\u1E7C');
+        addDeadChar(ACCENT_TILDE, 'Y', '\u1EF8');
+        addDeadChar(ACCENT_TILDE, 'a', '\u00E3');
+        addDeadChar(ACCENT_TILDE, 'e', '\u1EBD');
+        addDeadChar(ACCENT_TILDE, 'i', '\u0129');
+        addDeadChar(ACCENT_TILDE, 'n', '\u00F1');
+        addDeadChar(ACCENT_TILDE, 'o', '\u00F5');
+        addDeadChar(ACCENT_TILDE, 'u', '\u0169');
+        addDeadChar(ACCENT_TILDE, 'v', '\u1E7D');
+        addDeadChar(ACCENT_TILDE, 'y', '\u1EF9');
+        addDeadChar(ACCENT_UMLAUT, 'A', '\u00C4');
+        addDeadChar(ACCENT_UMLAUT, 'E', '\u00CB');
+        addDeadChar(ACCENT_UMLAUT, 'H', '\u1E26');
+        addDeadChar(ACCENT_UMLAUT, 'I', '\u00CF');
+        addDeadChar(ACCENT_UMLAUT, 'O', '\u00D6');
+        addDeadChar(ACCENT_UMLAUT, 'U', '\u00DC');
+        addDeadChar(ACCENT_UMLAUT, 'W', '\u1E84');
+        addDeadChar(ACCENT_UMLAUT, 'X', '\u1E8C');
+        addDeadChar(ACCENT_UMLAUT, 'Y', '\u0178');
+        addDeadChar(ACCENT_UMLAUT, 'a', '\u00E4');
+        addDeadChar(ACCENT_UMLAUT, 'e', '\u00EB');
+        addDeadChar(ACCENT_UMLAUT, 'h', '\u1E27');
+        addDeadChar(ACCENT_UMLAUT, 'i', '\u00EF');
+        addDeadChar(ACCENT_UMLAUT, 'o', '\u00F6');
+        addDeadChar(ACCENT_UMLAUT, 't', '\u1E97');
+        addDeadChar(ACCENT_UMLAUT, 'u', '\u00FC');
+        addDeadChar(ACCENT_UMLAUT, 'w', '\u1E85');
+        addDeadChar(ACCENT_UMLAUT, 'x', '\u1E8D');
+        addDeadChar(ACCENT_UMLAUT, 'y', '\u00FF');
+    }
+
     public static final Parcelable.Creator<KeyCharacterMap> CREATOR =
             new Parcelable.Creator<KeyCharacterMap>() {
         public KeyCharacterMap createFromParcel(Parcel in) {
@@ -232,7 +389,7 @@
 
         int map = COMBINING.get(ch);
         if (map != 0) {
-            return map;
+            return map | COMBINING_ACCENT;
         } else {
             return ch;
         }
@@ -346,6 +503,13 @@
      * @return The combined character, or 0 if the characters cannot be combined.
      */
     public static int getDeadChar(int accent, int c) {
+        if (accent == ACCENT_CIRCUMFLEX_LEGACY) {
+            accent = ACCENT_CIRCUMFLEX;
+        } else if (accent == ACCENT_GRAVE_LEGACY) {
+            accent = ACCENT_GRAVE;
+        } else if (accent == ACCENT_TILDE_LEGACY) {
+            accent = ACCENT_TILDE;
+        }
         return DEAD.get((accent << 16) | c);
     }
 
@@ -559,157 +723,8 @@
         return 0;
     }
 
-    /**
-     * Maps Unicode combining diacritical to display-form dead key
-     * (display character shifted left 16 bits).
-     */
-    private static SparseIntArray COMBINING = new SparseIntArray();
-
-    /**
-     * Maps combinations of (display-form) dead key and second character
-     * to combined output character.
-     */
-    private static SparseIntArray DEAD = new SparseIntArray();
-
-    /*
-     * TODO: Change the table format to support full 21-bit-wide
-     * accent characters and combined characters if ever necessary.
-     */
-    private static final int ACUTE = '\u00B4' << 16;
-    private static final int GRAVE = '`' << 16;
-    private static final int CIRCUMFLEX = '^' << 16;
-    private static final int TILDE = '~' << 16;
-    private static final int UMLAUT = '\u00A8' << 16;
-
-    /*
-     * This bit will be set in the return value of {@link #get(int, int)} if the
-     * key is a "dead key."
-     */
-    public static final int COMBINING_ACCENT = 0x80000000;
-    /**
-     * Mask the return value from {@link #get(int, int)} with this value to get
-     * a printable representation of the accent character of a "dead key."
-     */
-    public static final int COMBINING_ACCENT_MASK = 0x7FFFFFFF;
-
-    static {
-        COMBINING.put('\u0300', (GRAVE >> 16) | COMBINING_ACCENT);
-        COMBINING.put('\u0301', (ACUTE >> 16) | COMBINING_ACCENT);
-        COMBINING.put('\u0302', (CIRCUMFLEX >> 16) | COMBINING_ACCENT);
-        COMBINING.put('\u0303', (TILDE >> 16) | COMBINING_ACCENT);
-        COMBINING.put('\u0308', (UMLAUT >> 16) | COMBINING_ACCENT);
-
-        DEAD.put(ACUTE | 'A', '\u00C1');
-        DEAD.put(ACUTE | 'C', '\u0106');
-        DEAD.put(ACUTE | 'E', '\u00C9');
-        DEAD.put(ACUTE | 'G', '\u01F4');
-        DEAD.put(ACUTE | 'I', '\u00CD');
-        DEAD.put(ACUTE | 'K', '\u1E30');
-        DEAD.put(ACUTE | 'L', '\u0139');
-        DEAD.put(ACUTE | 'M', '\u1E3E');
-        DEAD.put(ACUTE | 'N', '\u0143');
-        DEAD.put(ACUTE | 'O', '\u00D3');
-        DEAD.put(ACUTE | 'P', '\u1E54');
-        DEAD.put(ACUTE | 'R', '\u0154');
-        DEAD.put(ACUTE | 'S', '\u015A');
-        DEAD.put(ACUTE | 'U', '\u00DA');
-        DEAD.put(ACUTE | 'W', '\u1E82');
-        DEAD.put(ACUTE | 'Y', '\u00DD');
-        DEAD.put(ACUTE | 'Z', '\u0179');
-        DEAD.put(ACUTE | 'a', '\u00E1');
-        DEAD.put(ACUTE | 'c', '\u0107');
-        DEAD.put(ACUTE | 'e', '\u00E9');
-        DEAD.put(ACUTE | 'g', '\u01F5');
-        DEAD.put(ACUTE | 'i', '\u00ED');
-        DEAD.put(ACUTE | 'k', '\u1E31');
-        DEAD.put(ACUTE | 'l', '\u013A');
-        DEAD.put(ACUTE | 'm', '\u1E3F');
-        DEAD.put(ACUTE | 'n', '\u0144');
-        DEAD.put(ACUTE | 'o', '\u00F3');
-        DEAD.put(ACUTE | 'p', '\u1E55');
-        DEAD.put(ACUTE | 'r', '\u0155');
-        DEAD.put(ACUTE | 's', '\u015B');
-        DEAD.put(ACUTE | 'u', '\u00FA');
-        DEAD.put(ACUTE | 'w', '\u1E83');
-        DEAD.put(ACUTE | 'y', '\u00FD');
-        DEAD.put(ACUTE | 'z', '\u017A');
-        DEAD.put(CIRCUMFLEX | 'A', '\u00C2');
-        DEAD.put(CIRCUMFLEX | 'C', '\u0108');
-        DEAD.put(CIRCUMFLEX | 'E', '\u00CA');
-        DEAD.put(CIRCUMFLEX | 'G', '\u011C');
-        DEAD.put(CIRCUMFLEX | 'H', '\u0124');
-        DEAD.put(CIRCUMFLEX | 'I', '\u00CE');
-        DEAD.put(CIRCUMFLEX | 'J', '\u0134');
-        DEAD.put(CIRCUMFLEX | 'O', '\u00D4');
-        DEAD.put(CIRCUMFLEX | 'S', '\u015C');
-        DEAD.put(CIRCUMFLEX | 'U', '\u00DB');
-        DEAD.put(CIRCUMFLEX | 'W', '\u0174');
-        DEAD.put(CIRCUMFLEX | 'Y', '\u0176');
-        DEAD.put(CIRCUMFLEX | 'Z', '\u1E90');
-        DEAD.put(CIRCUMFLEX | 'a', '\u00E2');
-        DEAD.put(CIRCUMFLEX | 'c', '\u0109');
-        DEAD.put(CIRCUMFLEX | 'e', '\u00EA');
-        DEAD.put(CIRCUMFLEX | 'g', '\u011D');
-        DEAD.put(CIRCUMFLEX | 'h', '\u0125');
-        DEAD.put(CIRCUMFLEX | 'i', '\u00EE');
-        DEAD.put(CIRCUMFLEX | 'j', '\u0135');
-        DEAD.put(CIRCUMFLEX | 'o', '\u00F4');
-        DEAD.put(CIRCUMFLEX | 's', '\u015D');
-        DEAD.put(CIRCUMFLEX | 'u', '\u00FB');
-        DEAD.put(CIRCUMFLEX | 'w', '\u0175');
-        DEAD.put(CIRCUMFLEX | 'y', '\u0177');
-        DEAD.put(CIRCUMFLEX | 'z', '\u1E91');
-        DEAD.put(GRAVE | 'A', '\u00C0');
-        DEAD.put(GRAVE | 'E', '\u00C8');
-        DEAD.put(GRAVE | 'I', '\u00CC');
-        DEAD.put(GRAVE | 'N', '\u01F8');
-        DEAD.put(GRAVE | 'O', '\u00D2');
-        DEAD.put(GRAVE | 'U', '\u00D9');
-        DEAD.put(GRAVE | 'W', '\u1E80');
-        DEAD.put(GRAVE | 'Y', '\u1EF2');
-        DEAD.put(GRAVE | 'a', '\u00E0');
-        DEAD.put(GRAVE | 'e', '\u00E8');
-        DEAD.put(GRAVE | 'i', '\u00EC');
-        DEAD.put(GRAVE | 'n', '\u01F9');
-        DEAD.put(GRAVE | 'o', '\u00F2');
-        DEAD.put(GRAVE | 'u', '\u00F9');
-        DEAD.put(GRAVE | 'w', '\u1E81');
-        DEAD.put(GRAVE | 'y', '\u1EF3');
-        DEAD.put(TILDE | 'A', '\u00C3');
-        DEAD.put(TILDE | 'E', '\u1EBC');
-        DEAD.put(TILDE | 'I', '\u0128');
-        DEAD.put(TILDE | 'N', '\u00D1');
-        DEAD.put(TILDE | 'O', '\u00D5');
-        DEAD.put(TILDE | 'U', '\u0168');
-        DEAD.put(TILDE | 'V', '\u1E7C');
-        DEAD.put(TILDE | 'Y', '\u1EF8');
-        DEAD.put(TILDE | 'a', '\u00E3');
-        DEAD.put(TILDE | 'e', '\u1EBD');
-        DEAD.put(TILDE | 'i', '\u0129');
-        DEAD.put(TILDE | 'n', '\u00F1');
-        DEAD.put(TILDE | 'o', '\u00F5');
-        DEAD.put(TILDE | 'u', '\u0169');
-        DEAD.put(TILDE | 'v', '\u1E7D');
-        DEAD.put(TILDE | 'y', '\u1EF9');
-        DEAD.put(UMLAUT | 'A', '\u00C4');
-        DEAD.put(UMLAUT | 'E', '\u00CB');
-        DEAD.put(UMLAUT | 'H', '\u1E26');
-        DEAD.put(UMLAUT | 'I', '\u00CF');
-        DEAD.put(UMLAUT | 'O', '\u00D6');
-        DEAD.put(UMLAUT | 'U', '\u00DC');
-        DEAD.put(UMLAUT | 'W', '\u1E84');
-        DEAD.put(UMLAUT | 'X', '\u1E8C');
-        DEAD.put(UMLAUT | 'Y', '\u0178');
-        DEAD.put(UMLAUT | 'a', '\u00E4');
-        DEAD.put(UMLAUT | 'e', '\u00EB');
-        DEAD.put(UMLAUT | 'h', '\u1E27');
-        DEAD.put(UMLAUT | 'i', '\u00EF');
-        DEAD.put(UMLAUT | 'o', '\u00F6');
-        DEAD.put(UMLAUT | 't', '\u1E97');
-        DEAD.put(UMLAUT | 'u', '\u00FC');
-        DEAD.put(UMLAUT | 'w', '\u1E85');
-        DEAD.put(UMLAUT | 'x', '\u1E8D');
-        DEAD.put(UMLAUT | 'y', '\u00FF');
+    private static void addDeadChar(int accent, int c, char combinedResult) {
+        DEAD.put((accent << 16) | c, combinedResult);
     }
 
     /**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0ded5f9..2fea8ec 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6359,16 +6359,14 @@
     public boolean performAccessibilityAction(int action) {
         switch (action) {
             case AccessibilityNodeInfo.ACTION_CLICK: {
-                final long now = SystemClock.uptimeMillis();
-                // Send down.
-                MotionEvent event = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
-                        getWidth() / 2, getHeight() / 2, 0);
-                onTouchEvent(event);
-                // Send up.
-                event.setAction(MotionEvent.ACTION_UP);
-                onTouchEvent(event);
-                // Clean up.
-                event.recycle();
+                if (isClickable()) {
+                    performClick();
+                }
+            } break;
+            case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
+                if (isLongClickable()) {
+                    performLongClick();
+                }
             } break;
             case AccessibilityNodeInfo.ACTION_FOCUS: {
                 if (!hasFocus()) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 6371963..91e945b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5792,11 +5792,13 @@
                 throw new IllegalStateException("Instance already recycled.");
             }
             clear();
-            if (sPoolSize < MAX_POOL_SIZE) {
-                mNext = sPool;
-                mIsPooled = true;
-                sPool = this;
-                sPoolSize++;
+            synchronized (sPoolLock) {
+                if (sPoolSize < MAX_POOL_SIZE) {
+                    mNext = sPool;
+                    mIsPooled = true;
+                    sPool = this;
+                    sPoolSize++;
+                }
             }
         }
 
@@ -5889,11 +5891,13 @@
                 throw new IllegalStateException("Instance already recycled.");
             }
             clear();
-            if (sPoolSize < MAX_POOL_SIZE) {
-                mNext = sPool;
-                mIsPooled = true;
-                sPool = this;
-                sPoolSize++;
+            synchronized (sPoolLock) {
+                if (sPoolSize < MAX_POOL_SIZE) {
+                    mNext = sPool;
+                    mIsPooled = true;
+                    sPool = this;
+                    sPoolSize++;
+                }
             }
         }
 
@@ -5943,9 +5947,9 @@
             if (widthDiference != 0) {
                 return -widthDiference;
             }
-            // Return nondeterministically one of them since we do
-            // not want to ignore any views.
-            return 1;
+            // Just break the tie somehow. The accessibliity ids are unique
+            // and stable, hence this is deterministic tie breaking.
+            return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
         }
 
         private void init(ViewGroup root, View view) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1472993..3d40b2f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2665,6 +2665,7 @@
     private final static int MSG_PROCESS_INPUT_EVENTS = 19;
     private final static int MSG_DISPATCH_SCREEN_STATE = 20;
     private final static int MSG_INVALIDATE_DISPLAY_LIST = 21;
+    private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 22;
 
     final class ViewRootHandler extends Handler {
         @Override
@@ -2712,6 +2713,8 @@
                     return "MSG_DISPATCH_SCREEN_STATE";
                 case MSG_INVALIDATE_DISPLAY_LIST:
                     return "MSG_INVALIDATE_DISPLAY_LIST";
+                case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
+                    return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
             }
             return super.getMessageName(message);
         }
@@ -2921,6 +2924,9 @@
             case MSG_INVALIDATE_DISPLAY_LIST: {
                 invalidateDisplayLists();
             } break;
+            case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
+                setAccessibilityFocusedHost(null);
+            } break;
             }
         }
     }
@@ -5066,7 +5072,7 @@
                 }
             } else {
                 ensureNoConnection();
-                setAccessibilityFocusedHost(null);
+                mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
             }
         }
 
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 1071c65..c5f2062 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -84,7 +84,7 @@
     /**
      * Action that gives input focus to the node.
      */
-    public static final int ACTION_FOCUS = 0x00000001;
+    public static final int ACTION_FOCUS =  0x00000001;
 
     /**
      * Action that clears input focus of the node.
@@ -102,19 +102,24 @@
     public static final int ACTION_CLEAR_SELECTION = 0x00000008;
 
     /**
+     * Action that clicks on the node info.
+     */
+    public static final int ACTION_CLICK = 0x00000010;
+
+    /**
+     * Action that clicks on the node.
+     */
+    public static final int ACTION_LONG_CLICK = 0x00000020;
+
+    /**
      * Action that gives accessibility focus to the node.
      */
-    public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000010;
+    public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040;
 
     /**
      * Action that clears accessibility focus of the node.
      */
-    public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000020;
-
-    /**
-     * Action that clicks on the node info./AccessibilityNodeInfoCache.java
-     */
-    public static final int ACTION_CLICK = 0x00000040;
+    public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080;
 
     /**
      * The input focus.
@@ -278,9 +283,9 @@
             (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
         mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
     }
-    
+
     /**
-     * Find the view that has the input focus. The search starts from
+     * Find the view that has the specified focus type. The search starts from
      * the view represented by this node info.
      *
      * @param focus The focus to find. One of {@link #FOCUS_INPUT} or
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 9fbc477..a46714e 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -279,7 +279,7 @@
             format,// word length, PCM
             nativeChannelMask,
             frameCount,
-            AUDIO_POLICY_OUTPUT_FLAG_NONE,
+            AUDIO_OUTPUT_FLAG_NONE,
             audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
             0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
             0,// shared mem
@@ -300,7 +300,7 @@
             format,// word length, PCM
             nativeChannelMask,
             frameCount,
-            AUDIO_POLICY_OUTPUT_FLAG_NONE,
+            AUDIO_OUTPUT_FLAG_NONE,
             audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
             0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
             lpJniStorage->mMemBase,// shared mem
diff --git a/core/res/res/raw/accessibility_gestures.bin b/core/res/res/raw/accessibility_gestures.bin
index 1f95e56..f7e6615 100644
--- a/core/res/res/raw/accessibility_gestures.bin
+++ b/core/res/res/raw/accessibility_gestures.bin
Binary files differ
diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm
index b5f6897..544076f 100644
--- a/data/keyboards/Generic.kcm
+++ b/data/keyboards/Generic.kcm
@@ -28,14 +28,12 @@
     label:                              'A'
     base:                               'a'
     shift, capslock:                    'A'
-    ctrl, alt, meta:                    none
 }
 
 key B {
     label:                              'B'
     base:                               'b'
     shift, capslock:                    'B'
-    ctrl, alt, meta:                    none
 }
 
 key C {
@@ -44,14 +42,12 @@
     shift, capslock:                    'C'
     alt:                                '\u00e7'
     shift+alt:                          '\u00c7'
-    ctrl, meta:                         none
 }
 
 key D {
     label:                              'D'
     base:                               'd'
     shift, capslock:                    'D'
-    ctrl, alt, meta:                    none
 }
 
 key E {
@@ -59,28 +55,24 @@
     base:                               'e'
     shift, capslock:                    'E'
     alt:                                '\u0301'
-    ctrl, meta:                         none
 }
 
 key F {
     label:                              'F'
     base:                               'f'
     shift, capslock:                    'F'
-    ctrl, alt, meta:                    none
 }
 
 key G {
     label:                              'G'
     base:                               'g'
     shift, capslock:                    'G'
-    ctrl, alt, meta:                    none
 }
 
 key H {
     label:                              'H'
     base:                               'h'
     shift, capslock:                    'H'
-    ctrl, alt, meta:                    none
 }
 
 key I {
@@ -88,35 +80,30 @@
     base:                               'i'
     shift, capslock:                    'I'
     alt:                                '\u0302'
-    ctrl, meta:                         none
 }
 
 key J {
     label:                              'J'
     base:                               'j'
     shift, capslock:                    'J'
-    ctrl, alt, meta:                    none
 }
 
 key K {
     label:                              'K'
     base:                               'k'
     shift, capslock:                    'K'
-    ctrl, alt, meta:                    none
 }
 
 key L {
     label:                              'L'
     base:                               'l'
     shift, capslock:                    'L'
-    ctrl, alt, meta:                    none
 }
 
 key M {
     label:                              'M'
     base:                               'm'
     shift, capslock:                    'M'
-    ctrl, alt, meta:                    none
 }
 
 key N {
@@ -124,35 +111,30 @@
     base:                               'n'
     shift, capslock:                    'N'
     alt:                                '\u0303'
-    ctrl, meta:                         none
 }
 
 key O {
     label:                              'O'
     base:                               'o'
     shift, capslock:                    'O'
-    ctrl, alt, meta:                    none
 }
 
 key P {
     label:                              'P'
     base:                               'p'
     shift, capslock:                    'P'
-    ctrl, alt, meta:                    none
 }
 
 key Q {
     label:                              'Q'
     base:                               'q'
     shift, capslock:                    'Q'
-    ctrl, alt, meta:                    none
 }
 
 key R {
     label:                              'R'
     base:                               'r'
     shift, capslock:                    'R'
-    ctrl, alt, meta:                    none
 }
 
 key S {
@@ -160,14 +142,12 @@
     base:                               's'
     shift, capslock:                    'S'
     alt:                                '\u00df'
-    ctrl, meta:                         none
 }
 
 key T {
     label:                              'T'
     base:                               't'
     shift, capslock:                    'T'
-    ctrl, alt, meta:                    none
 }
 
 key U {
@@ -175,338 +155,289 @@
     base:                               'u'
     shift, capslock:                    'U'
     alt:                                '\u0308'
-    ctrl, meta:                         none
 }
 
 key V {
     label:                              'V'
     base:                               'v'
     shift, capslock:                    'V'
-    ctrl, alt, meta:                    none
 }
 
 key W {
     label:                              'W'
     base:                               'w'
     shift, capslock:                    'W'
-    ctrl, alt, meta:                    none
 }
 
 key X {
     label:                              'X'
     base:                               'x'
     shift, capslock:                    'X'
-    ctrl, alt, meta:                    none
 }
 
 key Y {
     label:                              'Y'
     base:                               'y'
     shift, capslock:                    'Y'
-    ctrl, alt, meta:                    none
 }
 
 key Z {
     label:                              'Z'
     base:                               'z'
     shift, capslock:                    'Z'
-    ctrl, alt, meta:                    none
 }
 
 key 0 {
-    label, number:                      '0'
+    label:                              '0'
     base:                               '0'
     shift:                              ')'
-    ctrl, alt, meta:                    none
 }
 
 key 1 {
-    label, number:                      '1'
+    label:                              '1'
     base:                               '1'
     shift:                              '!'
-    ctrl, alt, meta:                    none
 }
 
 key 2 {
-    label, number:                      '2'
+    label:                              '2'
     base:                               '2'
     shift:                              '@'
-    ctrl, alt, meta:                    none
 }
 
 key 3 {
-    label, number:                      '3'
+    label:                              '3'
     base:                               '3'
     shift:                              '#'
-    ctrl, alt, meta:                    none
 }
 
 key 4 {
-    label, number:                      '4'
+    label:                              '4'
     base:                               '4'
     shift:                              '$'
-    ctrl, alt, meta:                    none
 }
 
 key 5 {
-    label, number:                      '5'
+    label:                              '5'
     base:                               '5'
     shift:                              '%'
-    ctrl, alt, meta:                    none
 }
 
 key 6 {
-    label, number:                      '6'
+    label:                              '6'
     base:                               '6'
     shift:                              '^'
-    ctrl, alt, meta:                    none
     alt+shift:                          '\u0302'
 }
 
 key 7 {
-    label, number:                      '7'
+    label:                              '7'
     base:                               '7'
     shift:                              '&'
-    ctrl, alt, meta:                    none
 }
 
 key 8 {
-    label, number:                      '8'
+    label:                              '8'
     base:                               '8'
     shift:                              '*'
-    ctrl, alt, meta:                    none
 }
 
 key 9 {
-    label, number:                      '9'
+    label:                              '9'
     base:                               '9'
     shift:                              '('
-    ctrl, alt, meta:                    none
 }
 
 key SPACE {
     label:                              ' '
     base:                               ' '
-    ctrl:                               none
     alt, meta:                          fallback SEARCH
 }
 
 key ENTER {
     label:                              '\n'
     base:                               '\n'
-    ctrl, alt, meta:                    none
 }
 
 key TAB {
     label:                              '\t'
     base:                               '\t'
-    ctrl, alt, meta:                    none
 }
 
 key COMMA {
-    label, number:                      ','
+    label:                              ','
     base:                               ','
     shift:                              '<'
-    ctrl, alt, meta:                    none
 }
 
 key PERIOD {
-    label, number:                      '.'
+    label:                              '.'
     base:                               '.'
     shift:                              '>'
-    ctrl, alt, meta:                    none
 }
 
 key SLASH {
-    label, number:                      '/'
+    label:                              '/'
     base:                               '/'
     shift:                              '?'
-    ctrl, alt, meta:                    none
 }
 
 key GRAVE {
-    label, number:                      '`'
+    label:                              '`'
     base:                               '`'
     shift:                              '~'
     alt:                                '\u0300'
     alt+shift:                          '\u0303'
-    ctrl, meta:                         none
 }
 
 key MINUS {
-    label, number:                      '-'
+    label:                              '-'
     base:                               '-'
     shift:                              '_'
-    ctrl, alt, meta:                    none
 }
 
 key EQUALS {
-    label, number:                      '='
+    label:                              '='
     base:                               '='
     shift:                              '+'
-    ctrl, alt, meta:                    none
 }
 
 key LEFT_BRACKET {
-    label, number:                      '['
+    label:                              '['
     base:                               '['
     shift:                              '{'
-    ctrl, alt, meta:                    none
 }
 
 key RIGHT_BRACKET {
-    label, number:                      ']'
+    label:                              ']'
     base:                               ']'
     shift:                              '}'
-    ctrl, alt, meta:                    none
 }
 
 key BACKSLASH {
-    label, number:                      '\\'
+    label:                              '\\'
     base:                               '\\'
     shift:                              '|'
-    ctrl, alt, meta:                    none
 }
 
 key SEMICOLON {
-    label, number:                      ';'
+    label:                              ';'
     base:                               ';'
     shift:                              ':'
-    ctrl, alt, meta:                    none
 }
 
 key APOSTROPHE {
-    label, number:                      '\''
+    label:                              '\''
     base:                               '\''
     shift:                              '"'
-    ctrl, alt, meta:                    none
 }
 
 ### Numeric keypad ###
 
 key NUMPAD_0 {
-    label, number:                      '0'
+    label:                              '0'
     base:                               fallback INSERT
     numlock:                            '0'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_1 {
-    label, number:                      '1'
+    label:                              '1'
     base:                               fallback MOVE_END
     numlock:                            '1'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_2 {
-    label, number:                      '2'
+    label:                              '2'
     base:                               fallback DPAD_DOWN
     numlock:                            '2'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_3 {
-    label, number:                      '3'
+    label:                              '3'
     base:                               fallback PAGE_DOWN
     numlock:                            '3'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_4 {
-    label, number:                      '4'
+    label:                              '4'
     base:                               fallback DPAD_LEFT
     numlock:                            '4'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_5 {
-    label, number:                      '5'
+    label:                              '5'
     base:                               fallback DPAD_CENTER
     numlock:                            '5'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_6 {
-    label, number:                      '6'
+    label:                              '6'
     base:                               fallback DPAD_RIGHT
     numlock:                            '6'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_7 {
-    label, number:                      '7'
+    label:                              '7'
     base:                               fallback MOVE_HOME
     numlock:                            '7'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_8 {
-    label, number:                      '8'
+    label:                              '8'
     base:                               fallback DPAD_UP
     numlock:                            '8'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_9 {
-    label, number:                      '9'
+    label:                              '9'
     base:                               fallback PAGE_UP
     numlock:                            '9'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_LEFT_PAREN {
-    label, number:                      '('
+    label:                              '('
     base:                               '('
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_RIGHT_PAREN {
-    label, number:                      ')'
+    label:                              ')'
     base:                               ')'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_DIVIDE {
-    label, number:                      '/'
+    label:                              '/'
     base:                               '/'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_MULTIPLY {
-    label, number:                      '*'
+    label:                              '*'
     base:                               '*'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_SUBTRACT {
-    label, number:                      '-'
+    label:                              '-'
     base:                               '-'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_ADD {
-    label, number:                      '+'
+    label:                              '+'
     base:                               '+'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_DOT {
-    label, number:                      '.'
+    label:                              '.'
     base:                               fallback FORWARD_DEL
     numlock:                            '.'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_COMMA {
-    label, number:                      ','
+    label:                              ','
     base:                               ','
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_EQUALS {
-    label, number:                      '='
+    label:                              '='
     base:                               '='
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_ENTER {
@@ -518,22 +449,22 @@
 ### Special keys on phones ###
 
 key AT {
-    label, number:                      '@'
+    label:                              '@'
     base:                               '@'
 }
 
 key STAR {
-    label, number:                      '*'
+    label:                              '*'
     base:                               '*'
 }
 
 key POUND {
-    label, number:                      '#'
+    label:                              '#'
     base:                               '#'
 }
 
 key PLUS {
-    label, number:                      '+'
+    label:                              '+'
     base:                               '+'
 }
 
diff --git a/data/keyboards/Virtual.kcm b/data/keyboards/Virtual.kcm
index 0ce4a68..e592013 100644
--- a/data/keyboards/Virtual.kcm
+++ b/data/keyboards/Virtual.kcm
@@ -25,14 +25,12 @@
     label:                              'A'
     base:                               'a'
     shift, capslock:                    'A'
-    ctrl, alt, meta:                    none
 }
 
 key B {
     label:                              'B'
     base:                               'b'
     shift, capslock:                    'B'
-    ctrl, alt, meta:                    none
 }
 
 key C {
@@ -41,14 +39,12 @@
     shift, capslock:                    'C'
     alt:                                '\u00e7'
     shift+alt:                          '\u00c7'
-    ctrl, meta:                         none
 }
 
 key D {
     label:                              'D'
     base:                               'd'
     shift, capslock:                    'D'
-    ctrl, alt, meta:                    none
 }
 
 key E {
@@ -56,28 +52,24 @@
     base:                               'e'
     shift, capslock:                    'E'
     alt:                                '\u0301'
-    ctrl, meta:                         none
 }
 
 key F {
     label:                              'F'
     base:                               'f'
     shift, capslock:                    'F'
-    ctrl, alt, meta:                    none
 }
 
 key G {
     label:                              'G'
     base:                               'g'
     shift, capslock:                    'G'
-    ctrl, alt, meta:                    none
 }
 
 key H {
     label:                              'H'
     base:                               'h'
     shift, capslock:                    'H'
-    ctrl, alt, meta:                    none
 }
 
 key I {
@@ -85,35 +77,30 @@
     base:                               'i'
     shift, capslock:                    'I'
     alt:                                '\u0302'
-    ctrl, meta:                         none
 }
 
 key J {
     label:                              'J'
     base:                               'j'
     shift, capslock:                    'J'
-    ctrl, alt, meta:                    none
 }
 
 key K {
     label:                              'K'
     base:                               'k'
     shift, capslock:                    'K'
-    ctrl, alt, meta:                    none
 }
 
 key L {
     label:                              'L'
     base:                               'l'
     shift, capslock:                    'L'
-    ctrl, alt, meta:                    none
 }
 
 key M {
     label:                              'M'
     base:                               'm'
     shift, capslock:                    'M'
-    ctrl, alt, meta:                    none
 }
 
 key N {
@@ -121,35 +108,30 @@
     base:                               'n'
     shift, capslock:                    'N'
     alt:                                '\u0303'
-    ctrl, meta:                         none
 }
 
 key O {
     label:                              'O'
     base:                               'o'
     shift, capslock:                    'O'
-    ctrl, alt, meta:                    none
 }
 
 key P {
     label:                              'P'
     base:                               'p'
     shift, capslock:                    'P'
-    ctrl, alt, meta:                    none
 }
 
 key Q {
     label:                              'Q'
     base:                               'q'
     shift, capslock:                    'Q'
-    ctrl, alt, meta:                    none
 }
 
 key R {
     label:                              'R'
     base:                               'r'
     shift, capslock:                    'R'
-    ctrl, alt, meta:                    none
 }
 
 key S {
@@ -157,14 +139,12 @@
     base:                               's'
     shift, capslock:                    'S'
     alt:                                '\u00df'
-    ctrl, meta:                         none
 }
 
 key T {
     label:                              'T'
     base:                               't'
     shift, capslock:                    'T'
-    ctrl, alt, meta:                    none
 }
 
 key U {
@@ -172,339 +152,289 @@
     base:                               'u'
     shift, capslock:                    'U'
     alt:                                '\u0308'
-    ctrl, meta:                         none
 }
 
 key V {
     label:                              'V'
     base:                               'v'
     shift, capslock:                    'V'
-    ctrl, alt, meta:                    none
 }
 
 key W {
     label:                              'W'
     base:                               'w'
     shift, capslock:                    'W'
-    ctrl, alt, meta:                    none
 }
 
 key X {
     label:                              'X'
     base:                               'x'
     shift, capslock:                    'X'
-    ctrl, alt, meta:                    none
 }
 
 key Y {
     label:                              'Y'
     base:                               'y'
     shift, capslock:                    'Y'
-    ctrl, alt, meta:                    none
 }
 
 key Z {
     label:                              'Z'
     base:                               'z'
     shift, capslock:                    'Z'
-    ctrl, alt, meta:                    none
 }
 
 key 0 {
-    label, number:                      '0'
+    label:                              '0'
     base:                               '0'
     shift:                              ')'
-    ctrl, alt, meta:                    none
 }
 
 key 1 {
-    label, number:                      '1'
+    label:                              '1'
     base:                               '1'
     shift:                              '!'
-    ctrl, alt, meta:                    none
 }
 
 key 2 {
-    label, number:                      '2'
+    label:                              '2'
     base:                               '2'
     shift:                              '@'
-    ctrl, alt, meta:                    none
 }
 
 key 3 {
-    label, number:                      '3'
+    label:                              '3'
     base:                               '3'
     shift:                              '#'
-    ctrl, alt, meta:                    none
 }
 
 key 4 {
-    label, number:                      '4'
+    label:                              '4'
     base:                               '4'
     shift:                              '$'
-    ctrl, alt, meta:                    none
 }
 
 key 5 {
-    label, number:                      '5'
+    label:                              '5'
     base:                               '5'
     shift:                              '%'
-    ctrl, alt, meta:                    none
 }
 
 key 6 {
-    label, number:                      '6'
+    label:                              '6'
     base:                               '6'
     shift:                              '^'
-    ctrl, alt, meta:                    none
     alt+shift:                          '\u0302'
 }
 
 key 7 {
-    label, number:                      '7'
+    label:                              '7'
     base:                               '7'
     shift:                              '&'
-    ctrl, alt, meta:                    none
 }
 
 key 8 {
-    label, number:                      '8'
+    label:                              '8'
     base:                               '8'
     shift:                              '*'
-    ctrl, alt, meta:                    none
 }
 
 key 9 {
-    label, number:                      '9'
+    label:                              '9'
     base:                               '9'
     shift:                              '('
-    ctrl, alt, meta:                    none
 }
 
 key SPACE {
     label:                              ' '
     base:                               ' '
-    ctrl, alt:                          none
-    meta:                               fallback SEARCH
+    alt, meta:                          fallback SEARCH
 }
 
 key ENTER {
     label:                              '\n'
     base:                               '\n'
-    ctrl, alt, meta:                    none
 }
 
 key TAB {
     label:                              '\t'
     base:                               '\t'
-    ctrl, alt:                          none
-    meta:                               fallback APP_SWITCH
 }
 
 key COMMA {
-    label, number:                      ','
+    label:                              ','
     base:                               ','
     shift:                              '<'
-    ctrl, alt, meta:                    none
 }
 
 key PERIOD {
-    label, number:                      '.'
+    label:                              '.'
     base:                               '.'
     shift:                              '>'
-    ctrl, alt, meta:                    none
 }
 
 key SLASH {
-    label, number:                      '/'
+    label:                              '/'
     base:                               '/'
     shift:                              '?'
-    ctrl, alt, meta:                    none
 }
 
 key GRAVE {
-    label, number:                      '`'
+    label:                              '`'
     base:                               '`'
     shift:                              '~'
     alt:                                '\u0300'
     alt+shift:                          '\u0303'
-    ctrl, meta:                         none
 }
 
 key MINUS {
-    label, number:                      '-'
+    label:                              '-'
     base:                               '-'
     shift:                              '_'
-    ctrl, alt, meta:                    none
 }
 
 key EQUALS {
-    label, number:                      '='
+    label:                              '='
     base:                               '='
     shift:                              '+'
-    ctrl, alt, meta:                    none
 }
 
 key LEFT_BRACKET {
-    label, number:                      '['
+    label:                              '['
     base:                               '['
     shift:                              '{'
-    ctrl, alt, meta:                    none
 }
 
 key RIGHT_BRACKET {
-    label, number:                      ']'
+    label:                              ']'
     base:                               ']'
     shift:                              '}'
-    ctrl, alt, meta:                    none
 }
 
 key BACKSLASH {
-    label, number:                      '\\'
+    label:                              '\\'
     base:                               '\\'
     shift:                              '|'
-    ctrl, alt, meta:                    none
 }
 
 key SEMICOLON {
-    label, number:                      ';'
+    label:                              ';'
     base:                               ';'
     shift:                              ':'
-    ctrl, alt, meta:                    none
 }
 
 key APOSTROPHE {
-    label, number:                      '\''
+    label:                              '\''
     base:                               '\''
     shift:                              '"'
-    ctrl, alt, meta:                    none
 }
 
 ### Numeric keypad ###
 
 key NUMPAD_0 {
-    label, number:                      '0'
+    label:                              '0'
     base:                               fallback INSERT
     numlock:                            '0'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_1 {
-    label, number:                      '1'
+    label:                              '1'
     base:                               fallback MOVE_END
     numlock:                            '1'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_2 {
-    label, number:                      '2'
+    label:                              '2'
     base:                               fallback DPAD_DOWN
     numlock:                            '2'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_3 {
-    label, number:                      '3'
+    label:                              '3'
     base:                               fallback PAGE_DOWN
     numlock:                            '3'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_4 {
-    label, number:                      '4'
+    label:                              '4'
     base:                               fallback DPAD_LEFT
     numlock:                            '4'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_5 {
-    label, number:                      '5'
+    label:                              '5'
     base:                               fallback DPAD_CENTER
     numlock:                            '5'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_6 {
-    label, number:                      '6'
+    label:                              '6'
     base:                               fallback DPAD_RIGHT
     numlock:                            '6'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_7 {
-    label, number:                      '7'
+    label:                              '7'
     base:                               fallback MOVE_HOME
     numlock:                            '7'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_8 {
-    label, number:                      '8'
+    label:                              '8'
     base:                               fallback DPAD_UP
     numlock:                            '8'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_9 {
-    label, number:                      '9'
+    label:                              '9'
     base:                               fallback PAGE_UP
     numlock:                            '9'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_LEFT_PAREN {
-    label, number:                      '('
+    label:                              '('
     base:                               '('
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_RIGHT_PAREN {
-    label, number:                      ')'
+    label:                              ')'
     base:                               ')'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_DIVIDE {
-    label, number:                      '/'
+    label:                              '/'
     base:                               '/'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_MULTIPLY {
-    label, number:                      '*'
+    label:                              '*'
     base:                               '*'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_SUBTRACT {
-    label, number:                      '-'
+    label:                              '-'
     base:                               '-'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_ADD {
-    label, number:                      '+'
+    label:                              '+'
     base:                               '+'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_DOT {
-    label, number:                      '.'
+    label:                              '.'
     base:                               fallback FORWARD_DEL
     numlock:                            '.'
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_COMMA {
-    label, number:                      ','
+    label:                              ','
     base:                               ','
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_EQUALS {
-    label, number:                      '='
+    label:                              '='
     base:                               '='
-    ctrl, alt, meta:                    none
 }
 
 key NUMPAD_ENTER {
@@ -516,22 +446,22 @@
 ### Special keys on phones ###
 
 key AT {
-    label, number:                      '@'
+    label:                              '@'
     base:                               '@'
 }
 
 key STAR {
-    label, number:                      '*'
+    label:                              '*'
     base:                               '*'
 }
 
 key POUND {
-    label, number:                      '#'
+    label:                              '#'
     base:                               '#'
 }
 
 key PLUS {
-    label, number:                      '+'
+    label:                              '+'
     base:                               '+'
 }
 
@@ -539,6 +469,132 @@
 
 key ESCAPE {
     base:                               fallback BACK
-    meta:                               fallback HOME
-    alt:                                fallback MENU
+    alt, meta:                          fallback HOME
+    ctrl:                               fallback MENU
+}
+
+### Gamepad buttons ###
+
+key BUTTON_A {
+    base:                               fallback BACK
+}
+
+key BUTTON_B {
+    base:                               fallback BACK
+}
+
+key BUTTON_C {
+    base:                               fallback BACK
+}
+
+key BUTTON_X {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_Y {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_Z {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_L1 {
+    base:                               none
+}
+
+key BUTTON_R1 {
+    base:                               none
+}
+
+key BUTTON_L2 {
+    base:                               none
+}
+
+key BUTTON_R2 {
+    base:                               none
+}
+
+key BUTTON_THUMBL {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_THUMBR {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_START {
+    base:                               fallback HOME
+}
+
+key BUTTON_SELECT {
+    base:                               fallback MENU
+}
+
+key BUTTON_MODE {
+    base:                               fallback MENU
+}
+
+key BUTTON_1 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_2 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_3 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_4 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_5 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_6 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_7 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_8 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_9 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_10 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_11 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_12 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_13 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_14 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_15 {
+    base:                               fallback DPAD_CENTER
+}
+
+key BUTTON_16 {
+    base:                               fallback DPAD_CENTER
 }
diff --git a/include/androidfw/KeyCharacterMap.h b/include/androidfw/KeyCharacterMap.h
index 8db5781..06799f9 100644
--- a/include/androidfw/KeyCharacterMap.h
+++ b/include/androidfw/KeyCharacterMap.h
@@ -206,6 +206,7 @@
         status_t parseMapKey();
         status_t parseKey();
         status_t parseKeyProperty();
+        status_t finishKey(Key* key);
         status_t parseModifier(const String8& token, int32_t* outMetaState);
         status_t parseCharacterLiteral(char16_t* outCharacter);
     };
@@ -224,6 +225,7 @@
     bool getKey(int32_t keyCode, const Key** outKey) const;
     bool getKeyBehavior(int32_t keyCode, int32_t metaState,
             const Key** outKey, const Behavior** outBehavior) const;
+    static bool matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState);
 
     bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const;
 
diff --git a/libs/androidfw/KeyCharacterMap.cpp b/libs/androidfw/KeyCharacterMap.cpp
index c8f9439..2dc7507f 100644
--- a/libs/androidfw/KeyCharacterMap.cpp
+++ b/libs/androidfw/KeyCharacterMap.cpp
@@ -372,7 +372,7 @@
     if (getKey(keyCode, &key)) {
         const Behavior* behavior = key->firstBehavior;
         while (behavior) {
-            if ((behavior->metaState & metaState) == behavior->metaState) {
+            if (matchesMetaState(metaState, behavior->metaState)) {
                 *outKey = key;
                 *outBehavior = behavior;
                 return true;
@@ -383,6 +383,37 @@
     return false;
 }
 
+bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
+    // Behavior must have at least the set of meta states specified.
+    // And if the key event has CTRL, ALT or META then the behavior must exactly
+    // match those, taking into account that a behavior can specify that it handles
+    // one, both or either of a left/right modifier pair.
+    if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
+        const int32_t EXACT_META_STATES =
+                AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
+                | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
+                | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
+        int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
+        if (behaviorMetaState & AMETA_CTRL_ON) {
+            unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
+        } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
+            unmatchedMetaState &= ~AMETA_CTRL_ON;
+        }
+        if (behaviorMetaState & AMETA_ALT_ON) {
+            unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
+        } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
+            unmatchedMetaState &= ~AMETA_ALT_ON;
+        }
+        if (behaviorMetaState & AMETA_META_ON) {
+            unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
+        } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
+            unmatchedMetaState &= ~AMETA_META_ON;
+        }
+        return !unmatchedMetaState;
+    }
+    return false;
+}
+
 bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
     if (!ch) {
         return false;
@@ -699,12 +730,13 @@
         return BAD_VALUE;
     }
 
+    if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
+        ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
+                mTokenizer->getLocation().string());
+        return BAD_VALUE;
+    }
+
     if (mFormat == FORMAT_BASE) {
-        if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
-            ALOGE("%s: Base keyboard layout missing required keyboard 'type' declaration.",
-                    mTokenizer->getLocation().string());
-            return BAD_VALUE;
-        }
         if (mMap->mType == KEYBOARD_TYPE_OVERLAY) {
             ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
                     mTokenizer->getLocation().string());
@@ -840,10 +872,11 @@
 }
 
 status_t KeyCharacterMap::Parser::parseKeyProperty() {
+    Key* key = mMap->mKeys.valueFor(mKeyCode);
     String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
     if (token == "}") {
         mState = STATE_TOP;
-        return NO_ERROR;
+        return finishKey(key);
     }
 
     Vector<Property> properties;
@@ -943,7 +976,6 @@
     } while (!mTokenizer->isEol());
 
     // Add the behavior.
-    Key* key = mMap->mKeys.valueFor(mKeyCode);
     for (size_t i = 0; i < properties.size(); i++) {
         const Property& property = properties.itemAt(i);
         switch (property.property) {
@@ -992,6 +1024,28 @@
     return NO_ERROR;
 }
 
+status_t KeyCharacterMap::Parser::finishKey(Key* key) {
+    // Fill in default number property.
+    if (!key->number) {
+        char16_t digit = 0;
+        char16_t symbol = 0;
+        for (Behavior* b = key->firstBehavior; b; b = b->next) {
+            char16_t ch = b->character;
+            if (ch) {
+                if (ch >= '0' && ch <= '9') {
+                    digit = ch;
+                } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
+                        || ch == '-' || ch == '+' || ch == ',' || ch == '.'
+                        || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
+                    symbol = ch;
+                }
+            }
+        }
+        key->number = digit ? digit : symbol;
+    }
+    return NO_ERROR;
+}
+
 status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
     if (token == "base") {
         *outMetaState = 0;
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index e5167a5..429f246 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Известия"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth има връзка с тетъринг"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Методи на въвеждане: Настройка"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Физическа клавиатура"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Да се разреши ли на приложението <xliff:g id="APPLICATION">%1$s</xliff:g> достъп до USB устройството?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Да се разреши ли на приложението <xliff:g id="APPLICATION">%1$s</xliff:g> достъп до аксесоара за USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Да се отвори ли <xliff:g id="ACTIVITY">%1$s</xliff:g>, когато това USB устройство е свързано?"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 847bfc4..9c9674a 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Oznámení"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Datové připojení Bluetooth se sdílí"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Nastavit metody vstupu"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fyzická klávesnice"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Povolit aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> přístup k zařízení USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Povolit aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> přístup k perifernímu zařízení USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Chcete při připojení tohoto zařízení USB otevřít aplikaci <xliff:g id="ACTIVITY">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index f3d4043..2226aa8 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Obavijesti"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth posredno povezan"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Postavljanje načina unosa"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizička tipkovnica"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Dopustiti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> da pristupi ovom USB uređaju?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Dopustiti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> da pristupi ovom USB dodatku?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Otvoriti <xliff:g id="ACTIVITY">%1$s</xliff:g> kad se spoji ovaj USB uređaj?"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 267f5e7..f246132 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Pemberitahuan"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tertambat"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Menyiapkan metode masukan"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Keyboard fisik"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Izinkan apl <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses perangkat USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Izinkan apl <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses aksesori USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Buka <xliff:g id="ACTIVITY">%1$s</xliff:g> ketika perangkat USB ini tersambung?"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index fdd3b10..c7b272a 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Varslinger"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tilknyttet"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfigurer inndatametoder"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysisk tastatur"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Vil du gi appen <xliff:g id="APPLICATION">%1$s</xliff:g> tilgang til USB-enheten?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vil du gi appen <xliff:g id="APPLICATION">%1$s</xliff:g> tilgang til USB-tilbehøret?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vil du åpne <xliff:g id="ACTIVITY">%1$s</xliff:g> når denne USB-enheten er tilkoblet?"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index ff6ca3d..b778e4d 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificări"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Conectat prin tethering prin Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configuraţi metode de intrare"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Tastatură fizică"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Permiteţi aplicaţiei <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze dispozitivul USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Permiteţi aplicaţiei <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze accesoriul USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Deschideţi <xliff:g id="ACTIVITY">%1$s</xliff:g> la conectarea acestui dispozitiv USB?"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 3268544..fb7c21a 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Обавештења"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Веза преко Bluetooth-а"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Подеси методе уноса"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Физичка тастатура"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Желите ли да дозволите апликацији <xliff:g id="APPLICATION">%1$s</xliff:g> да приступа USB уређају?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Желите ли да дозволите апликацији <xliff:g id="APPLICATION">%1$s</xliff:g> да приступа USB помоћном уређају?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Желите ли да се отвори <xliff:g id="ACTIVITY">%1$s</xliff:g> када се прикључи овај USB уређај?"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 42c4721..82c5dd7 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"การแจ้งเตือน"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"บลูทูธที่ปล่อยสัญญาณ"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ตั้งค่าวิธีการป้อนข้อมูล"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"แป้นพิมพ์บนเครื่อง"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"อนุญาตให้แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> เข้าถึงอุปกรณ์ USB นี้หรือไม่"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"อนุญาตให้แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> เข้าถึงอุปกรณ์เสริม USB นี้หรือไม่"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"เปิด <xliff:g id="ACTIVITY">%1$s</xliff:g> เมื่อมีการเชื่อมต่ออุปกรณ์ USB นี้หรือไม่"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 9a05919..8a13400 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Сповіщення"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Створено прив\'язку Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Налаштувати методи введення"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Фізична клавіатура"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"Надати програмі <xliff:g id="APPLICATION">%1$s</xliff:g> доступ до пристрою USB?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Надати програмі <xliff:g id="APPLICATION">%1$s</xliff:g> доступ до аксесуара USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Відкривати \"<xliff:g id="ACTIVITY">%1$s</xliff:g>\", коли під’єднано пристрій USB?"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index cabc243..399890b 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -48,8 +48,7 @@
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"通知"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"藍牙網路共用已開"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"設定輸入法"</string>
-    <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
-    <skip />
+    <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"實體鍵盤"</string>
     <string name="usb_device_permission_prompt" msgid="834698001271562057">"允許 <xliff:g id="APPLICATION">%1$s</xliff:g> 應用程式存取 USB 裝置嗎?"</string>
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"允許 <xliff:g id="APPLICATION">%1$s</xliff:g> 應用程式存取 USB 配件嗎?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"連接這個 USB 裝置時啟用 <xliff:g id="ACTIVITY">%1$s</xliff:g> 嗎?"</string>
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 897b8d0..b22a109 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -306,7 +306,7 @@
     WindowState mStatusBar = null;
     boolean mHasSystemNavBar;
     int mStatusBarHeight;
-    final ArrayList<WindowState> mStatusBarPanels = new ArrayList<WindowState>();
+    final ArrayList<WindowState> mStatusBarSubPanels = new ArrayList<WindowState>();
     WindowState mNavigationBar = null;
     boolean mHasNavigationBar = false;
     boolean mCanHideNavigationBar = false;
@@ -1560,13 +1560,12 @@
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.STATUS_BAR_SERVICE,
                         "PhoneWindowManager");
-                mStatusBarPanels.add(win);
                 break;
             case TYPE_STATUS_BAR_SUB_PANEL:
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.STATUS_BAR_SERVICE,
                         "PhoneWindowManager");
-                mStatusBarPanels.add(win);
+                mStatusBarSubPanels.add(win);
                 break;
             case TYPE_KEYGUARD:
                 if (mKeyguard != null) {
@@ -1587,7 +1586,7 @@
         } else if (mNavigationBar == win) {
             mNavigationBar = null;
         } else {
-            mStatusBarPanels.remove(win);
+            mStatusBarSubPanels.remove(win);
         }
     }
 
@@ -2760,8 +2759,8 @@
         }
         if (mStatusBar != null && mStatusBar.isVisibleLw()) {
             RectF rect = new RectF(mStatusBar.getShownFrameLw());
-            for (int i=mStatusBarPanels.size()-1; i>=0; i--) {
-                WindowState w = mStatusBarPanels.get(i);
+            for (int i=mStatusBarSubPanels.size()-1; i>=0; i--) {
+                WindowState w = mStatusBarSubPanels.get(i);
                 if (w.isVisibleLw()) {
                     rect.union(w.getShownFrameLw());
                 }
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index ed2a6c0..6675816 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -36,6 +36,7 @@
 import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
 import android.graphics.Rect;
+import android.hardware.input.InputManager;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -44,12 +45,16 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.text.TextUtils.SimpleStringSplitter;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.IWindow;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -1301,11 +1306,11 @@
                     }
                 }
             }
-            final int flags = (mIncludeNotImportantViews) ?
-                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
-            final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
+                final int flags = (mIncludeNotImportantViews) ?
+                        AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
+                final int interrogatingPid = Binder.getCallingPid();
                 connection.performAccessibilityAction(accessibilityNodeId, action, interactionId,
                         callback, flags, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
@@ -1318,6 +1323,24 @@
             return true;
         }
 
+        public boolean perfromGlobalAction(int action) {
+            switch (action) {
+                case AccessibilityService.GLOBAL_ACTION_BACK: {
+                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK);
+                } return true;
+                case AccessibilityService.GLOBAL_ACTION_HOME: {
+                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME);
+                } return true;
+                case AccessibilityService.GLOBAL_ACTION_RECENTS: {
+                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_APP_SWITCH);
+                } return true;
+                case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: {
+                    // TODO: Implement when 6346026 is fixed.
+                } return true;
+            }
+            return false;
+        }
+
         public void onServiceDisconnected(ComponentName componentName) {
             /* do nothing - #binderDied takes care */
         }
@@ -1358,6 +1381,30 @@
             }
         }
 
+        private void sendDownAndUpKeyEvents(int keyCode) {
+            final long token = Binder.clearCallingIdentity();
+
+            // Inject down.
+            final long downTime = SystemClock.uptimeMillis();
+            KeyEvent down = KeyEvent.obtain(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
+                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
+                    InputDevice.SOURCE_KEYBOARD, null);
+            InputManager.getInstance().injectInputEvent(down,
+                    InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+            down.recycle();
+
+            // Inject up.
+            final long upTime = SystemClock.uptimeMillis();
+            KeyEvent up = KeyEvent.obtain(downTime, upTime, KeyEvent.ACTION_UP, keyCode, 0, 0,
+                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
+                    InputDevice.SOURCE_KEYBOARD, null);
+            InputManager.getInstance().injectInputEvent(up,
+                    InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+            up.recycle();
+
+            Binder.restoreCallingIdentity(token);
+        }
+
         private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
             if (DEBUG) {
                 Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 9085cea..ad13c41 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -3946,6 +3946,17 @@
         }
     }
 
+    final void updateTransitLocked(int transit, Bundle options) {
+        if (options != null) {
+            ActivityRecord r = topRunningActivityLocked(null);
+            if (r != null && r.state != ActivityState.RESUMED) {
+                r.updateOptionsLocked(options);
+            } else {
+                ActivityOptions.abort(options);
+            }
+        }
+        mService.mWindowManager.prepareAppTransition(transit, false);
+    }
 
     final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason, Bundle options) {
         if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
@@ -3955,7 +3966,12 @@
 
         if (top < 0 || (mHistory.get(top)).task.taskId == task) {
             // nothing to do!
-            ActivityOptions.abort(options);
+            if (reason != null &&
+                    (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
+                ActivityOptions.abort(options);
+            } else {
+                updateTransitLocked(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT, options);
+            }
             return;
         }
 
@@ -3999,16 +4015,7 @@
             }
             ActivityOptions.abort(options);
         } else {
-            if (options != null) {
-                ActivityRecord r = topRunningActivityLocked(null);
-                if (r != null && r.state != ActivityState.RESUMED) {
-                    r.updateOptionsLocked(options);
-                } else {
-                    ActivityOptions.abort(options);
-                }
-            }
-            mService.mWindowManager.prepareAppTransition(
-                    WindowManagerPolicy.TRANSIT_TASK_TO_FRONT, false);
+            updateTransitLocked(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT, options);
         }
         
         mService.mWindowManager.moveAppTokensToTop(moved);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 966f4c1..7aee8d2 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -3076,6 +3076,43 @@
         return null;
     }
 
+    private Animation createExitAnimationLocked(int transit, int duration) {
+        if (transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN ||
+                transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE) {
+            // If we are on top of the wallpaper, we need an animation that
+            // correctly handles the wallpaper staying static behind all of
+            // the animated elements.  To do this, will just have the existing
+            // element fade out.
+            Animation a = new AlphaAnimation(1, 0);
+            a.setDetachWallpaper(true);
+            a.setDuration(duration);
+            return a;
+        } else {
+            // For normal animations, the exiting element just holds in place.
+            Animation a = new AlphaAnimation(1, 1);
+            a.setDuration(duration);
+            return a;
+        }
+    }
+
+    /**
+     * Compute the pivot point for an animation that is scaling from a small
+     * rect on screen to a larger rect.  The pivot point varies depending on
+     * the distance between the inner and outer edges on both sides.  This
+     * function computes the pivot point for one dimension.
+     * @param startPos  Offset from left/top edge of outer rectangle to
+     * left/top edge of inner rectangle.
+     * @param finalScale The scaling factor between the size of the outer
+     * and inner rectangles.
+     */
+    private static float computePivot(int startPos, float finalScale) {
+        final float denom = finalScale-1;
+        if (Math.abs(denom) < .0001f) {
+            return startPos;
+        }
+        return -startPos / denom;
+    }
+
     private Animation createScaleUpAnimationLocked(int transit, boolean enter) {
         Animation a;
         // Pick the desired duration.  If this is an inter-activity transition,
@@ -3094,11 +3131,12 @@
         }
         if (enter) {
             // Entering app zooms out from the center of the initial rect.
-            Animation scale = new ScaleAnimation(
-                    mNextAppTransitionStartWidth/mAppDisplayWidth, 1,
-                    mNextAppTransitionStartHeight/mAppDisplayHeight, 1,
-                    mNextAppTransitionStartX + mNextAppTransitionStartWidth/2,
-                    mNextAppTransitionStartY + mNextAppTransitionStartHeight/2);
+            float scaleW = mNextAppTransitionStartWidth/(float)mAppDisplayWidth;
+            float scaleH = mNextAppTransitionStartHeight/(float)mAppDisplayHeight;
+            Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
+                    computePivot(mNextAppTransitionStartX, scaleW),
+                    computePivot(mNextAppTransitionStartY, scaleH));
+            scale.setDuration(duration);
             AnimationSet set = new AnimationSet(true);
             Animation alpha = new AlphaAnimation(0, 1);
             scale.setDuration(duration);
@@ -3107,13 +3145,11 @@
             set.addAnimation(alpha);
             a = set;
         } else {
-            // Exiting app just holds in place.
-            a = new AlphaAnimation(1, 1);
-            a.setDuration(duration);
+            a = createExitAnimationLocked(transit, duration);
         }
         a.setFillAfter(true);
         final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext,
-                com.android.internal.R.interpolator.decelerate_quint);
+                com.android.internal.R.interpolator.decelerate_quad);
         a.setInterpolator(interpolator);
         a.initialize(mAppDisplayWidth, mAppDisplayHeight,
                 mAppDisplayWidth, mAppDisplayHeight);
@@ -3123,8 +3159,10 @@
     private Animation createThumbnailAnimationLocked(int transit,
             boolean enter, boolean thumb) {
         Animation a;
-        final float thumbWidth = mNextAppTransitionThumbnail.getWidth();
-        final float thumbHeight = mNextAppTransitionThumbnail.getHeight();
+        final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
+        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
+        final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
+        final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
         // Pick the desired duration.  If this is an inter-activity transition,
         // it  is the standard duration for that.  Otherwise we use the longer
         // task transition duration.
@@ -3142,11 +3180,11 @@
         if (thumb) {
             // Animation for zooming thumbnail from its initial size to
             // filling the screen.
-            Animation scale = new ScaleAnimation(
-                    1, mAppDisplayWidth/thumbWidth,
-                    1, mAppDisplayHeight/thumbHeight,
-                    mNextAppTransitionStartX + thumbWidth/2,
-                    mNextAppTransitionStartY + thumbHeight/2);
+            float scaleW = mAppDisplayWidth/thumbWidth;
+            float scaleH = mAppDisplayHeight/thumbHeight;
+            Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
+                    computePivot(mNextAppTransitionStartX, 1/scaleW),
+                    computePivot(mNextAppTransitionStartY, 1/scaleH));
             AnimationSet set = new AnimationSet(true);
             Animation alpha = new AlphaAnimation(1, 0);
             scale.setDuration(duration);
@@ -3156,20 +3194,18 @@
             a = set;
         } else if (enter) {
             // Entering app zooms out from the center of the thumbnail.
-            a = new ScaleAnimation(
-                    thumbWidth/mAppDisplayWidth, 1,
-                    thumbHeight/mAppDisplayHeight, 1,
-                    mNextAppTransitionStartX + thumbWidth/2,
-                    mNextAppTransitionStartY + thumbHeight/2);
+            float scaleW = thumbWidth/mAppDisplayWidth;
+            float scaleH = thumbHeight/mAppDisplayHeight;
+            a = new ScaleAnimation(scaleW, 1, scaleH, 1,
+                    computePivot(mNextAppTransitionStartX, scaleW),
+                    computePivot(mNextAppTransitionStartY, scaleH));
             a.setDuration(duration);
         } else {
-            // Exiting app just holds in place.
-            a = new AlphaAnimation(1, 1);
-            a.setDuration(duration);
+            a = createExitAnimationLocked(transit, duration);
         }
         a.setFillAfter(true);
         final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext,
-                com.android.internal.R.interpolator.decelerate_quint);
+                com.android.internal.R.interpolator.decelerate_quad);
         a.setInterpolator(interpolator);
         a.initialize(mAppDisplayWidth, mAppDisplayHeight,
                 mAppDisplayWidth, mAppDisplayHeight);
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 0a7e7fd..3a51afe 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -978,7 +978,7 @@
 
         setSurfaceBoundaries(recoveringMemory);
 
-        if (w.mAttachedHidden || !w.isReadyForDisplay()) {
+        if (w.mAttachedHidden || !w.isReadyForDisplay() || !w.isDrawnLw()) {
             if (!mLastHidden) {
                 //dump();
                 mLastHidden = true;
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 214627d..55f2ca3 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -46,7 +46,6 @@
 
 import com.android.internal.R;
 import com.android.internal.telephony.DataConnection.FailCause;
-import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
@@ -58,7 +57,6 @@
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * {@hide}
@@ -140,7 +138,6 @@
     public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 30;
     public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
     public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32;
-    protected static final int EVENT_ICC_CHANGED = BASE + 33;
 
     /***** Constants *****/
 
@@ -253,8 +250,6 @@
 
     // member variables
     protected PhoneBase mPhone;
-    protected UiccController mUiccController;
-    protected AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
     protected Activity mActivity = Activity.NONE;
     protected State mState = State.IDLE;
     protected Handler mDataConnectionTracker = null;
@@ -505,8 +500,6 @@
     protected DataConnectionTracker(PhoneBase phone) {
         super();
         mPhone = phone;
-        mUiccController = UiccController.getInstance();
-        mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(getActionIntentReconnectAlarm());
@@ -548,7 +541,6 @@
         mIsDisposed = true;
         mPhone.getContext().unregisterReceiver(this.mIntentReceiver);
         mDataRoamingSettingObserver.unregister(mPhone.getContext());
-        mUiccController.unregisterForIccChanged(this);
     }
 
     protected void broadcastMessenger() {
@@ -671,7 +663,6 @@
     protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
     protected abstract void onCleanUpAllConnections(String cause);
     protected abstract boolean isDataPossible(String apnType);
-    protected abstract void onUpdateIcc();
 
     protected void onDataStallAlarm(int tag) {
         loge("onDataStallAlarm: not impleted tag=" + tag);
@@ -782,10 +773,6 @@
                 onSetPolicyDataEnabled(enabled);
                 break;
             }
-            case EVENT_ICC_CHANGED:
-                onUpdateIcc();
-                break;
-
             default:
                 Log.e("DATA", "Unidentified event msg=" + msg);
                 break;
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index 140b7c6..92024cd 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -35,12 +35,10 @@
 
 import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.CommandsInterface.RadioState;
-import com.android.internal.telephony.gsm.GSMPhone;
 import com.android.internal.telephony.gsm.SIMFileHandler;
 import com.android.internal.telephony.gsm.SIMRecords;
 import com.android.internal.telephony.cat.CatService;
 import com.android.internal.telephony.cdma.CDMALTEPhone;
-import com.android.internal.telephony.cdma.CDMAPhone;
 import com.android.internal.telephony.cdma.CdmaLteUiccFileHandler;
 import com.android.internal.telephony.cdma.CdmaLteUiccRecords;
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
@@ -116,6 +114,8 @@
     protected static final int EVENT_ICC_LOCKED = 1;
     private static final int EVENT_GET_ICC_STATUS_DONE = 2;
     protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3;
+    private static final int EVENT_PINPUK_DONE = 4;
+    private static final int EVENT_REPOLL_STATUS_DONE = 5;
     protected static final int EVENT_ICC_READY = 6;
     private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7;
     private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8;
@@ -178,19 +178,34 @@
         return State.UNKNOWN;
     }
 
-    public IccCard(PhoneBase phone, IccCardStatus ics, String logTag, boolean dbg) {
+    public IccCard(PhoneBase phone, String logTag, Boolean is3gpp, Boolean dbg) {
         mLogTag = logTag;
         mDbg = dbg;
-        if (mDbg) log("Creating");
-        update(phone, ics);
+        if (mDbg) log("[IccCard] Creating card type " + (is3gpp ? "3gpp" : "3gpp2"));
+        mPhone = phone;
+        this.is3gpp = is3gpp;
         mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(mPhone.getContext(),
                 mPhone.mCM, mHandler, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
+        if (phone.mCM.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE
+                && phone instanceof CDMALTEPhone) {
+            mIccFileHandler = new CdmaLteUiccFileHandler(this, "", mPhone.mCM);
+            mIccRecords = new CdmaLteUiccRecords(this, mPhone.mContext, mPhone.mCM);
+        } else {
+            // Correct aid will be set later (when GET_SIM_STATUS returns)
+            mIccFileHandler = is3gpp ? new SIMFileHandler(this, "", mPhone.mCM) :
+                                       new RuimFileHandler(this, "", mPhone.mCM);
+            mIccRecords = is3gpp ? new SIMRecords(this, mPhone.mContext, mPhone.mCM) :
+                                   new RuimRecords(this, mPhone.mContext, mPhone.mCM);
+        }
+        mCatService = CatService.getInstance(mPhone.mCM, mIccRecords,
+                mPhone.mContext, mIccFileHandler, this);
         mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
         mPhone.mCM.registerForOn(mHandler, EVENT_RADIO_ON, null);
+        mPhone.mCM.registerForIccStatusChanged(mHandler, EVENT_ICC_STATUS_CHANGED, null);
     }
 
     public void dispose() {
-        if (mDbg) log("Disposing card type " + (is3gpp ? "3gpp" : "3gpp2"));
+        if (mDbg) log("[IccCard] Disposing card type " + (is3gpp ? "3gpp" : "3gpp2"));
         mPhone.mCM.unregisterForIccStatusChanged(mHandler);
         mPhone.mCM.unregisterForOffOrNotAvailable(mHandler);
         mPhone.mCM.unregisterForOn(mHandler);
@@ -200,40 +215,6 @@
         mIccFileHandler.dispose();
     }
 
-    public void update(PhoneBase phone, IccCardStatus ics) {
-        if (phone != mPhone) {
-            PhoneBase oldPhone = mPhone;
-            mPhone = phone;
-            log("Update");
-            if (phone instanceof GSMPhone) {
-                is3gpp = true;
-            } else if (phone instanceof CDMALTEPhone){
-                is3gpp = true;
-            } else if (phone instanceof CDMAPhone){
-                is3gpp = false;
-            } else {
-                throw new RuntimeException("Update: Unhandled phone type. Critical error!" +
-                        phone.getPhoneName());
-            }
-
-
-            if (phone.mCM.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE
-                    && phone instanceof CDMALTEPhone) {
-                mIccFileHandler = new CdmaLteUiccFileHandler(this, "", mPhone.mCM);
-                mIccRecords = new CdmaLteUiccRecords(this, mPhone.mContext, mPhone.mCM);
-            } else {
-                // Correct aid will be set later (when GET_SIM_STATUS returns)
-                mIccFileHandler = is3gpp ? new SIMFileHandler(this, "", mPhone.mCM) :
-                                           new RuimFileHandler(this, "", mPhone.mCM);
-                mIccRecords = is3gpp ? new SIMRecords(this, mPhone.mContext, mPhone.mCM) :
-                                       new RuimRecords(this, mPhone.mContext, mPhone.mCM);
-            }
-            mCatService = CatService.getInstance(mPhone.mCM, mIccRecords, mPhone.mContext,
-                    mIccFileHandler, this);
-        }
-        mHandler.sendMessage(mHandler.obtainMessage(EVENT_GET_ICC_STATUS_DONE, ics));
-    }
-
     protected void finalize() {
         if (mDbg) log("[IccCard] Finalized card type " + (is3gpp ? "3gpp" : "3gpp2"));
     }
@@ -363,23 +344,27 @@
      */
 
     public void supplyPin (String pin, Message onComplete) {
-        mPhone.mCM.supplyIccPin(pin, onComplete);
+        mPhone.mCM.supplyIccPin(pin, mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
     }
 
     public void supplyPuk (String puk, String newPin, Message onComplete) {
-        mPhone.mCM.supplyIccPuk(puk, newPin, onComplete);
+        mPhone.mCM.supplyIccPuk(puk, newPin,
+                mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
     }
 
     public void supplyPin2 (String pin2, Message onComplete) {
-        mPhone.mCM.supplyIccPin2(pin2, onComplete);
+        mPhone.mCM.supplyIccPin2(pin2,
+                mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
     }
 
     public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
-        mPhone.mCM.supplyIccPuk2(puk2, newPin2, onComplete);
+        mPhone.mCM.supplyIccPuk2(puk2, newPin2,
+                mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
     }
 
     public void supplyNetworkDepersonalization (String pin, Message onComplete) {
-        mPhone.mCM.supplyNetworkDepersonalization(pin, onComplete);
+        mPhone.mCM.supplyNetworkDepersonalization(pin,
+                mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
     }
 
     /**
@@ -509,15 +494,21 @@
      *
      */
     public String getServiceProviderName () {
-        return mIccRecords.getServiceProviderName();
+        return mPhone.mIccRecords.getServiceProviderName();
     }
 
     protected void updateStateProperty() {
         mPhone.setSystemProperty(TelephonyProperties.PROPERTY_SIM_STATE, getState().toString());
     }
 
-    private void getIccCardStatusDone(IccCardStatus ics) {
-        handleIccCardStatus(ics);
+    private void getIccCardStatusDone(AsyncResult ar) {
+        if (ar.exception != null) {
+            Log.e(mLogTag,"Error getting ICC status. "
+                    + "RIL_REQUEST_GET_ICC_STATUS should "
+                    + "never return an error", ar.exception);
+            return;
+        }
+        handleIccCardStatus((IccCardStatus) ar.result);
     }
 
     private void handleIccCardStatus(IccCardStatus newCardStatus) {
@@ -593,7 +584,6 @@
         if (oldState != State.READY && newState == State.READY &&
                 (is3gpp || isSubscriptionFromIccCard)) {
             mIccFileHandler.setAid(getAid());
-            broadcastIccStateChangedIntent(INTENT_VALUE_ICC_READY, null);
             mIccRecords.onReady();
         }
     }
@@ -714,6 +704,7 @@
                     if (!is3gpp) {
                         handleCdmaSubscriptionSource();
                     }
+                    mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
                     break;
                 case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
                     handleCdmaSubscriptionSource();
@@ -734,9 +725,30 @@
                              obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
                      break;
                 case EVENT_GET_ICC_STATUS_DONE:
-                    IccCardStatus cs = (IccCardStatus)msg.obj;
+                    ar = (AsyncResult)msg.obj;
 
-                    getIccCardStatusDone(cs);
+                    getIccCardStatusDone(ar);
+                    break;
+                case EVENT_PINPUK_DONE:
+                    // a PIN/PUK/PIN2/PUK2/Network Personalization
+                    // request has completed. ar.userObj is the response Message
+                    // Repoll before returning
+                    ar = (AsyncResult)msg.obj;
+                    // TODO should abstract these exceptions
+                    AsyncResult.forMessage(((Message)ar.userObj)).exception
+                                                        = ar.exception;
+                    mPhone.mCM.getIccCardStatus(
+                        obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj));
+                    break;
+                case EVENT_REPOLL_STATUS_DONE:
+                    // Finished repolling status after PIN operation
+                    // ar.userObj is the response messaeg
+                    // ar.userObj.obj is already an AsyncResult with an
+                    // appropriate exception filled in if applicable
+
+                    ar = (AsyncResult)msg.obj;
+                    getIccCardStatusDone(ar);
+                    ((Message)ar.userObj).sendToTarget();
                     break;
                 case EVENT_QUERY_FACILITY_LOCK_DONE:
                     ar = (AsyncResult)msg.obj;
@@ -785,6 +797,10 @@
                                                         = ar.exception;
                     ((Message)ar.userObj).sendToTarget();
                     break;
+                case EVENT_ICC_STATUS_CHANGED:
+                    Log.d(mLogTag, "Received Event EVENT_ICC_STATUS_CHANGED");
+                    mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
+                    break;
                 case EVENT_CARD_REMOVED:
                     onIccSwap(false);
                     break;
@@ -951,10 +967,6 @@
         Log.d(mLogTag, "[IccCard] " + msg);
     }
 
-    private void loge(String msg) {
-        Log.e(mLogTag, "[IccCard] " + msg);
-    }
-
     protected int getCurrentApplicationIndex() {
         if (is3gpp) {
             return mIccCardStatus.getGsmUmtsSubscriptionAppIndex();
diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
index 0e5f2da..45562ca 100644
--- a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
@@ -103,23 +103,11 @@
 
     public IccPhoneBookInterfaceManager(PhoneBase phone) {
         this.phone = phone;
-        IccRecords r = phone.mIccRecords.get();
-        if (r != null) {
-            adnCache = r.getAdnCache();
-        }
     }
 
     public void dispose() {
     }
 
-    public void updateIccRecords(IccRecords iccRecords) {
-        if (iccRecords != null) {
-            adnCache = iccRecords.getAdnCache();
-        } else {
-            adnCache = null;
-        }
-    }
-
     protected void publish() {
         //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy
         ServiceManager.addService("simphonebook", this);
diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java
index 3c906471a..41c9d5a 100644
--- a/telephony/java/com/android/internal/telephony/IccRecords.java
+++ b/telephony/java/com/android/internal/telephony/IccRecords.java
@@ -26,8 +26,6 @@
 import com.android.internal.telephony.gsm.UsimServiceTable;
 import com.android.internal.telephony.ims.IsimRecords;
 
-import java.util.concurrent.atomic.AtomicBoolean;
-
 /**
  * {@hide}
  */
@@ -35,7 +33,7 @@
 
     protected static final boolean DBG = true;
     // ***** Instance Variables
-    protected AtomicBoolean mDestroyed = new AtomicBoolean(false);
+    protected boolean mDestroyed = false; // set to true once this object needs to be disposed of
     protected Context mContext;
     protected CommandsInterface mCi;
     protected IccFileHandler mFh;
@@ -81,9 +79,9 @@
 
     // ***** Event Constants
     protected static final int EVENT_SET_MSISDN_DONE = 30;
-    public static final int EVENT_MWI = 0; // Message Waiting indication
-    public static final int EVENT_CFI = 1; // Call Forwarding indication
-    public static final int EVENT_SPN = 2; // Service Provider Name
+    public static final int EVENT_MWI = 0;
+    public static final int EVENT_CFI = 1;
+    public static final int EVENT_SPN = 2;
 
     public static final int EVENT_GET_ICC_RECORD_DONE = 100;
 
@@ -115,7 +113,7 @@
      * Call when the IccRecords object is no longer going to be used.
      */
     public void dispose() {
-        mDestroyed.set(true);
+        mDestroyed = true;
         mParentCard = null;
         mFh = null;
         mCi = null;
@@ -130,8 +128,12 @@
         return adnCache;
     }
 
+    public IccCard getIccCard() {
+        return mParentCard;
+    }
+
     public void registerForRecordsLoaded(Handler h, int what, Object obj) {
-        if (mDestroyed.get()) {
+        if (mDestroyed) {
             return;
         }
 
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 0c2f234..2ac9365 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -40,7 +40,6 @@
 import com.android.internal.telephony.gsm.UsimServiceTable;
 import com.android.internal.telephony.ims.IsimRecords;
 import com.android.internal.telephony.test.SimulatedRadioControl;
-import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.telephony.gsm.SIMRecords;
 
 import java.io.FileDescriptor;
@@ -111,7 +110,6 @@
     protected static final int EVENT_SET_NETWORK_AUTOMATIC          = 28;
     protected static final int EVENT_NEW_ICC_SMS                    = 29;
     protected static final int EVENT_ICC_RECORD_EVENTS              = 30;
-    protected static final int EVENT_ICC_CHANGED                    = 31;
 
     // Key used to read/write current CLIR setting
     public static final String CLIR_KEY = "clir_key";
@@ -128,8 +126,7 @@
     int mCallRingDelay;
     public boolean mIsTheCurrentActivePhone = true;
     boolean mIsVoiceCapable = true;
-    protected UiccController mUiccController = null;
-    public AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
+    public IccRecords mIccRecords;
     protected AtomicReference<IccCard> mIccCard = new AtomicReference<IccCard>();
     public SmsStorageMonitor mSmsStorageMonitor;
     public SmsUsageMonitor mSmsUsageMonitor;
@@ -254,8 +251,6 @@
         // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers.
         mSmsStorageMonitor = new SmsStorageMonitor(this);
         mSmsUsageMonitor = new SmsUsageMonitor(context);
-        mUiccController = UiccController.getInstance(this);
-        mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
     }
 
     public void dispose() {
@@ -267,7 +262,6 @@
             // Dispose the SMS usage and storage monitors
             mSmsStorageMonitor.dispose();
             mSmsUsageMonitor.dispose();
-            mUiccController.unregisterForIccChanged(this);
         }
     }
 
@@ -275,10 +269,9 @@
         mSmsStorageMonitor = null;
         mSmsUsageMonitor = null;
         mSMS = null;
-        mIccRecords.set(null);
+        mIccRecords = null;
         mIccCard.set(null);
         mDataConnectionTracker = null;
-        mUiccController = null;
     }
 
     /**
@@ -315,10 +308,6 @@
                 }
                 break;
 
-            case EVENT_ICC_CHANGED:
-                onUpdateIccAvailability();
-                break;
-
             default:
                 throw new RuntimeException("unexpected event not handled");
         }
@@ -329,9 +318,6 @@
         return mContext;
     }
 
-    // Will be called when icc changed
-    protected abstract void onUpdateIccAvailability();
-
     /**
      * Disables the DNS check (i.e., allows "0.0.0.0").
      * Useful for lab testing environment.
@@ -680,26 +666,22 @@
 
     @Override
     public String getIccSerialNumber() {
-        IccRecords r = mIccRecords.get();
-        return (r != null) ? r.iccid : "";
+        return mIccRecords.iccid;
     }
 
     @Override
     public boolean getIccRecordsLoaded() {
-        IccRecords r = mIccRecords.get();
-        return (r != null) ? r.getRecordsLoaded() : false;
+        return mIccRecords.getRecordsLoaded();
     }
 
     @Override
     public boolean getMessageWaitingIndicator() {
-        IccRecords r = mIccRecords.get();
-        return (r != null) ? r.getVoiceMessageWaiting() : false;
+        return mIccRecords.getVoiceMessageWaiting();
     }
 
     @Override
     public boolean getCallForwardingIndicator() {
-        IccRecords r = mIccRecords.get();
-        return (r != null) ? r.getVoiceCallForwardingFlag() : false;
+        return mIccRecords.getVoiceCallForwardingFlag();
     }
 
     /**
@@ -1153,10 +1135,7 @@
      */
     @Override
     public void setVoiceMessageWaiting(int line, int countWaiting) {
-        IccRecords r = mIccRecords.get();
-        if (r != null) {
-            r.setVoiceMessageWaiting(line, countWaiting);
-        }
+        mIccRecords.setVoiceMessageWaiting(line, countWaiting);
     }
 
     /**
@@ -1165,8 +1144,7 @@
      */
     @Override
     public UsimServiceTable getUsimServiceTable() {
-        IccRecords r = mIccRecords.get();
-        return (r != null) ? r.getUsimServiceTable() : null;
+        return mIccRecords.getUsimServiceTable();
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index a86b68b..75eb226 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -18,15 +18,12 @@
 
 import android.os.AsyncResult;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 
-import com.android.internal.telephony.uicc.UiccController;
-
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
@@ -36,9 +33,6 @@
 public abstract class ServiceStateTracker extends Handler {
 
     protected CommandsInterface cm;
-    protected UiccController mUiccController = null;
-    protected IccCard mIccCard = null;
-    protected IccRecords mIccRecords = null;
 
     public ServiceState ss;
     protected ServiceState newSS;
@@ -136,7 +130,7 @@
     protected static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED  = 39;
     protected static final int EVENT_CDMA_PRL_VERSION_CHANGED          = 40;
     protected static final int EVENT_RADIO_ON                          = 41;
-    protected static final int EVENT_ICC_CHANGED                       = 42;
+
 
     protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
 
@@ -173,10 +167,7 @@
     protected static final String REGISTRATION_DENIED_GEN  = "General";
     protected static final String REGISTRATION_DENIED_AUTH = "Authentication Failure";
 
-    public ServiceStateTracker(PhoneBase p, CommandsInterface ci) {
-        cm = ci;
-        mUiccController = UiccController.getInstance();
-        mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
+    public ServiceStateTracker() {
     }
 
     public boolean getDesiredPowerState() {
@@ -303,10 +294,6 @@
                 }
                 break;
 
-            case EVENT_ICC_CHANGED:
-                onUpdateIccAvailability();
-                break;
-
             default:
                 log("Unhandled message with number: " + msg.what);
                 break;
@@ -317,7 +304,6 @@
     protected abstract void handlePollStateResult(int what, AsyncResult ar);
     protected abstract void updateSpnDisplay();
     protected abstract void setPowerStateToDesired();
-    protected abstract void onUpdateIccAvailability();
     protected abstract void log(String s);
     protected abstract void loge(String s);
 
@@ -477,21 +463,6 @@
         pollingContext = new int[1];
     }
 
-    /**
-     * Verifies the current thread is the same as the thread originally
-     * used in the initialization of this instance. Throws RuntimeException
-     * if not.
-     *
-     * @exception RuntimeException if the current thread is not
-     * the thread that originally obtained this PhoneBase instance.
-     */
-    protected void checkCorrectThread() {
-        if (Thread.currentThread() != getLooper().getThread()) {
-            throw new RuntimeException(
-                    "ServiceStateTracker must be used from within one thread");
-        }
-    }
-
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("ServiceStateTracker:");
         pw.println(" ss=" + ss);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index 24bb814..d99a625 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -29,7 +29,6 @@
 
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.IccRecords;
 import com.android.internal.telephony.OperatorInfo;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneNotifier;
@@ -67,6 +66,7 @@
     public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
         super(context, ci, notifier, false);
         m3gppSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
+        mIccRecords.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
     }
 
     @Override
@@ -88,6 +88,10 @@
 
     @Override
     protected void initSstIcc() {
+        mIccCard.set(UiccController.getInstance(this).getIccCard());
+        mIccRecords = mIccCard.get().getIccRecords();
+        // CdmaLteServiceStateTracker registers with IccCard to know
+        // when the card is ready. So create mIccCard before the ServiceStateTracker
         mSST = new CdmaLteServiceStateTracker(this);
     }
 
@@ -96,6 +100,7 @@
         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
             super.dispose();
             m3gppSMS.dispose();
+            mIccRecords.unregisterForNewSms(this);
         }
     }
 
@@ -198,12 +203,11 @@
 
     @Override
     public boolean updateCurrentCarrierInProvider() {
-        IccRecords r = mIccRecords.get();
-        if (r != null) {
+        if (mIccRecords != null) {
             try {
                 Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
                 ContentValues map = new ContentValues();
-                String operatorNumeric = r.getOperatorNumeric();
+                String operatorNumeric = mIccRecords.getOperatorNumeric();
                 map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
                 if (DBG) log("updateCurrentCarrierInProvider from UICC: numeric=" +
                         operatorNumeric);
@@ -221,8 +225,7 @@
     // return IMSI from USIM as subscriber ID.
     @Override
     public String getSubscriberId() {
-        IccRecords r = mIccRecords.get();
-        return (r != null) ? r.getIMSI() : "";
+        return mIccRecords.getIMSI();
     }
 
     @Override
@@ -237,14 +240,12 @@
 
     @Override
     public IsimRecords getIsimRecords() {
-        IccRecords r = mIccRecords.get();
-        return (r != null) ? r.getIsimRecords() : null;
+        return mIccRecords.getIsimRecords();
     }
 
     @Override
     public String getMsisdn() {
-        IccRecords r = mIccRecords.get();
-        return (r != null) ? r.getMsisdnNumber() : null;
+        return mIccRecords.getMsisdnNumber();
     }
 
     @Override
@@ -258,26 +259,6 @@
     }
 
     @Override
-    protected void registerForRuimRecordEvents() {
-        IccRecords r = mIccRecords.get();
-        if (r == null) {
-            return;
-        }
-        r.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
-        super.registerForRuimRecordEvents();
-    }
-
-    @Override
-    protected void unregisterForRuimRecordEvents() {
-        IccRecords r = mIccRecords.get();
-        if (r == null) {
-            return;
-        }
-        r.unregisterForNewSms(this);
-        super.unregisterForRuimRecordEvents();
-    }
-
-    @Override
     protected void log(String s) {
             Log.d(LOG_TAG, "[CDMALTEPhone] " + s);
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 7922b3c..9f6ec71 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -50,7 +50,6 @@
 import com.android.internal.telephony.IccException;
 import com.android.internal.telephony.IccFileHandler;
 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
-import com.android.internal.telephony.IccRecords;
 import com.android.internal.telephony.IccSmsInterfaceManager;
 import com.android.internal.telephony.MccTable;
 import com.android.internal.telephony.MmiCode;
@@ -153,6 +152,10 @@
     }
 
     protected void initSstIcc() {
+        mIccCard.set(UiccController.getInstance(this).getIccCard());
+        mIccRecords = mIccCard.get().getIccRecords();
+        // CdmaServiceStateTracker registers with IccCard to know
+        // when the Ruim card is ready. So create mIccCard before the ServiceStateTracker
         mSST = new CdmaServiceStateTracker(this);
     }
 
@@ -169,6 +172,7 @@
         mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML);
 
         mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
+        registerForRuimRecordEvents();
         mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
         mCM.registerForOn(this, EVENT_RADIO_ON, null);
         mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
@@ -723,10 +727,7 @@
         Message resp;
         mVmNumber = voiceMailNumber;
         resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
-        IccRecords r = mIccRecords.get();
-        if (r != null) {
-            r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
-        }
+        mIccRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp);
     }
 
     public String getVoiceMailNumber() {
@@ -748,8 +749,7 @@
      * @hide
      */
     public int getVoiceMessageCount() {
-        IccRecords r = mIccRecords.get();
-        int voicemailCount =  (r != null) ? r.getVoiceMessageCount() : 0;
+        int voicemailCount =  mIccRecords.getVoiceMessageCount();
         // If mRuimRecords.getVoiceMessageCount returns zero, then there is possibility
         // that phone was power cycled and would have lost the voicemail count.
         // So get the count from preferences.
@@ -1064,39 +1064,6 @@
         }
     }
 
-    @Override
-    protected void onUpdateIccAvailability() {
-        if (mUiccController == null ) {
-            return;
-        }
-
-        IccCard newIccCard = mUiccController.getIccCard();
-
-        IccCard c = mIccCard.get();
-        if (c != newIccCard) {
-            if (c != null) {
-                log("Removing stale icc objects.");
-                if (mIccRecords.get() != null) {
-                    unregisterForRuimRecordEvents();
-                    if (mRuimPhoneBookInterfaceManager != null) {
-                        mRuimPhoneBookInterfaceManager.updateIccRecords(null);
-                    }
-                }
-                mIccRecords.set(null);
-                mIccCard.set(null);
-            }
-            if (newIccCard != null) {
-                log("New card found");
-                mIccCard.set(newIccCard);
-                mIccRecords.set(newIccCard.getIccRecords());
-                registerForRuimRecordEvents();
-                if (mRuimPhoneBookInterfaceManager != null) {
-                    mRuimPhoneBookInterfaceManager.updateIccRecords(mIccRecords.get());
-                }
-            }
-        }
-    }
-
     private void processIccRecordEvents(int eventCode) {
         switch (eventCode) {
             case RuimRecords.EVENT_MWI:
@@ -1495,22 +1462,14 @@
         return mEriManager.isEriFileLoaded();
     }
 
-    protected void registerForRuimRecordEvents() {
-        IccRecords r = mIccRecords.get();
-        if (r == null) {
-            return;
-        }
-        r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
-        r.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
+    private void registerForRuimRecordEvents() {
+        mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
+        mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
     }
 
-    protected void unregisterForRuimRecordEvents() {
-        IccRecords r = mIccRecords.get();
-        if (r == null) {
-            return;
-        }
-        r.unregisterForRecordsEvents(this);
-        r.unregisterForRecordsLoaded(this);
+    private void unregisterForRuimRecordEvents() {
+        mIccRecords.unregisterForRecordsEvents(this);
+        mIccRecords.unregisterForRecordsLoaded(this);
     }
 
     protected void log(String s) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index d05ed624..7e5e707 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -40,8 +40,6 @@
 import com.android.internal.telephony.DataConnectionAc;
 import com.android.internal.telephony.DataConnectionTracker;
 import com.android.internal.telephony.EventLogTags;
-import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.IccRecords;
 import com.android.internal.telephony.RetryManager;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.Phone;
@@ -112,6 +110,7 @@
 
         p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
         p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
+        p.mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
         p.mCM.registerForDataNetworkStateChanged (this, EVENT_DATA_STATE_CHANGED, null);
         p.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null);
         p.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null);
@@ -153,8 +152,7 @@
         // Unregister from all events
         mPhone.mCM.unregisterForAvailable(this);
         mPhone.mCM.unregisterForOffOrNotAvailable(this);
-        IccRecords r = mIccRecords.get();
-        if (r != null) { r.unregisterForRecordsLoaded(this);}
+        mCdmaPhone.mIccRecords.unregisterForRecordsLoaded(this);
         mPhone.mCM.unregisterForDataNetworkStateChanged(this);
         mCdmaPhone.mCT.unregisterForVoiceCallEnded(this);
         mCdmaPhone.mCT.unregisterForVoiceCallStarted(this);
@@ -224,12 +222,11 @@
         boolean subscriptionFromNv = (mCdmaSSM.getCdmaSubscriptionSource()
                                        == CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_NV);
 
-        IccRecords r = mIccRecords.get();
         boolean allowed =
                     (psState == ServiceState.STATE_IN_SERVICE ||
                             mAutoAttachOnCreation) &&
                     (subscriptionFromNv ||
-                            (r != null && r.getRecordsLoaded())) &&
+                            mCdmaPhone.mIccRecords.getRecordsLoaded()) &&
                     (mCdmaPhone.mSST.isConcurrentVoiceAndDataAllowed() ||
                             mPhone.getState() == Phone.State.IDLE) &&
                     !roaming &&
@@ -244,7 +241,7 @@
                 reason += " - psState= " + psState;
             }
             if (!subscriptionFromNv &&
-                    !(r != null && r.getRecordsLoaded())) {
+                    !mCdmaPhone.mIccRecords.getRecordsLoaded()) {
                 reason += " - RUIM not loaded";
             }
             if (!(mCdmaPhone.mSST.isConcurrentVoiceAndDataAllowed() ||
@@ -1009,33 +1006,6 @@
     }
 
     @Override
-    protected void onUpdateIcc() {
-        if (mUiccController == null ) {
-            return;
-        }
-
-        IccCard newIccCard = mUiccController.getIccCard();
-        IccRecords newIccRecords = null;
-        if (newIccCard != null) {
-            newIccRecords = newIccCard.getIccRecords();
-        }
-
-        IccRecords r = mIccRecords.get();
-        if (r != newIccRecords) {
-            if (r != null) {
-                log("Removing stale icc objects.");
-                r.unregisterForRecordsLoaded(this);
-                mIccRecords.set(null);
-            }
-            if (newIccCard != null) {
-                log("New card found");
-                mIccRecords.set(newIccRecords);
-                newIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
-            }
-        }
-    }
-
-    @Override
     public boolean isDisconnected() {
         return ((mState == State.IDLE) || (mState == State.FAILED));
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 9a82f57..ff7a0810 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -65,7 +65,7 @@
             handlePollStateResult(msg.what, ar);
             break;
         case EVENT_RUIM_RECORDS_LOADED:
-            CdmaLteUiccRecords sim = (CdmaLteUiccRecords)mIccRecords;
+            CdmaLteUiccRecords sim = (CdmaLteUiccRecords)phone.mIccRecords;
             if ((sim != null) && sim.isProvisioned()) {
                 mMdn = sim.getMdn();
                 mMin = sim.getMin();
@@ -353,18 +353,16 @@
                 ss.setOperatorAlphaLong(eriText);
             }
 
-            if (mIccCard != null && mIccCard.getState() == IccCard.State.READY &&
-                    mIccRecords != null) {
+            if (phone.getIccCard().getState() == IccCard.State.READY) {
                 // SIM is found on the device. If ERI roaming is OFF, and SID/NID matches
                 // one configfured in SIM, use operator name  from CSIM record.
                 boolean showSpn =
-                    ((CdmaLteUiccRecords)mIccRecords).getCsimSpnDisplayCondition();
+                    ((CdmaLteUiccRecords)phone.mIccRecords).getCsimSpnDisplayCondition();
                 int iconIndex = ss.getCdmaEriIconIndex();
 
                 if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) &&
-                    isInHomeSidNid(ss.getSystemId(), ss.getNetworkId()) &&
-                    mIccRecords != null) {
-                    ss.setOperatorAlphaLong(mIccRecords.getServiceProviderName());
+                    isInHomeSidNid(ss.getSystemId(), ss.getNetworkId())) {
+                    ss.setOperatorAlphaLong(phone.mIccRecords.getServiceProviderName());
                 }
             }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 16ff70e..b694e0a 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -115,6 +115,12 @@
     long mSavedTime;
     long mSavedAtTime;
 
+    /**
+     * We can't register for SIM_RECORDS_LOADED immediately because the
+     * SIMRecords object may not be instantiated yet.
+     */
+    private boolean mNeedToRegForRuimLoaded = false;
+
     /** Wake lock used while setting time of day. */
     private PowerManager.WakeLock mWakeLock;
     private static final String WAKELOCK_TAG = "ServiceStateTracker";
@@ -156,10 +162,11 @@
     };
 
     public CdmaServiceStateTracker(CDMAPhone phone) {
-        super(phone, phone.mCM);
+        super();
 
         this.phone = phone;
         cr = phone.getContext().getContentResolver();
+        cm = phone.mCM;
         ss = new ServiceState();
         newSS = new ServiceState();
         cellLoc = new CdmaCellLocation();
@@ -196,17 +203,18 @@
             Settings.System.getUriFor(Settings.System.AUTO_TIME_ZONE), true,
             mAutoTimeZoneObserver);
         setSignalStrengthDefaultValues();
+
+        mNeedToRegForRuimLoaded = true;
     }
 
     public void dispose() {
-        checkCorrectThread();
         // Unregister for all events.
         cm.unregisterForRadioStateChanged(this);
         cm.unregisterForVoiceNetworkStateChanged(this);
+        phone.getIccCard().unregisterForReady(this);
         cm.unregisterForCdmaOtaProvision(this);
         phone.unregisterForEriFileLoaded(this);
-        if (mIccCard != null) {mIccCard.unregisterForReady(this);}
-        if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);}
+        phone.mIccRecords.unregisterForRecordsLoaded(this);
         cm.unSetOnSignalStrengthUpdate(this);
         cm.unSetOnNITZTime(this);
         cr.unregisterContentObserver(mAutoTimeObserver);
@@ -277,6 +285,14 @@
         case EVENT_RUIM_READY:
             // TODO: Consider calling setCurrentPreferredNetworkType as we do in GsmSST.
             // cm.setCurrentPreferredNetworkType();
+
+            // The RUIM is now ready i.e if it was locked it has been
+            // unlocked. At this stage, the radio is already powered on.
+            if (mNeedToRegForRuimLoaded) {
+                phone.mIccRecords.registerForRecordsLoaded(this,
+                        EVENT_RUIM_RECORDS_LOADED, null);
+                mNeedToRegForRuimLoaded = false;
+            }
             if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription.");
             getSubscriptionInfoAndStartPollingThreads();
             phone.prepareEri();
@@ -389,16 +405,8 @@
                     mIsMinInfoReady = true;
 
                     updateOtaspState();
-                    if (mIccCard != null) {
-                        if (DBG) log("GET_CDMA_SUBSCRIPTION broadcast Icc state changed");
-                        mIccCard.broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI,
-                                null);
-                    } else {
-                        if (DBG) {
-                            log("GET_CDMA_SUBSCRIPTION mIccCard is null (probably NV type device)" +
-                                    " can't broadcast Icc state changed");
-                        }
-                    }
+                    phone.getIccCard().broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI,
+                            null);
                 } else {
                     if (DBG) {
                         log("GET_CDMA_SUBSCRIPTION: error parsing cdmaSubscription params num="
@@ -490,6 +498,8 @@
         if (!isSubscriptionFromRuim) {
             // NV is ready when subscription source is NV
             sendMessage(obtainMessage(EVENT_NV_READY));
+        } else {
+            phone.getIccCard().registerForReady(this, EVENT_RUIM_READY, null);
         }
     }
 
@@ -1685,38 +1695,6 @@
     }
 
     @Override
-    protected void onUpdateIccAvailability() {
-        if (mUiccController == null ) {
-            return;
-        }
-
-        IccCard newIccCard = mUiccController.getIccCard();
-
-        if (mIccCard != newIccCard) {
-            if (mIccCard != null) {
-                log("Removing stale icc objects.");
-                mIccCard.unregisterForReady(this);
-                if (mIccRecords != null) {
-                    mIccRecords.unregisterForRecordsLoaded(this);
-                }
-                mIccRecords = null;
-                mIccCard = null;
-            }
-            if (newIccCard != null) {
-                log("New card found");
-                mIccCard = newIccCard;
-                mIccRecords = mIccCard.getIccRecords();
-                if (isSubscriptionFromRuim) {
-                    mIccCard.registerForReady(this, EVENT_RUIM_READY, null);
-                    if (mIccRecords != null) {
-                        mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
     protected void log(String s) {
         Log.d(LOG_TAG, "[CdmaSST] " + s);
     }
@@ -1749,6 +1727,7 @@
         pw.println(" mSavedTimeZone=" + mSavedTimeZone);
         pw.println(" mSavedTime=" + mSavedTime);
         pw.println(" mSavedAtTime=" + mSavedAtTime);
+        pw.println(" mNeedToRegForRuimLoaded=" + mNeedToRegForRuimLoaded);
         pw.println(" mWakeLock=" + mWakeLock);
         pw.println(" mCurPlmn=" + mCurPlmn);
         pw.println(" mMdn=" + mMdn);
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
index e919245..04ee2dd8 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
@@ -21,7 +21,6 @@
 import android.os.Message;
 import android.util.Log;
 
-import com.android.internal.telephony.IccFileHandler;
 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
 
 /**
@@ -35,6 +34,7 @@
 
     public RuimPhoneBookInterfaceManager(CDMAPhone phone) {
         super(phone);
+        adnCache = phone.mIccRecords.getAdnCache();
         //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy
     }
 
@@ -61,12 +61,8 @@
             AtomicBoolean status = new AtomicBoolean(false);
             Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE, status);
 
-            IccFileHandler fh = phone.getIccFileHandler();
-            //IccFileHandler can be null if there is no icc card present.
-            if (fh != null) {
-                fh.getEFLinearRecordSize(efid, response);
-                waitForResult(status);
-            }
+            phone.getIccFileHandler().getEFLinearRecordSize(efid, response);
+            waitForResult(status);
         }
 
         return recordSize;
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index 80183c6..2fefa3f 100755
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -199,7 +199,7 @@
 
         boolean isRecordLoadResponse = false;
 
-        if (mDestroyed.get()) {
+        if (mDestroyed) {
             loge("Received message " + msg +
                     "[" + msg.what + "] while being destroyed. Ignoring.");
             return;
@@ -317,20 +317,18 @@
         // One record loaded successfully or failed, In either case
         // we need to update the recordsToLoad count
         recordsToLoad -= 1;
-        if (DBG) log("onRecordLoaded " + recordsToLoad + " requested: " + recordsRequested);
+        if (DBG) log("RuimRecords:onRecordLoaded " + recordsToLoad + " requested: " + recordsRequested);
 
         if (recordsToLoad == 0 && recordsRequested == true) {
             onAllRecordsLoaded();
         } else if (recordsToLoad < 0) {
-            loge("recordsToLoad <0, programmer error suspected");
+            loge("RuimRecords: recordsToLoad <0, programmer error suspected");
             recordsToLoad = 0;
         }
     }
 
     @Override
     protected void onAllRecordsLoaded() {
-        if (DBG) log("record load complete");
-
         // Further records that can be inserted are Operator/OEM dependent
 
         String operator = getRUIMOperatorNumeric();
@@ -350,6 +348,13 @@
 
     @Override
     public void onReady() {
+        /* broadcast intent ICC_READY here so that we can make sure
+          READY is sent before IMSI ready
+        */
+
+        mParentCard.broadcastIccStateChangedIntent(
+                IccCard.INTENT_VALUE_ICC_READY, null);
+
         fetchRuimRecords();
 
         mCi.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
@@ -359,7 +364,7 @@
     private void fetchRuimRecords() {
         recordsRequested = true;
 
-        if (DBG) log("fetchRuimRecords " + recordsToLoad);
+        Log.v(LOG_TAG, "RuimRecords:fetchRuimRecords " + recordsToLoad);
 
         mCi.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
         recordsToLoad++;
@@ -368,7 +373,7 @@
                 obtainMessage(EVENT_GET_ICCID_DONE));
         recordsToLoad++;
 
-        if (DBG) log("fetchRuimRecords " + recordsToLoad + " requested: " + recordsRequested);
+        log("RuimRecords:fetchRuimRecords " + recordsToLoad + " requested: " + recordsRequested);
         // Further records that can be inserted are Operator/OEM dependent
     }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 8dda74b..6e9cd51 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -59,7 +59,6 @@
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.IccFileHandler;
 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
-import com.android.internal.telephony.IccRecords;
 import com.android.internal.telephony.IccSmsInterfaceManager;
 import com.android.internal.telephony.MmiCode;
 import com.android.internal.telephony.OperatorInfo;
@@ -138,11 +137,13 @@
         if (ci instanceof SimulatedRadioControl) {
             mSimulatedRadioControl = (SimulatedRadioControl) ci;
         }
+
         mCM.setPhoneType(Phone.PHONE_TYPE_GSM);
+        mIccCard.set(UiccController.getInstance(this).getIccCard());
+        mIccRecords = mIccCard.get().getIccRecords();
         mCT = new GsmCallTracker(this);
         mSST = new GsmServiceStateTracker (this);
         mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
-
         mDataConnectionTracker = new GsmDataConnectionTracker (this);
         if (!unitTestMode) {
             mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
@@ -151,6 +152,7 @@
         }
 
         mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
+        registerForSimRecordEvents();
         mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
         mCM.registerForOn(this, EVENT_RADIO_ON, null);
         mCM.setOnUSSD(this, EVENT_USSD, null);
@@ -794,8 +796,7 @@
 
     public String getVoiceMailNumber() {
         // Read from the SIM. If its null, try reading from the shared preference area.
-        IccRecords r = mIccRecords.get();
-        String number = (r != null) ? r.getVoiceMailNumber() : "";
+        String number = mIccRecords.getVoiceMailNumber();
         if (TextUtils.isEmpty(number)) {
             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
             number = sp.getString(VM_NUMBER, null);
@@ -817,9 +818,8 @@
 
     public String getVoiceMailAlphaTag() {
         String ret;
-        IccRecords r = mIccRecords.get();
 
-        ret = (r != null) ? r.getVoiceMailAlphaTag() : "";
+        ret = mIccRecords.getVoiceMailAlphaTag();
 
         if (ret == null || ret.length() == 0) {
             return mContext.getText(
@@ -852,31 +852,24 @@
     }
 
     public String getSubscriberId() {
-        IccRecords r = mIccRecords.get();
-        return (r != null) ? r.getIMSI() : "";
+        return mIccRecords.getIMSI();
     }
 
     public String getLine1Number() {
-        IccRecords r = mIccRecords.get();
-        return (r != null) ? r.getMsisdnNumber() : "";
+        return mIccRecords.getMsisdnNumber();
     }
 
     @Override
     public String getMsisdn() {
-        IccRecords r = mIccRecords.get();
-        return (r != null) ? r.getMsisdnNumber() : "";
+        return mIccRecords.getMsisdnNumber();
     }
 
     public String getLine1AlphaTag() {
-        IccRecords r = mIccRecords.get();
-        return (r != null) ? r.getMsisdnAlphaTag() : "";
+        return mIccRecords.getMsisdnAlphaTag();
     }
 
     public void setLine1Number(String alphaTag, String number, Message onComplete) {
-        IccRecords r = mIccRecords.get();
-        if (r != null) {
-            r.setMsisdnNumber(alphaTag, number, onComplete);
-        }
+        mIccRecords.setMsisdnNumber(alphaTag, number, onComplete);
     }
 
     public void setVoiceMailNumber(String alphaTag,
@@ -886,10 +879,7 @@
         Message resp;
         mVmNumber = voiceMailNumber;
         resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
-        IccRecords r = mIccRecords.get();
-        if (r != null) {
-            r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
-        }
+        mIccRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp);
     }
 
     private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) {
@@ -1257,9 +1247,8 @@
 
             case EVENT_SET_CALL_FORWARD_DONE:
                 ar = (AsyncResult)msg.obj;
-                IccRecords r = mIccRecords.get();
-                if (ar.exception == null && r != null) {
-                    r.setVoiceCallForwardingFlag(1, msg.arg1 == 1);
+                if (ar.exception == null) {
+                    mIccRecords.setVoiceCallForwardingFlag(1, msg.arg1 == 1);
                 }
                 onComplete = (Message) ar.userObj;
                 if (onComplete != null) {
@@ -1332,41 +1321,12 @@
         }
     }
 
-    @Override
-    protected void onUpdateIccAvailability() {
-        if (mUiccController == null ) {
-            return;
-        }
-
-        IccCard newIccCard = mUiccController.getIccCard();
-
-        IccCard c = mIccCard.get();
-        if (c != newIccCard) {
-            if (c != null) {
-                if (LOCAL_DEBUG) log("Removing stale icc objects.");
-                if (mIccRecords.get() != null) {
-                    unregisterForSimRecordEvents();
-                    mSimPhoneBookIntManager.updateIccRecords(null);
-                }
-                mIccRecords.set(null);
-                mIccCard.set(null);
-            }
-            if (newIccCard != null) {
-                if (LOCAL_DEBUG) log("New card found");
-                mIccCard.set(newIccCard);
-                mIccRecords.set(newIccCard.getIccRecords());
-                registerForSimRecordEvents();
-                mSimPhoneBookIntManager.updateIccRecords(mIccRecords.get());
-            }
-        }
-    }
-
     private void processIccRecordEvents(int eventCode) {
         switch (eventCode) {
-            case IccRecords.EVENT_CFI:
+            case SIMRecords.EVENT_CFI:
                 notifyCallForwardingIndicator();
                 break;
-            case IccRecords.EVENT_MWI:
+            case SIMRecords.EVENT_MWI:
                 notifyMessageWaitingIndicator();
                 break;
         }
@@ -1378,12 +1338,11 @@
      * @return true for success; false otherwise.
      */
     boolean updateCurrentCarrierInProvider() {
-        IccRecords r = mIccRecords.get();
-        if (r != null) {
+        if (mIccRecords != null) {
             try {
                 Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
                 ContentValues map = new ContentValues();
-                map.put(Telephony.Carriers.NUMERIC, r.getOperatorNumeric());
+                map.put(Telephony.Carriers.NUMERIC, mIccRecords.getOperatorNumeric());
                 mContext.getContentResolver().insert(uri, map);
                 return true;
             } catch (SQLException e) {
@@ -1445,19 +1404,16 @@
     }
 
     private void handleCfuQueryResult(CallForwardInfo[] infos) {
-        IccRecords r = mIccRecords.get();
-        if (r != null) {
-            if (infos == null || infos.length == 0) {
-                // Assume the default is not active
-                // Set unconditional CFF in SIM to false
-                r.setVoiceCallForwardingFlag(1, false);
-            } else {
-                for (int i = 0, s = infos.length; i < s; i++) {
-                    if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
-                        r.setVoiceCallForwardingFlag(1, (infos[i].status == 1));
-                        // should only have the one
-                        break;
-                    }
+        if (infos == null || infos.length == 0) {
+            // Assume the default is not active
+            // Set unconditional CFF in SIM to false
+            mIccRecords.setVoiceCallForwardingFlag(1, false);
+        } else {
+            for (int i = 0, s = infos.length; i < s; i++) {
+                if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
+                    mIccRecords.setVoiceCallForwardingFlag(1, (infos[i].status == 1));
+                    // should only have the one
+                    break;
                 }
             }
         }
@@ -1516,35 +1472,22 @@
     }
 
     public boolean isCspPlmnEnabled() {
-        IccRecords r = mIccRecords.get();
-        return (r != null) ? r.isCspPlmnEnabled() : false;
+        return mIccRecords.isCspPlmnEnabled();
     }
 
     private void registerForSimRecordEvents() {
-        IccRecords r = mIccRecords.get();
-        if (r == null) {
-            return;
-        }
-        r.registerForNetworkSelectionModeAutomatic(
+        mIccRecords.registerForNetworkSelectionModeAutomatic(
                 this, EVENT_SET_NETWORK_AUTOMATIC, null);
-        r.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
-        r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
-        r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
+        mIccRecords.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
+        mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
+        mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
     }
 
     private void unregisterForSimRecordEvents() {
-        IccRecords r = mIccRecords.get();
-        if (r == null) {
-            return;
-        }
-        r.unregisterForNetworkSelectionModeAutomatic(this);
-        r.unregisterForNewSms(this);
-        r.unregisterForRecordsEvents(this);
-        r.unregisterForRecordsLoaded(this);
-    }
-
-    protected void log(String s) {
-            Log.d(LOG_TAG, "[GSMPhone] " + s);
+        mIccRecords.unregisterForNetworkSelectionModeAutomatic(this);
+        mIccRecords.unregisterForNewSms(this);
+        mIccRecords.unregisterForRecordsEvents(this);
+        mIccRecords.unregisterForRecordsLoaded(this);
     }
 
     @Override
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index b44ba0b..40ee58c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -59,8 +59,6 @@
 import com.android.internal.telephony.DataConnectionAc;
 import com.android.internal.telephony.DataConnectionTracker;
 import com.android.internal.telephony.EventLogTags;
-import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.IccRecords;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.RILConstants;
@@ -180,6 +178,7 @@
 
         p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
         p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
+        p.mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
         p.mCM.registerForDataNetworkStateChanged (this, EVENT_DATA_STATE_CHANGED, null);
         p.getCallTracker().registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null);
         p.getCallTracker().registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null);
@@ -220,8 +219,7 @@
         //Unregister for all events
         mPhone.mCM.unregisterForAvailable(this);
         mPhone.mCM.unregisterForOffOrNotAvailable(this);
-        IccRecords r = mIccRecords.get();
-        if (r != null) { r.unregisterForRecordsLoaded(this);}
+        mPhone.mIccRecords.unregisterForRecordsLoaded(this);
         mPhone.mCM.unregisterForDataNetworkStateChanged(this);
         mPhone.getCallTracker().unregisterForVoiceCallEnded(this);
         mPhone.getCallTracker().unregisterForVoiceCallStarted(this);
@@ -622,12 +620,10 @@
 
         int gprsState = mPhone.getServiceStateTracker().getCurrentDataConnectionState();
         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
-        IccRecords r = mIccRecords.get();
-        boolean recordsLoaded = (r != null) ? r.getRecordsLoaded() : false;
 
         boolean allowed =
                     (gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) &&
-                    recordsLoaded &&
+                    mPhone.mIccRecords.getRecordsLoaded() &&
                     (mPhone.getState() == Phone.State.IDLE ||
                      mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) &&
                     internalDataEnabled &&
@@ -639,7 +635,7 @@
             if (!((gprsState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) {
                 reason += " - gprs= " + gprsState;
             }
-            if (!recordsLoaded) reason += " - SIM not loaded";
+            if (!mPhone.mIccRecords.getRecordsLoaded()) reason += " - SIM not loaded";
             if (mPhone.getState() != Phone.State.IDLE &&
                     !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
                 reason += " - PhoneState= " + mPhone.getState();
@@ -1900,8 +1896,7 @@
             log("onRadioAvailable: We're on the simulator; assuming data is connected");
         }
 
-        IccRecords r = mIccRecords.get();
-        if (r != null && r.getRecordsLoaded()) {
+        if (mPhone.mIccRecords.getRecordsLoaded()) {
             notifyOffApnsOfAvailability(null);
         }
 
@@ -2213,8 +2208,7 @@
      */
     private void createAllApnList() {
         mAllApns = new ArrayList<ApnSetting>();
-        IccRecords r = mIccRecords.get();
-        String operator = (r != null) ? r.getOperatorNumeric() : "";
+        String operator = mPhone.mIccRecords.getOperatorNumeric();
         if (operator != null) {
             String selection = "numeric = '" + operator + "'";
             // query only enabled apn.
@@ -2325,9 +2319,8 @@
             }
         }
 
-        IccRecords r = mIccRecords.get();
-        String operator = (r != null) ? r.getOperatorNumeric() : "";
-        int radioTech = mPhone.getServiceState().getRadioTechnology();
+        String operator = mPhone.mIccRecords.getOperatorNumeric();
+        int networkType = mPhone.getServiceState().getNetworkType();
 
         if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
             if (canSetPreferApn && mPreferredApn != null) {
@@ -2336,7 +2329,7 @@
                         + mPreferredApn.numeric + ":" + mPreferredApn);
                 }
                 if (mPreferredApn.numeric.equals(operator)) {
-                    if (mPreferredApn.bearer == 0 || mPreferredApn.bearer == radioTech) {
+                    if (mPreferredApn.bearer == 0 || mPreferredApn.bearer == networkType) {
                         apnList.add(mPreferredApn);
                         if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
                         return apnList;
@@ -2355,7 +2348,7 @@
         if (mAllApns != null) {
             for (ApnSetting apn : mAllApns) {
                 if (apn.canHandleType(requestedApnType)) {
-                    if (apn.bearer == 0 || apn.bearer == radioTech) {
+                    if (apn.bearer == 0 || apn.bearer == networkType) {
                         if (DBG) log("apn info : " +apn.toString());
                         apnList.add(apn);
                     }
@@ -2563,33 +2556,6 @@
     }
 
     @Override
-    protected void onUpdateIcc() {
-        if (mUiccController == null ) {
-            return;
-        }
-
-        IccCard newIccCard = mUiccController.getIccCard();
-        IccRecords newIccRecords = null;
-        if (newIccCard != null) {
-            newIccRecords = newIccCard.getIccRecords();
-        }
-
-        IccRecords r = mIccRecords.get();
-        if (r != newIccRecords) {
-            if (r != null) {
-                log("Removing stale icc objects.");
-                r.unregisterForRecordsLoaded(this);
-                mIccRecords.set(null);
-            }
-            if (newIccCard != null) {
-                log("New card found");
-                mIccRecords.set(newIccRecords);
-                newIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
-            }
-        }
-    }
-
-    @Override
     protected void log(String s) {
         Log.d(LOG_TAG, "[GsmDCT] "+ s);
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index 9e34b6a..9b3d5cd 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -885,10 +885,7 @@
                 */
                 if ((ar.exception == null) && (msg.arg1 == 1)) {
                     boolean cffEnabled = (msg.arg2 == 1);
-                    IccRecords r = phone.mIccRecords.get();
-                    if (r != null) {
-                        r.setVoiceCallForwardingFlag(1, cffEnabled);
-                    }
+                    phone.mIccRecords.setVoiceCallForwardingFlag(1, cffEnabled);
                 }
 
                 onSetComplete(ar);
@@ -1206,10 +1203,7 @@
                 (info.serviceClass & serviceClassMask)
                         == CommandsInterface.SERVICE_CLASS_VOICE) {
             boolean cffEnabled = (info.status == 1);
-            IccRecords r = phone.mIccRecords.get();
-            if (r != null) {
-                r.setVoiceCallForwardingFlag(1, cffEnabled);
-            }
+            phone.mIccRecords.setVoiceCallForwardingFlag(1, cffEnabled);
         }
 
         return TextUtils.replace(template, sources, destinations);
@@ -1234,10 +1228,7 @@
                 sb.append(context.getText(com.android.internal.R.string.serviceDisabled));
 
                 // Set unconditional CFF in SIM to false
-                IccRecords r = phone.mIccRecords.get();
-                if (r != null) {
-                    r.setVoiceCallForwardingFlag(1, false);
-                }
+                phone.mIccRecords.setVoiceCallForwardingFlag(1, false);
             } else {
 
                 SpannableStringBuilder tb = new SpannableStringBuilder();
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 7c03d03..c0acf5b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -124,6 +124,12 @@
     long mSavedTime;
     long mSavedAtTime;
 
+    /**
+     * We can't register for SIM_RECORDS_LOADED immediately because the
+     * SIMRecords object may not be instantiated yet.
+     */
+    private boolean mNeedToRegForSimLoaded;
+
     /** Started the recheck process after finding gprs should registered but not. */
     private boolean mStartedGprsRegCheck = false;
 
@@ -186,9 +192,10 @@
     };
 
     public GsmServiceStateTracker(GSMPhone phone) {
-        super(phone, phone.mCM);
+        super();
 
         this.phone = phone;
+        cm = phone.mCM;
         ss = new ServiceState();
         newSS = new ServiceState();
         cellLoc = new GsmCellLocation();
@@ -206,6 +213,7 @@
         cm.setOnNITZTime(this, EVENT_NITZ_TIME, null);
         cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null);
         cm.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
+        phone.getIccCard().registerForReady(this, EVENT_SIM_READY, null);
 
         // system setting property AIRPLANE_MODE_ON is set in Settings.
         int airplaneMode = Settings.System.getInt(
@@ -222,6 +230,7 @@
                 mAutoTimeZoneObserver);
 
         setSignalStrengthDefaultValues();
+        mNeedToRegForSimLoaded = true;
 
         // Monitor locale change
         IntentFilter filter = new IntentFilter();
@@ -233,13 +242,12 @@
     }
 
     public void dispose() {
-        checkCorrectThread();
         // Unregister for all events.
         cm.unregisterForAvailable(this);
         cm.unregisterForRadioStateChanged(this);
         cm.unregisterForVoiceNetworkStateChanged(this);
-        if (mIccCard != null) {mIccCard.unregisterForReady(this);}
-        if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);}
+        phone.getIccCard().unregisterForReady(this);
+        phone.mIccRecords.unregisterForRecordsLoaded(this);
         cm.unSetOnSignalStrengthUpdate(this);
         cm.unSetOnRestrictedStateChanged(this);
         cm.unSetOnNITZTime(this);
@@ -277,6 +285,15 @@
                 // Set the network type, in case the radio does not restore it.
                 cm.setCurrentPreferredNetworkType();
 
+                // The SIM is now ready i.e if it was locked
+                // it has been unlocked. At this stage, the radio is already
+                // powered on.
+                if (mNeedToRegForSimLoaded) {
+                    phone.mIccRecords.registerForRecordsLoaded(this,
+                            EVENT_SIM_RECORDS_LOADED, null);
+                    mNeedToRegForSimLoaded = false;
+                }
+
                 boolean skipRestoringSelection = phone.getContext().getResources().getBoolean(
                         com.android.internal.R.bool.skip_restoring_network_selection);
 
@@ -478,11 +495,8 @@
     }
 
     protected void updateSpnDisplay() {
-        if (mIccRecords == null) {
-            return;
-        }
-        int rule = mIccRecords.getDisplayRule(ss.getOperatorNumeric());
-        String spn = mIccRecords.getServiceProviderName();
+        int rule = phone.mIccRecords.getDisplayRule(ss.getOperatorNumeric());
+        String spn = phone.mIccRecords.getServiceProviderName();
         String plmn = ss.getOperatorAlphaLong();
 
         // For emergency calls only, pass the EmergencyCallsOnly string via EXTRA_PLMN
@@ -1131,7 +1145,7 @@
                     ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) ||
                     ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
             //ignore the normal call and data restricted state before SIM READY
-            if (mIccCard.getState() == IccCard.State.READY) {
+            if (phone.getIccCard().getState() == IccCard.State.READY) {
                 newRs.setCsNormalRestricted(
                         ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) ||
                         ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
@@ -1658,35 +1672,6 @@
     }
 
     @Override
-    protected void onUpdateIccAvailability() {
-        if (mUiccController == null ) {
-            return;
-        }
-
-        IccCard newIccCard = mUiccController.getIccCard();
-
-        if (mIccCard != newIccCard) {
-            if (mIccCard != null) {
-                log("Removing stale icc objects.");
-                mIccCard.unregisterForReady(this);
-                if (mIccRecords != null) {
-                    mIccRecords.unregisterForRecordsLoaded(this);
-                }
-                mIccRecords = null;
-                mIccCard = null;
-            }
-            if (newIccCard != null) {
-                log("New card found");
-                mIccCard = newIccCard;
-                mIccRecords = mIccCard.getIccRecords();
-                mIccCard.registerForReady(this, EVENT_SIM_READY, null);
-                if (mIccRecords != null) {
-                    mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
-                }
-            }
-        }
-    }
-    @Override
     protected void log(String s) {
         Log.d(LOG_TAG, "[GsmSST] " + s);
     }
@@ -1726,6 +1711,7 @@
         pw.println(" mSavedTimeZone=" + mSavedTimeZone);
         pw.println(" mSavedTime=" + mSavedTime);
         pw.println(" mSavedAtTime=" + mSavedAtTime);
+        pw.println(" mNeedToRegForSimLoaded=" + mNeedToRegForSimLoaded);
         pw.println(" mStartedGprsRegCheck=" + mStartedGprsRegCheck);
         pw.println(" mReportedGprsNoReg=" + mReportedGprsNoReg);
         pw.println(" mNotification=" + mNotification);
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 3077995..80988fd 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -521,7 +521,7 @@
 
         boolean isRecordLoadResponse = false;
 
-        if (mDestroyed.get()) {
+        if (mDestroyed) {
             loge("Received message " + msg + "[" + msg.what + "] " +
                     " while being destroyed. Ignoring.");
             return;
@@ -1299,6 +1299,12 @@
 
     @Override
     public void onReady() {
+        /* broadcast intent SIM_READY here so that we can make sure
+          READY is sent before IMSI ready
+        */
+        mParentCard.broadcastIccStateChangedIntent(
+                IccCard.INTENT_VALUE_ICC_READY, null);
+
         fetchSimRecords();
     }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
index 37f9a4f..35ba0d1 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
@@ -21,7 +21,6 @@
 import android.os.Message;
 import android.util.Log;
 
-import com.android.internal.telephony.IccFileHandler;
 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
 
 /**
@@ -35,6 +34,7 @@
 
     public SimPhoneBookInterfaceManager(GSMPhone phone) {
         super(phone);
+        adnCache = phone.mIccRecords.getAdnCache();
         //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy
     }
 
@@ -61,11 +61,8 @@
             AtomicBoolean status = new AtomicBoolean(false);
             Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE, status);
 
-            IccFileHandler fh = phone.getIccFileHandler();
-            if (fh != null) {
-                fh.getEFLinearRecordSize(efid, response);
-                waitForResult(status);
-            }
+            phone.getIccFileHandler().getEFLinearRecordSize(efid, response);
+            waitForResult(status);
         }
 
         return recordSize;
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
index 0243522..5c4b446 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -461,8 +461,4 @@
             notifyPhoneStateChanged();
         }
     }
-
-    @Override
-    protected void onUpdateIccAvailability() {
-    }
 }
diff --git a/telephony/java/com/android/internal/telephony/uicc/UiccController.java b/telephony/java/com/android/internal/telephony/uicc/UiccController.java
index 4e12d6d..5961efd 100644
--- a/telephony/java/com/android/internal/telephony/uicc/UiccController.java
+++ b/telephony/java/com/android/internal/telephony/uicc/UiccController.java
@@ -16,150 +16,78 @@
 
 package com.android.internal.telephony.uicc;
 
-import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.IccCardStatus;
-import com.android.internal.telephony.IccCardStatus.CardState;
 import com.android.internal.telephony.PhoneBase;
+import com.android.internal.telephony.cdma.CDMALTEPhone;
+import com.android.internal.telephony.cdma.CDMAPhone;
+import com.android.internal.telephony.gsm.GSMPhone;
 
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Registrant;
-import android.os.RegistrantList;
 import android.util.Log;
 
 /* This class is responsible for keeping all knowledge about
  * ICCs in the system. It is also used as API to get appropriate
  * applications to pass them to phone and service trackers.
  */
-public class UiccController extends Handler {
+public class UiccController {
     private static final boolean DBG = true;
     private static final String LOG_TAG = "RIL_UiccController";
 
-    private static final int EVENT_ICC_STATUS_CHANGED = 1;
-    private static final int EVENT_GET_ICC_STATUS_DONE = 2;
-
     private static UiccController mInstance;
 
     private PhoneBase mCurrentPhone;
-    private CommandsInterface mCi;
+    private boolean mIsCurrentCard3gpp;
     private IccCard mIccCard;
-    private boolean mRegisteredWithCi = false;
-
-    private RegistrantList mIccChangedRegistrants = new RegistrantList();
 
     public static synchronized UiccController getInstance(PhoneBase phone) {
         if (mInstance == null) {
             mInstance = new UiccController(phone);
-        } else if (phone != null) {
+        } else {
             mInstance.setNewPhone(phone);
         }
         return mInstance;
     }
 
-    // This method is not synchronized as getInstance(PhoneBase) is.
-    public static UiccController getInstance() {
-        return getInstance(null);
-    }
-
-    public synchronized IccCard getIccCard() {
+    public IccCard getIccCard() {
         return mIccCard;
     }
 
-    //Notifies when card status changes
-    public void registerForIccChanged(Handler h, int what, Object obj) {
-        Registrant r = new Registrant (h, what, obj);
-        mIccChangedRegistrants.add(r);
-        //Notify registrant right after registering, so that it will get the latest ICC status,
-        //otherwise which may not happen until there is an actual change in ICC status.
-        r.notifyRegistrant();
-    }
-    public void unregisterForIccChanged(Handler h) {
-        mIccChangedRegistrants.remove(h);
-    }
-
-    @Override
-    public void handleMessage (Message msg) {
-        switch (msg.what) {
-            case EVENT_ICC_STATUS_CHANGED:
-                if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
-                mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
-                break;
-            case EVENT_GET_ICC_STATUS_DONE:
-                if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
-                AsyncResult ar = (AsyncResult)msg.obj;
-                onGetIccCardStatusDone(ar);
-                break;
-            default:
-                Log.e(LOG_TAG, " Unknown Event " + msg.what);
-        }
-    }
-
     private UiccController(PhoneBase phone) {
         if (DBG) log("Creating UiccController");
         setNewPhone(phone);
     }
 
-    private synchronized void onGetIccCardStatusDone(AsyncResult ar) {
-        if (ar.exception != null) {
-            Log.e(LOG_TAG,"Error getting ICC status. "
-                    + "RIL_REQUEST_GET_ICC_STATUS should "
-                    + "never return an error", ar.exception);
+    private void setNewPhone(PhoneBase phone) {
+        mCurrentPhone = phone;
+        if (phone instanceof GSMPhone) {
+            if (DBG) log("New phone is GSMPhone");
+            updateCurrentCard(IccCard.CARD_IS_3GPP);
+        } else if (phone instanceof CDMALTEPhone){
+            if (DBG) log("New phone type is CDMALTEPhone");
+            updateCurrentCard(IccCard.CARD_IS_3GPP);
+        } else if (phone instanceof CDMAPhone){
+            if (DBG) log("New phone type is CDMAPhone");
+            updateCurrentCard(IccCard.CARD_IS_NOT_3GPP);
+        } else {
+            Log.e(LOG_TAG, "Unhandled phone type. Critical error!");
+        }
+    }
+
+    private void updateCurrentCard(boolean isNewCard3gpp) {
+        if (mIsCurrentCard3gpp == isNewCard3gpp && mIccCard != null) {
             return;
         }
 
-        IccCardStatus status = (IccCardStatus)ar.result;
-
-        //Update already existing card
-        if (mIccCard != null && status.getCardState() == CardState.CARDSTATE_PRESENT) {
-            mIccCard.update(mCurrentPhone, status);
-        }
-
-        //Dispose of removed card
-        if (mIccCard != null && status.getCardState() != CardState.CARDSTATE_PRESENT) {
+        if (mIccCard != null) {
             mIccCard.dispose();
             mIccCard = null;
         }
 
-        //Create new card
-        if (mIccCard == null && status.getCardState() == CardState.CARDSTATE_PRESENT) {
-            mIccCard = new IccCard(mCurrentPhone, status, mCurrentPhone.getPhoneName(), true);
-        }
-
-        if (DBG) log("Notifying IccChangedRegistrants");
-        mIccChangedRegistrants.notifyRegistrants();
-    }
-
-    private void setNewPhone(PhoneBase phone) {
-        if (phone == null) {
-            throw new RuntimeException("Phone can't be null in UiccController");
-        }
-
-        if (DBG) log("setNewPhone");
-        if (mCurrentPhone != phone) {
-            if (mIccCard != null) {
-                // Refresh card if phone changed
-                // TODO: Remove once card is simplified
-                if (DBG) log("Disposing card since phone object changed");
-                mIccCard.dispose();
-                mIccCard = null;
-            }
-            sendMessage(obtainMessage(EVENT_ICC_STATUS_CHANGED));
-            mCurrentPhone = phone;
-
-            if (!mRegisteredWithCi) {
-                // This needs to be done only once after we have valid phone object
-                mCi = mCurrentPhone.mCM;
-                mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null);
-                // TODO remove this once modem correctly notifies the unsols
-                mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED, null);
-                mRegisteredWithCi = true;
-            }
-        }
+        mIsCurrentCard3gpp = isNewCard3gpp;
+        mIccCard = new IccCard(mCurrentPhone, mCurrentPhone.getPhoneName(),
+                isNewCard3gpp, DBG);
     }
 
     private void log(String string) {
         Log.d(LOG_TAG, string);
     }
-}
+}
\ No newline at end of file