Merge "Integreate surfacetexture test into our continuous test framework."
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index f8d0142..75dcd6e 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -415,6 +415,9 @@
         }
 
         if (params.mBytesWritten < params.mAudioBufferSize) {
+            if (DBG) Log.d(TAG, "Stopping audio track to flush audio, state was : " +
+                    audioTrack.getPlayState());
+            params.mIsShortUtterance = true;
             audioTrack.stop();
         }
 
@@ -452,10 +455,40 @@
             return;
         }
 
+        if (params.mIsShortUtterance) {
+            // In this case we would have called AudioTrack#stop() to flush
+            // buffers to the mixer. This makes the playback head position
+            // unobservable and notification markers do not work reliably. We
+            // have no option but to wait until we think the track would finish
+            // playing and release it after.
+            //
+            // This isn't as bad as it looks because (a) We won't end up waiting
+            // for much longer than we should because even at 4khz mono, a short
+            // utterance weighs in at about 2 seconds, and (b) such short utterances
+            // are expected to be relatively infrequent and in a stream of utterances
+            // this shows up as a slightly longer pause.
+            blockUntilEstimatedCompletion(params);
+        } else {
+            blockUntilCompletion(params);
+        }
+    }
+
+    private static void blockUntilEstimatedCompletion(SynthesisMessageParams params) {
+        final int lengthInFrames = params.mBytesWritten / params.mBytesPerFrame;
+        final long estimatedTimeMs = (lengthInFrames * 1000 / params.mSampleRateInHz);
+
+        if (DBG) Log.d(TAG, "About to sleep for: " + estimatedTimeMs + "ms for a short utterance");
+
+        try {
+            Thread.sleep(estimatedTimeMs);
+        } catch (InterruptedException ie) {
+            // Do nothing.
+        }
+    }
+
+    private static void blockUntilCompletion(SynthesisMessageParams params) {
         final AudioTrack audioTrack = params.mAudioTrack;
-        final int bytesPerFrame = params.mBytesPerFrame;
-        final int lengthInBytes = params.mBytesWritten;
-        final int lengthInFrames = lengthInBytes / bytesPerFrame;
+        final int lengthInFrames = params.mBytesWritten / params.mBytesPerFrame;
 
         int currentPosition = 0;
         while ((currentPosition = audioTrack.getPlaybackHeadPosition()) < lengthInFrames) {
diff --git a/core/java/android/speech/tts/SynthesisMessageParams.java b/core/java/android/speech/tts/SynthesisMessageParams.java
index 3e905d6..779721e 100644
--- a/core/java/android/speech/tts/SynthesisMessageParams.java
+++ b/core/java/android/speech/tts/SynthesisMessageParams.java
@@ -41,7 +41,13 @@
     // Written by the synthesis thread, but read on the audio playback
     // thread.
     volatile int mBytesWritten;
+    // A "short utterance" is one that uses less bytes than the audio
+    // track buffer size (mAudioBufferSize). In this case, we need to call
+    // AudioTrack#stop() to send pending buffers to the mixer, and slightly
+    // different logic is required to wait for the track to finish.
+    //
     // Not volatile, accessed only from the audio playback thread.
+    boolean mIsShortUtterance;
     int mAudioBufferSize;
     // Always synchronized on "this".
     int mUnconsumedBytes;
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index ae81537..3880bc45 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -446,7 +446,9 @@
     /** @hide */
     public native   void setLayer(int zorder);
     /** @hide */
-    public native   void setPosition(int x, int y);
+    public void setPosition(int x, int y) { setPosition((float)x, (float)y); }
+    /** @hide */
+    public native   void setPosition(float x, float y);
     /** @hide */
     public native   void setSize(int w, int h);
     /** @hide */
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index da5baf8..302be57 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1583,6 +1583,14 @@
     /**
      * Set additional input method subtypes. Only a process which shares the same uid with the IME
      * can add additional input method subtypes to the IME.
+     * Please note that a subtype's status is stored in the system.
+     * For example, enabled subtypes are remembered by the framework even after they are removed
+     * by using this method. If you re-add the same subtypes again,
+     * they will just get enabled. If you want to avoid such conflicts, for instance, you may
+     * want to create a "different" new subtype even with the same locale and mode,
+     * by changing its extra value. The different subtype won't get affected by the stored past
+     * status. (You may want to take a look at {@link InputMethodSubtype#hashCode()} to refer
+     * to the current implementation.)
      * @param imiId Id of InputMethodInfo which additional input method subtypes will be added to.
      * @param subtypes subtypes will be added as additional subtypes of the current input method.
      * @return true if the additional input method subtypes are successfully added.
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index c85b2d9..01587aa 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -66,7 +66,13 @@
 
     /**
      * Get a spell checker session for the specified spell checker
-     * @param locale the locale for the spell checker
+     * @param locale the locale for the spell checker. If {@param locale} is null and
+     * referToSpellCheckerLanguageSettings is true, the locale specified in Settings will be
+     * returned. If {@param locale} is not null and referToSpellCheckerLanguageSettings is true,
+     * the locale specified in Settings will be returned only when it is same as {@param locale}.
+     * Exceptionally, when referToSpellCheckerLanguageSettings is true and {@param locale} is
+     * only language (e.g. "en"), the specified locale in Settings (e.g. "en_US") will be
+     * selected.
      * @param listener a spell checker session lister for getting results from a spell checker.
      * @param referToSpellCheckerLanguageSettings if true, the session for one of enabled
      * languages in settings will be returned.
@@ -81,6 +87,11 @@
             throw new IllegalArgumentException("Locale should not be null if you don't refer"
                     + " settings.");
         }
+
+        if (referToSpellCheckerLanguageSettings && !isSpellCheckerEnabled()) {
+            return null;
+        }
+
         final SpellCheckerInfo sci;
         try {
             sci = sService.getCurrentSpellChecker(null);
@@ -108,7 +119,12 @@
             final String localeStr = locale.toString();
             for (int i = 0; i < sci.getSubtypeCount(); ++i) {
                 final SpellCheckerSubtype subtype = sci.getSubtypeAt(i);
-                if (subtype.getLocale().equals(localeStr)) {
+                final String tempSubtypeLocale = subtype.getLocale();
+                if (tempSubtypeLocale.equals(localeStr)) {
+                    subtypeInUse = subtype;
+                    break;
+                } else if (localeStr.length() >= 2 && tempSubtypeLocale.length() >= 2
+                        && localeStr.startsWith(tempSubtypeLocale)) {
                     subtypeInUse = subtype;
                 }
             }
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 4c1ca31..49441eb 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -589,7 +589,7 @@
 }
 
 static void Surface_setPosition(
-        JNIEnv* env, jobject clazz, jint x, jint y)
+        JNIEnv* env, jobject clazz, jfloat x, jfloat y)
 {
     const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
     if (surface == 0) return;
@@ -832,7 +832,7 @@
     {"screenshot",          "(II)Landroid/graphics/Bitmap;", (void*)Surface_screenshotAll },
     {"screenshot",          "(IIII)Landroid/graphics/Bitmap;", (void*)Surface_screenshot },
     {"setLayer",            "(I)V", (void*)Surface_setLayer },
-    {"setPosition",         "(II)V",(void*)Surface_setPosition },
+    {"setPosition",         "(FF)V",(void*)Surface_setPosition },
     {"setSize",             "(II)V",(void*)Surface_setSize },
     {"hide",                "()V",  (void*)Surface_hide },
     {"show",                "()V",  (void*)Surface_show },
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index 94a8488..7c4e147 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -55,7 +55,7 @@
 
     private void init() {
         final AnimatedRotateState state = mState;
-        mIncrement = 360.0f / (float) state.mFramesCount;
+        mIncrement = 360.0f / state.mFramesCount;
         final Drawable drawable = state.mDrawable;
         if (drawable != null) {
             drawable.setFilterBitmap(true);
@@ -65,6 +65,7 @@
         }
     }
 
+    @Override
     public void draw(Canvas canvas) {
         int saveCount = canvas.save();
 
@@ -146,14 +147,17 @@
                 | mState.mDrawable.getChangingConfigurations();
     }
     
+    @Override
     public void setAlpha(int alpha) {
         mState.mDrawable.setAlpha(alpha);
     }
 
+    @Override
     public void setColorFilter(ColorFilter cf) {
         mState.mDrawable.setColorFilter(cf);
     }
 
+    @Override
     public int getOpacity() {
         return mState.mDrawable.getOpacity();
     }
@@ -228,10 +232,10 @@
         tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY);
         final boolean pivotYRel = tv.type == TypedValue.TYPE_FRACTION;
         final float pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
-        
-        final int framesCount = a.getInt(R.styleable.AnimatedRotateDrawable_framesCount, 12);
-        final int frameDuration = a.getInt(R.styleable.AnimatedRotateDrawable_frameDuration, 150);
-        
+
+        setFramesCount(a.getInt(R.styleable.AnimatedRotateDrawable_framesCount, 12));
+        setFramesDuration(a.getInt(R.styleable.AnimatedRotateDrawable_frameDuration, 150));
+
         final int res = a.getResourceId(R.styleable.AnimatedRotateDrawable_drawable, 0);
         Drawable drawable = null;
         if (res > 0) {
@@ -265,8 +269,6 @@
         rotateState.mPivotX = pivotX;
         rotateState.mPivotYRel = pivotYRel;
         rotateState.mPivotY = pivotY;
-        rotateState.mFramesCount = framesCount;
-        rotateState.mFrameDuration = frameDuration;
 
         init();
 
@@ -275,6 +277,15 @@
         }
     }
 
+    public void setFramesCount(int framesCount) {
+        mState.mFramesCount = framesCount;
+        mIncrement = 360.0f / mState.mFramesCount;
+    }
+
+    public void setFramesDuration(int framesDuration) {
+        mState.mFrameDuration = framesDuration;
+    }
+
     @Override
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
diff --git a/include/private/surfaceflinger/LayerState.h b/include/private/surfaceflinger/LayerState.h
index d2fed41..3eb5c99 100644
--- a/include/private/surfaceflinger/LayerState.h
+++ b/include/private/surfaceflinger/LayerState.h
@@ -54,8 +54,8 @@
             };
             SurfaceID       surface;
             uint32_t        what;
-            int32_t         x;
-            int32_t         y;
+            float           x;
+            float           y;
             uint32_t        z;
             uint32_t        w;
             uint32_t        h;
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index 7fbbfb24..ace0735 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -145,7 +145,7 @@
     status_t    setAlpha(SurfaceID id, float alpha=1.0f);
     status_t    setFreezeTint(SurfaceID id, uint32_t tint);
     status_t    setMatrix(SurfaceID id, float dsdx, float dtdx, float dsdy, float dtdy);
-    status_t    setPosition(SurfaceID id, int32_t x, int32_t y);
+    status_t    setPosition(SurfaceID id, float x, float y);
     status_t    setSize(SurfaceID id, uint32_t w, uint32_t h);
     status_t    destroySurface(SurfaceID sid);
 
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 3b0ffea..00a4bf6 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -102,7 +102,7 @@
 public:
 
     status_t setPosition(const sp<SurfaceComposerClient>& client, SurfaceID id,
-            int32_t x, int32_t y);
+            float x, float y);
     status_t setSize(const sp<SurfaceComposerClient>& client, SurfaceID id,
             uint32_t w, uint32_t h);
     status_t setLayer(const sp<SurfaceComposerClient>& client, SurfaceID id,
@@ -161,7 +161,7 @@
 }
 
 status_t Composer::setPosition(const sp<SurfaceComposerClient>& client,
-        SurfaceID id, int32_t x, int32_t y) {
+        SurfaceID id, float x, float y) {
     Mutex::Autolock _l(mLock);
     layer_state_t* s = getLayerStateLocked(client, id);
     if (!s)
@@ -372,7 +372,7 @@
     return getComposer().setFreezeTint(this, id, tint);
 }
 
-status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y) {
+status_t SurfaceComposerClient::setPosition(SurfaceID id, float x, float y) {
     return getComposer().setPosition(this, id, x, y);
 }
 
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index d59bc2b..d7b85e4 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -22,6 +22,7 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.RectF;
+import android.media.MediaMetadataRetriever;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -29,6 +30,7 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.lang.IllegalArgumentException;
 import java.util.HashMap;
 
 /**
@@ -236,6 +238,23 @@
         mEventHandler = new EventHandler(this, looper);
     }
 
+    private static final int[] METADATA_KEYS_TYPE_STRING = {
+        MediaMetadataRetriever.METADATA_KEY_ALBUM,
+        MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
+        MediaMetadataRetriever.METADATA_KEY_TITLE,
+        MediaMetadataRetriever.METADATA_KEY_ARTIST,
+        MediaMetadataRetriever.METADATA_KEY_AUTHOR,
+        MediaMetadataRetriever.METADATA_KEY_COMPILATION,
+        MediaMetadataRetriever.METADATA_KEY_COMPOSER,
+        MediaMetadataRetriever.METADATA_KEY_DATE,
+        MediaMetadataRetriever.METADATA_KEY_GENRE,
+        MediaMetadataRetriever.METADATA_KEY_TITLE,
+        MediaMetadataRetriever.METADATA_KEY_WRITER };
+    private static final int[] METADATA_KEYS_TYPE_LONG = {
+        MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
+        MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
+        MediaMetadataRetriever.METADATA_KEY_DURATION };
+
     /**
      * Class used to modify metadata in a {@link RemoteControlClient} object.
      */
@@ -256,6 +275,11 @@
         }
 
         /**
+         * The metadata key for the content artwork / album art.
+         */
+        public final static int METADATA_KEY_ARTWORK = 100;
+
+        /**
          * Adds textual information to be displayed.
          * Note that none of the information added after {@link #apply()} has been called,
          * will be displayed.
@@ -265,49 +289,73 @@
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
-         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
-         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
-         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER},
-         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
-         * @param value the text for the given key, or null to signify there is no valid
+         *      .
+         * @param value the text for the given key, or {@code null} to signify there is no valid
          *      information for the field.
          * @return      FIXME description
          */
-        public synchronized MetadataEditor putString(int key, String value) {
+        public synchronized MetadataEditor putString(int key, String value)
+                throws IllegalArgumentException {
             if (mApplied) {
                 Log.e(TAG, "Can't edit a previously applied MetadataEditor");
                 return this;
             }
+            if (!validTypeForKey(key, METADATA_KEYS_TYPE_STRING)) {
+                throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
+            }
             mEditorMetadata.putString(String.valueOf(key), value);
             mMetadataChanged = true;
             return this;
         }
 
         /**
-         * The metadata key for the content artwork / album art.
+         * FIXME javadoc
+         * @param key the identifier of a the metadata field to set. Valid values are
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
+         *      expressed in milliseconds),
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
+         * @param value FIXME javadoc
+         * @return FIXME javadoc
+         * @throws IllegalArgumentException
          */
-        public final int METADATA_KEY_ARTWORK = 100;
+        public synchronized MetadataEditor putLong(int key, long value)
+                throws IllegalArgumentException {
+            if (mApplied) {
+                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
+                return this;
+            }
+            if (!validTypeForKey(key, METADATA_KEYS_TYPE_LONG)) {
+                throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
+            }
+            mEditorMetadata.putLong(String.valueOf(key), value);
+            mMetadataChanged = true;
+            return this;
+        }
 
         /**
          * Sets the album / artwork picture to be displayed on the remote control.
          * @param key FIXME description
          * @param bitmap the bitmap for the artwork, or null if there isn't any.
          * @return FIXME description
+         * @throws IllegalArgumentException
          * @see android.graphics.Bitmap
          */
-        public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap) {
+        public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap)
+                throws IllegalArgumentException {
             if (mApplied) {
                 Log.e(TAG, "Can't edit a previously applied MetadataEditor");
                 return this;
             }
             if (key != METADATA_KEY_ARTWORK) {
-                return this;
+                throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
             }
             if ((mArtworkExpectedWidth > 0) && (mArtworkExpectedHeight > 0)) {
                 mEditorArtwork = scaleBitmapIfTooBig(bitmap,
@@ -740,6 +788,24 @@
             }
         }
         return bitmap;
+    }
 
+    /**
+     *  Fast routine to go through an array of allowed keys and return whether the key is part
+     *  of that array
+     * @param key the key value
+     * @param validKeys the array of valid keys for a given type
+     * @return true if the key is part of the array, false otherwise
+     */
+    private static boolean validTypeForKey(int key, int[] validKeys) {
+        try {
+            for (int i = 0 ; ; i++) {
+                if (key == validKeys[i]) {
+                    return true;
+                }
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            return false;
+        }
     }
 }
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index ed13ace..f3d0bee 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -71,6 +71,7 @@
         </LinearLayout>
 
         <com.android.systemui.statusbar.policy.Clock
+            android:id="@+id/clock"
             android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 6e6567b..e3ea0de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1060,6 +1060,12 @@
         */
     }
 
