diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 4d952098c06f0ec98164027119e4ea482e97bf51..dc84763c1f8afe19dd18038f02171a65cff12fa0 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -349,7 +349,7 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions {
         return mKeyboardView;
     }
 
-    public View onCreateInputView() {
+    public View onCreateInputView(boolean isHardwareAcceleratedDrawingEnabled) {
         if (mKeyboardView != null) {
             mKeyboardView.closing();
         }
@@ -372,6 +372,10 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions {
         }
 
         mKeyboardView = (MainKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view);
+        if (isHardwareAcceleratedDrawingEnabled) {
+            mKeyboardView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            // TODO: Should use LAYER_TYPE_SOFTWARE when hardware acceleration is off?
+        }
         mKeyboardView.setKeyboardActionListener(mLatinIME);
         if (mForceNonDistinctMultitouch) {
             mKeyboardView.setDistinctMultitouch(false);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 6b1320d664935a7ea78e0a8b2dab231aab0ff4b0..69e4d98052278367d7b9fd2c890e99bcacea41d4 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -123,6 +123,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
     /** The working rectangle variable */
     private final Rect mWorkingRect = new Rect();
     /** The keyboard bitmap buffer for faster updates */
+    /** The clip region to draw keys */
+    private final Region mClipRegion = new Region();
     private Bitmap mOffscreenBuffer;
     /** The canvas for the above mutable keyboard bitmap */
     private Canvas mOffscreenCanvas;
@@ -457,10 +459,15 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
     @Override
     public void onDraw(Canvas canvas) {
         super.onDraw(canvas);
+        if (canvas.isHardwareAccelerated()) {
+            onDrawKeyboard(canvas);
+            return;
+        }
         if (mBufferNeedsUpdate || mOffscreenBuffer == null) {
             mBufferNeedsUpdate = false;
             if (maybeAllocateOffscreenBuffer()) {
                 mInvalidateAllKeys = true;
+                // TODO: Stop using the offscreen canvas even when in software rendering
                 if (mOffscreenCanvas != null) {
                     mOffscreenCanvas.setBitmap(mOffscreenBuffer);
                 } else {
@@ -502,35 +509,57 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
         final Paint paint = mPaint;
         final KeyDrawParams params = mKeyDrawParams;
 
-        if (mInvalidateAllKeys || mInvalidatedKeys.isEmpty()) {
-            mWorkingRect.set(0, 0, width, height);
-            canvas.clipRect(mWorkingRect, Region.Op.REPLACE);
-            canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
+        // Calculate clip region and set.
+        final boolean drawAllKeys = mInvalidateAllKeys || mInvalidatedKeys.isEmpty();
+        final boolean isHardwareAccelerated = canvas.isHardwareAccelerated();
+        // TODO: Confirm if it's really required to draw all keys when hardware acceleration is on.
+        if (drawAllKeys || isHardwareAccelerated) {
+            mClipRegion.set(0, 0, width, height);
+        } else {
+            mClipRegion.setEmpty();
+            for (final Key key : mInvalidatedKeys) {
+                if (mKeyboard.hasKey(key)) {
+                    final int x = key.mX + getPaddingLeft();
+                    final int y = key.mY + getPaddingTop();
+                    mWorkingRect.set(x, y, x + key.mWidth, y + key.mHeight);
+                    mClipRegion.union(mWorkingRect);
+                }
+            }
+        }
+        if (!isHardwareAccelerated) {
+            canvas.clipRegion(mClipRegion, Region.Op.REPLACE);
+        }
+
+        // Draw keyboard background.
+        canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
+        final Drawable background = getBackground();
+        if (background != null) {
+            background.draw(canvas);
+        }
+
+        // TODO: Confirm if it's really required to draw all keys when hardware acceleration is on.
+        if (drawAllKeys || isHardwareAccelerated) {
             // Draw all keys.
             for (final Key key : mKeyboard.mKeys) {
                 onDrawKey(key, canvas, paint, params);
             }
-            if (mNeedsToDimEntireKeyboard) {
-                drawDimRectangle(canvas, mWorkingRect, mBackgroundDimAlpha, paint);
-            }
         } else {
             // Draw invalidated keys.
             for (final Key key : mInvalidatedKeys) {
-                if (!mKeyboard.hasKey(key)) {
-                    continue;
-                }
-                final int x = key.mX + getPaddingLeft();
-                final int y = key.mY + getPaddingTop();
-                mWorkingRect.set(x, y, x + key.mWidth, y + key.mHeight);
-                canvas.clipRect(mWorkingRect, Region.Op.REPLACE);
-                canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
-                onDrawKey(key, canvas, paint, params);
-                if (mNeedsToDimEntireKeyboard) {
-                    drawDimRectangle(canvas, mWorkingRect, mBackgroundDimAlpha, paint);
+                if (mKeyboard.hasKey(key)) {
+                    onDrawKey(key, canvas, paint, params);
                 }
             }
         }
 
+        // Overlay a dark rectangle to dim.
+        if (mNeedsToDimEntireKeyboard) {
+            paint.setColor(Color.BLACK);
+            paint.setAlpha(mBackgroundDimAlpha);
+            // Note: clipRegion() above is in effect if it was called.
+            canvas.drawRect(0, 0, width, height, paint);
+        }
+
         // ResearchLogging indicator.
         // TODO: Reimplement using a keyboard background image specific to the ResearchLogger,
         // and remove this call.
@@ -863,13 +892,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
         canvas.translate(-x, -y);
     }
 
-    // Overlay a dark rectangle to dim.
-    private static void drawDimRectangle(Canvas canvas, Rect rect, int alpha, Paint paint) {
-        paint.setColor(Color.BLACK);
-        paint.setAlpha(alpha);
-        canvas.drawRect(rect, paint);
-    }
-
     public Paint newDefaultLabelPaint() {
         final Paint paint = new Paint();
         paint.setAntiAlias(true);
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 8dc1081f5dbaf78dfed0e88fb33d6fdeacbba525..a711ab9978dcdeb96f373d21010fca1721f7e1a5 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -553,7 +553,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
     @Override
     public View onCreateInputView() {
-        return mKeyboardSwitcher.onCreateInputView();
+        return mKeyboardSwitcher.onCreateInputView(mIsHardwareAcceleratedDrawingEnabled);
     }
 
     @Override