Fix keyboard redraw bug on long-press of CapsLock.

Expose invalidateKey and invalidateAllKeys for subclasses to call when needed.
diff --git a/api/current.xml b/api/current.xml
index ec84c0d..7c5e667 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -61016,6 +61016,30 @@
  visibility="public"
 >
 </method>
+<method name="invalidateAllKeys"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="invalidateKey"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyIndex" type="int">
+</parameter>
+</method>
 <method name="isPreviewEnabled"
  return="boolean"
  abstract="false"
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 65c9893..8b474d5 100755
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -407,7 +407,7 @@
         // Release buffer, just in case the new keyboard has a different size. 
         // It will be reallocated on the next draw.
         mBuffer = null;
-        invalidateAll();
+        invalidateAllKeys();
         computeProximityThreshold(keyboard);
         mMiniKeyboardCache.clear(); // Not really necessary to do every time, but will free up views
     }
@@ -431,7 +431,7 @@
         if (mKeyboard != null) {
             if (mKeyboard.setShifted(shifted)) {
                 // The whole keyboard probably needs to be redrawn
-                invalidateAll();
+                invalidateAllKeys();
                 return true;
             }
         }
@@ -573,7 +573,7 @@
         if (mBuffer == null) {
             mBuffer = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
             mCanvas = new Canvas(mBuffer);
-            invalidateAll();
+            invalidateAllKeys();
         }
         final Canvas canvas = mCanvas;
         canvas.clipRect(mDirtyRect, Op.REPLACE);
@@ -874,13 +874,27 @@
         mPreviewText.setVisibility(VISIBLE);
     }
 
-    private void invalidateAll() {
+    /**
+     * Requests a redraw of the entire keyboard. Calling {@link #invalidate} is not sufficient
+     * because the keyboard renders the keys to an off-screen buffer and an invalidate() only 
+     * draws the cached buffer.
+     * @see #invalidateKey(int)
+     */
+    public void invalidateAllKeys() {
         mDirtyRect.union(0, 0, getWidth(), getHeight());
         mDrawPending = true;
         invalidate();
     }
-    
-    private void invalidateKey(int keyIndex) {
+
+    /**
+     * Invalidates a key so that it will be redrawn on the next repaint. Use this method if only
+     * one key is changing it's content. Any changes that affect the position or size of the key
+     * may not be honored.
+     * @param keyIndex the index of the key in the attached {@link Keyboard}.
+     * @see #invalidateAllKeys
+     */
+    public void invalidateKey(int keyIndex) {
+        if (mKeys == null) return;
         if (keyIndex < 0 || keyIndex >= mKeys.length) {
             return;
         }
@@ -991,7 +1005,7 @@
             mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y);
             mMiniKeyboardOnScreen = true;
             //mMiniKeyboard.onTouchEvent(getTranslatedEvent(me));
-            invalidateAll();
+            invalidateAllKeys();
             return true;
         }
         return false;
@@ -1164,7 +1178,7 @@
         if (mPopupKeyboard.isShowing()) {
             mPopupKeyboard.dismiss();
             mMiniKeyboardOnScreen = false;
-            invalidateAll();
+            invalidateAllKeys();
         }
     }