+    public void showClock(boolean show) {
+        View clock = mStatusBarView.findViewById(R.id.clock);
+        if (clock != null) {
+            clock.setVisibility(show ? View.VISIBLE : View.GONE);
+        }
+    }
 
     /**
      * State is one or more of the DISABLE constants from StatusBarManager.
@@ -1074,6 +1080,10 @@
                 old, state, diff));
         }
 
+        if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
+            boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
+            showClock(show);
+        }
         if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
             if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
                 Slog.d(TAG, "DISABLE_EXPAND: yes");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
index 1e417ac..5911378 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
@@ -428,7 +428,7 @@
 
     private CharSequence getIMIName(InputMethodInfo imi) {
         if (imi == null) return null;
-        return mPackageManager.getApplicationLabel(imi.getServiceInfo().applicationInfo);
+        return imi.loadLabel(mPackageManager);
     }
 
     private CharSequence getSubtypeName(InputMethodInfo imi, InputMethodSubtype subtype) {
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 5661116..162381d 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -145,10 +145,10 @@
     private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000;
 
     /**
-     * Allow the user to operate the status bar when the keyguard is engaged (without a pattern or
-     * password).
+     * Allow the user to expand the status bar when the keyguard is engaged
+     * (without a pattern or password).
      */
-    private static final boolean ENABLE_STATUS_BAR_IN_KEYGUARD = true;
+    private static final boolean ENABLE_INSECURE_STATUS_BAR_EXPAND = true;
 
     private Context mContext;
     private AlarmManager mAlarmManager;
@@ -1184,19 +1184,25 @@
                 }
             }
 
-            // if the keyguard is shown, allow the status bar to open only if the keyguard is
-            // insecure and (is covered by another window OR this feature is enabled in general)
-            boolean enable = !mShowing
-                || ((ENABLE_STATUS_BAR_IN_KEYGUARD || mHidden) && !isSecure());
-            if (DEBUG) {
-                Log.d(TAG, "adjustStatusBarLocked: mShowing=" + mShowing + " mHidden=" + mHidden
-                    + " isSecure=" + isSecure() + " --> enable=" + enable);
+            int flags = StatusBarManager.DISABLE_NONE;
+            if (mShowing && !mHidden) {
+                // showing lockscreen exclusively; disable various extra
+                // statusbar components.
+                flags |= StatusBarManager.DISABLE_NAVIGATION;
+                flags |= StatusBarManager.DISABLE_CLOCK;
             }
-            mStatusBarManager.disable(enable ?
-                         StatusBarManager.DISABLE_NONE :
-                         ( StatusBarManager.DISABLE_EXPAND
-                         | StatusBarManager.DISABLE_NAVIGATION
-                         | StatusBarManager.DISABLE_CLOCK));
+            if (mShowing && (isSecure() || !ENABLE_INSECURE_STATUS_BAR_EXPAND)) {
+                // showing secure lockscreen; disable expanding.
+                flags |= StatusBarManager.DISABLE_EXPAND;
+            }
+
+            if (DEBUG) {
+                Log.d(TAG,
+                        "adjustStatusBarLocked: mShowing=" + mShowing + " mHidden=" + mHidden
+                                + " isSecure=" + isSecure() + " --> flags=" + flags);
+            }
+
+            mStatusBarManager.disable(flags);
         }
     }
 
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 38bcebc..bb831f5 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1682,7 +1682,12 @@
                 for (int i = 0; i < packageNum; ++i) {
                     if (packageInfos[i].equals(imi.getPackageName())) {
                         mFileManager.addInputMethodSubtypes(imi, subtypes);
-                        buildInputMethodListLocked(mMethodList, mMethodMap);
+                        final long ident = Binder.clearCallingIdentity();
+                        try {
+                            buildInputMethodListLocked(mMethodList, mMethodMap);
+                        } finally {
+                            Binder.restoreCallingIdentity(ident);
+                        }
                         return true;
                     }
                 }
@@ -1707,7 +1712,7 @@
                 return;
             }
 
-            long ident = Binder.clearCallingIdentity();
+            final long ident = Binder.clearCallingIdentity();
             try {
                 setInputMethodLocked(id, subtypeId);
             } finally {
@@ -3065,17 +3070,11 @@
         public void addInputMethodSubtypes(
                 InputMethodInfo imi, InputMethodSubtype[] additionalSubtypes) {
             synchronized (mMethodMap) {
-                final HashSet<InputMethodSubtype> existingSubtypes =
-                        new HashSet<InputMethodSubtype>();
-                for (int i = 0; i < imi.getSubtypeCount(); ++i) {
-                    existingSubtypes.add(imi.getSubtypeAt(i));
-                }
-
                 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
                 final int N = additionalSubtypes.length;
                 for (int i = 0; i < N; ++i) {
                     final InputMethodSubtype subtype = additionalSubtypes[i];
-                    if (!subtypes.contains(subtype) && !existingSubtypes.contains(subtype)) {
+                    if (!subtypes.contains(subtype)) {
                         subtypes.add(subtype);
                     }
                 }
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index f6c369e..c792b33 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -201,7 +201,7 @@
                     Settings.Secure.getString(mContext.getContentResolver(),
                             Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE);
             if (DBG) {
-                Slog.w(TAG, "getCurrentSpellChecker: " + subtypeHashCodeStr);
+                Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCodeStr);
             }
             final SpellCheckerInfo sci = getCurrentSpellChecker(null);
             if (sci == null || sci.getSubtypeCount() == 0) {
@@ -509,7 +509,8 @@
                                 listener.mScLocale, listener.mScListener, listener.mBundle);
                         listener.mTsListener.onServiceConnected(session);
                     } catch (RemoteException e) {
-                        Slog.e(TAG, "Exception in getting the spell checker session: " + e);
+                        Slog.e(TAG, "Exception in getting the spell checker session."
+                                + "Reconnect to the spellchecker. ", e);
                         removeAll();
                         return;
                     }
@@ -579,8 +580,12 @@
                 Slog.d(TAG, "cleanLocked");
             }
             if (mListeners.isEmpty()) {
-                if (mSpellCheckerBindGroups.containsKey(this)) {
-                    mSpellCheckerBindGroups.remove(this);
+                final String sciId = mInternalConnection.mSciId;
+                if (mSpellCheckerBindGroups.containsKey(sciId)) {
+                    if (DBG) {
+                        Slog.d(TAG, "Remove bind group.");
+                    }
+                    mSpellCheckerBindGroups.remove(sciId);
                 }
                 // Unbind service when there is no active clients.
                 mContext.unbindService(mInternalConnection);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f8925b8..edbc7b0 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -212,6 +212,24 @@
     } else {
         hwcl->transform = finalTransform;
     }
+
+    if (isCropped()) {
+        hwcl->sourceCrop.left   = mCurrentCrop.left;
+        hwcl->sourceCrop.top    = mCurrentCrop.top;
+        hwcl->sourceCrop.right  = mCurrentCrop.right;
+        hwcl->sourceCrop.bottom = mCurrentCrop.bottom;
+    } else {
+        const sp<GraphicBuffer>& buffer(mActiveBuffer);
+        hwcl->sourceCrop.left   = 0;
+        hwcl->sourceCrop.top    = 0;
+        if (buffer != NULL) {
+            hwcl->sourceCrop.right  = buffer->width;
+            hwcl->sourceCrop.bottom = buffer->height;
+        } else {
+            hwcl->sourceCrop.right  = mTransformedBounds.width();
+            hwcl->sourceCrop.bottom = mTransformedBounds.height();
+        }
+    }
 }
 
 void Layer::setPerFrameData(hwc_layer_t* hwcl) {
@@ -225,23 +243,6 @@
     } else {
         hwcl->handle = buffer->handle;
     }
-
-    if (isCropped()) {
-        hwcl->sourceCrop.left   = mCurrentCrop.left;
-        hwcl->sourceCrop.top    = mCurrentCrop.top;
-        hwcl->sourceCrop.right  = mCurrentCrop.right;
-        hwcl->sourceCrop.bottom = mCurrentCrop.bottom;
-    } else {
-        hwcl->sourceCrop.left   = 0;
-        hwcl->sourceCrop.top    = 0;
-        if (buffer != NULL) {
-            hwcl->sourceCrop.right  = buffer->width;
-            hwcl->sourceCrop.bottom = buffer->height;
-        } else {
-            hwcl->sourceCrop.right  = mTransformedBounds.width();
-            hwcl->sourceCrop.bottom = mTransformedBounds.height();
-        }
-    }
 }
 
 void Layer::onDraw(const Region& clip) const
@@ -416,8 +417,7 @@
             return;
         }
 
-        mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
-        mSurfaceTexture->getTransformMatrix(mTextureMatrix);
+        sp<GraphicBuffer> newFrontBuffer(mSurfaceTexture->getCurrentBuffer());
 
         const Rect crop(mSurfaceTexture->getCurrentCrop());
         const uint32_t transform(mSurfaceTexture->getCurrentTransform());
@@ -432,7 +432,23 @@
             mFlinger->invalidateHwcGeometry();
         }
 
-        mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
+        GLfloat textureMatrix[16];
+        mSurfaceTexture->getTransformMatrix(textureMatrix);
+        if (memcmp(textureMatrix, mTextureMatrix, sizeof(textureMatrix))) {
+            memcpy(mTextureMatrix, textureMatrix, sizeof(textureMatrix));
+            mFlinger->invalidateHwcGeometry();
+        }
+
+        uint32_t bufWidth  = newFrontBuffer->getWidth();
+        uint32_t bufHeight = newFrontBuffer->getHeight();
+        if (mActiveBuffer != NULL) {
+            if (bufWidth != uint32_t(mActiveBuffer->width) ||
+                bufHeight != uint32_t(mActiveBuffer->height)) {
+                mFlinger->invalidateHwcGeometry();
+            }
+        }
+
+        mCurrentOpacity = getOpacityForFormat(newFrontBuffer->format);
         if (oldOpacity != isOpaque()) {
             recomputeVisibleRegions = true;
         }
@@ -446,15 +462,14 @@
         // FIXME: mPostedDirtyRegion = dirty & bounds
         mPostedDirtyRegion.set(front.w, front.h);
 
+        // update active buffer
+        mActiveBuffer = newFrontBuffer;
 
         if ((front.w != front.requested_w) ||
             (front.h != front.requested_h))
         {
             // check that we received a buffer of the right size
             // (Take the buffer's orientation into account)
-            sp<GraphicBuffer> newFrontBuffer(mActiveBuffer);
-            uint32_t bufWidth  = newFrontBuffer->getWidth();
-            uint32_t bufHeight = newFrontBuffer->getHeight();
             if (mCurrentTransform & Transform::ROT_90) {
                 swap(bufWidth, bufHeight);
             }
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 4cc245a..603fb60 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -45,7 +45,6 @@
       mFlinger(flinger), mFiltering(false),
       mNeedsFiltering(false),
       mOrientation(0),
-      mLeft(0), mTop(0),
       mTransactionFlags(0),
       mPremultipliedAlpha(true), mName("unnamed"), mDebug(false),
       mInvalidate(0)
@@ -119,7 +118,7 @@
     return android_atomic_or(flags, &mTransactionFlags);
 }
 
-bool LayerBase::setPosition(int32_t x, int32_t y) {
+bool LayerBase::setPosition(float x, float y) {
     if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
         return false;
     mCurrentState.sequence++;
@@ -259,8 +258,6 @@
     mOrientation = tr.getOrientation();
     mTransform = tr;
     mTransformedBounds = tr.makeBounds(w, h);
-    mLeft = tr.tx();
-    mTop  = tr.ty();
 }
 
 void LayerBase::lockPageFlip(bool& recomputeVisibleRegions)
@@ -335,15 +332,16 @@
             reinterpret_cast<hwc_rect_t const *>(
                     visibleRegionScreen.getArray(
                             &hwcl->visibleRegionScreen.numRects));
+
+    hwcl->sourceCrop.left   = 0;
+    hwcl->sourceCrop.top    = 0;
+    hwcl->sourceCrop.right  = mTransformedBounds.width();
+    hwcl->sourceCrop.bottom = mTransformedBounds.height();
 }
 
 void LayerBase::setPerFrameData(hwc_layer_t* hwcl) {
     hwcl->compositionType = HWC_FRAMEBUFFER;
     hwcl->handle = NULL;
-    hwcl->sourceCrop.left   = 0;
-    hwcl->sourceCrop.top    = 0;
-    hwcl->sourceCrop.right  = mTransformedBounds.width();
-    hwcl->sourceCrop.bottom = mTransformedBounds.height();
 }
 
 void LayerBase::setFiltering(bool filtering)
@@ -476,10 +474,10 @@
     snprintf(buffer, SIZE,
             "+ %s %p\n"
             "      "
-            "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
+            "z=%9d, pos=(%g,%g), size=(%4d,%4d), "
             "isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
             "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
-            getTypeId(), this, s.z, tx(), ty(), s.w, s.h,
+            getTypeId(), this, s.z, s.transform.tx(), s.transform.ty(), s.w, s.h,
             isOpaque(), needsDithering(), contentDirty,
             s.alpha, s.flags,
             s.transform[0][0], s.transform[0][1],
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 2cd3a94..d20f06a 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -84,7 +84,7 @@
             String8 getName() const;
 
             // modify current state
-            bool setPosition(int32_t x, int32_t y);
+            bool setPosition(float x, float y);
             bool setLayer(uint32_t z);
             bool setSize(uint32_t w, uint32_t h);
             bool setAlpha(uint8_t alpha);
@@ -217,8 +217,6 @@
     inline  State&          currentState()          { return mCurrentState; }
 
     int32_t  getOrientation() const { return mOrientation; }
-    int  tx() const             { return mLeft; }
-    int  ty() const             { return mTop; }
     
 protected:
     const GraphicPlane& graphicPlane(int dpy) const;
@@ -250,8 +248,6 @@
                 Transform       mTransform;
                 GLfloat         mVertices[4][2];
                 Rect            mTransformedBounds;
-                int             mLeft;
-                int             mTop;
             
                 // these are protected by an external lock
                 State           mCurrentState;
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index 05b7527..ba345ce 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -91,12 +91,12 @@
     return type() > TRANSLATE;
 }
 
-int Transform::tx() const {
-    return floorf(mMatrix[2][0] + 0.5f);
+float Transform::tx() const {
+    return mMatrix[2][0];
 }
 
-int Transform::ty() const {
-    return floorf(mMatrix[2][1] + 0.5f);
+float Transform::ty() const {
+    return mMatrix[2][1];
 }
 
 void Transform::reset() {
@@ -239,7 +239,9 @@
             out.set(transform(reg.bounds()));
         }
     } else {
-        out = reg.translate(tx(), ty());
+        int xpos = floorf(tx() + 0.5f);
+        int ypos = floorf(ty() + 0.5f);
+        out = reg.translate(xpos, ypos);
     }
     return out;
 }
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
index 8fa5b86..ec74243 100644
--- a/services/surfaceflinger/Transform.h
+++ b/services/surfaceflinger/Transform.h
@@ -64,8 +64,8 @@
             uint32_t    getOrientation() const;
 
             float const* operator [] (int i) const;  // returns column i
-            int     tx() const;
-            int     ty() const;
+            float   tx() const;
+            float   ty() const;
 
             // modify the transform
             void        reset();