Merge "fix race condition when a new display is added" into klp-dev
diff --git a/api/current.txt b/api/current.txt
index 6026cc5..ff47557 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2338,17 +2338,23 @@
   public abstract class Animator implements java.lang.Cloneable {
     ctor public Animator();
     method public void addListener(android.animation.Animator.AnimatorListener);
+    method public void addPauseListener(android.animation.Animator.AnimatorPauseListener);
     method public void cancel();
     method public android.animation.Animator clone();
     method public void end();
     method public abstract long getDuration();
     method public android.animation.TimeInterpolator getInterpolator();
     method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners();
+    method public java.util.ArrayList<android.animation.Animator.AnimatorPauseListener> getPauseListeners();
     method public abstract long getStartDelay();
+    method public boolean isPaused();
     method public abstract boolean isRunning();
     method public boolean isStarted();
+    method public void pause();
     method public void removeAllListeners();
     method public void removeListener(android.animation.Animator.AnimatorListener);
+    method public void removePauseListener(android.animation.Animator.AnimatorPauseListener);
+    method public void resume();
     method public abstract android.animation.Animator setDuration(long);
     method public abstract void setInterpolator(android.animation.TimeInterpolator);
     method public abstract void setStartDelay(long);
@@ -2365,16 +2371,23 @@
     method public abstract void onAnimationStart(android.animation.Animator);
   }
 
+  public static abstract interface Animator.AnimatorPauseListener {
+    method public abstract void onAnimationPause(android.animation.Animator);
+    method public abstract void onAnimationResume(android.animation.Animator);
+  }
+
   public class AnimatorInflater {
     ctor public AnimatorInflater();
     method public static android.animation.Animator loadAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
   }
 
-  public abstract class AnimatorListenerAdapter implements android.animation.Animator.AnimatorListener {
+  public abstract class AnimatorListenerAdapter implements android.animation.Animator.AnimatorListener android.animation.Animator.AnimatorPauseListener {
     ctor public AnimatorListenerAdapter();
     method public void onAnimationCancel(android.animation.Animator);
     method public void onAnimationEnd(android.animation.Animator);
+    method public void onAnimationPause(android.animation.Animator);
     method public void onAnimationRepeat(android.animation.Animator);
+    method public void onAnimationResume(android.animation.Animator);
     method public void onAnimationStart(android.animation.Animator);
   }
 
@@ -18741,7 +18754,7 @@
     method public android.print.PrintDocumentInfo.Builder setPageCount(int);
   }
 
-  public final class PrintFileDocumentAdapter extends android.print.PrintDocumentAdapter {
+  public class PrintFileDocumentAdapter extends android.print.PrintDocumentAdapter {
     ctor public PrintFileDocumentAdapter(android.content.Context, java.io.File, android.print.PrintDocumentInfo);
     method public void onLayout(android.print.PrintAttributes, android.print.PrintAttributes, android.os.CancellationSignal, android.print.PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle);
     method public void onWrite(android.print.PageRange[], java.io.FileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback);
@@ -25819,7 +25832,9 @@
     method public android.view.InputDevice.MotionRange getMotionRange(int, int);
     method public java.util.List<android.view.InputDevice.MotionRange> getMotionRanges();
     method public java.lang.String getName();
+    method public int getProductId();
     method public int getSources();
+    method public int getVendorId();
     method public android.os.Vibrator getVibrator();
     method public boolean isVirtual();
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 39eb8d6..89accbb 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -30,6 +30,17 @@
     ArrayList<AnimatorListener> mListeners = null;
 
     /**
+     * The set of listeners to be sent pause/resume events through the life
+     * of an animation.
+     */
+    ArrayList<AnimatorPauseListener> mPauseListeners = null;
+
+    /**
+     * Whether this animator is currently in a paused state.
+     */
+    boolean mPaused = false;
+
+    /**
      * Starts this animation. If the animation has a nonzero startDelay, the animation will start
      * running after that delay elapses. A non-delayed animation will have its initial
      * value(s) set immediately, followed by calls to
@@ -69,6 +80,66 @@
     }
 
     /**
+     * Pauses a running animation. This method should only be called on the same thread on
+     * which the animation was started. If the animation has not yet been {@link
+     * #isStarted() started} or has since ended, then the call is ignored. Paused
+     * animations can be resumed by calling {@link #resume()}.
+     *
+     * @see #resume()
+     * @see #isPaused()
+     * @see AnimatorPauseListener
+     */
+    public void pause() {
+        if (isStarted() && !mPaused) {
+            mPaused = true;
+            if (mPauseListeners != null) {
+                ArrayList<AnimatorPauseListener> tmpListeners =
+                        (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
+                int numListeners = tmpListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    tmpListeners.get(i).onAnimationPause(this);
+                }
+            }
+        }
+    }
+
+    /**
+     * Resumes a paused animation, causing the animator to pick up where it left off
+     * when it was paused. This method should only be called on the same thread on
+     * which the animation was started. Calls to resume() on an animator that is
+     * not currently paused will be ignored.
+     *
+     * @see #pause()
+     * @see #isPaused()
+     * @see AnimatorPauseListener
+     */
+    public void resume() {
+        if (mPaused) {
+            mPaused = false;
+            if (mPauseListeners != null) {
+                ArrayList<AnimatorPauseListener> tmpListeners =
+                        (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
+                int numListeners = tmpListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    tmpListeners.get(i).onAnimationResume(this);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns whether this animator is currently in a paused state.
+     *
+     * @return True if the animator is currently paused, false otherwise.
+     *
+     * @see #pause()
+     * @see #resume()
+     */
+    public boolean isPaused() {
+        return mPaused;
+    }
+
+    /**
      * The amount of time, in milliseconds, to delay processing the animation
      * after {@link #start()} is called.
      *
@@ -180,15 +251,58 @@
     }
 
     /**
+     * Adds a pause listener to this animator.
+     *
+     * @param listener the listener to be added to the current set of pause listeners
+     * for this animation.
+     */
+    public void addPauseListener(AnimatorPauseListener listener) {
+        if (mPauseListeners == null) {
+            mPauseListeners = new ArrayList<AnimatorPauseListener>();
+        }
+        mPauseListeners.add(listener);
+    }
+
+    /**
+     * Removes a pause listener from the set listening to this animation.
+     *
+     * @param listener the listener to be removed from the current set of pause
+     * listeners for this animation.
+     */
+    public void removePauseListener(AnimatorPauseListener listener) {
+        if (mPauseListeners == null) {
+            return;
+        }
+        mPauseListeners.remove(listener);
+        if (mPauseListeners.size() == 0) {
+            mPauseListeners = null;
+        }
+    }
+
+    /**
+     * Gets the set of {@link AnimatorPauseListener} objects that are currently
+     * listening for pause/resume events on this animator.
+     *
+     * @return ArrayList<AnimatorListener> The set of pause listeners.
+     */
+    public ArrayList<AnimatorPauseListener> getPauseListeners() {
+        return mPauseListeners;
+    }
+
+    /**
      * Removes all listeners from this object. This is equivalent to calling
-     * <code>getListeners()</code> followed by calling <code>clear()</code> on the
-     * returned list of listeners.
+     * {@link #getListeners()} and {@link #getPauseListeners()} followed by calling
+     * {@link ArrayList#clear()} on the returned lists of listeners.
      */
     public void removeAllListeners() {
         if (mListeners != null) {
             mListeners.clear();
             mListeners = null;
         }
+        if (mPauseListeners != null) {
+            mPauseListeners.clear();
+            mPauseListeners = null;
+        }
     }
 
     @Override
@@ -203,6 +317,14 @@
                     anim.mListeners.add(oldListeners.get(i));
                 }
             }
+            if (mPauseListeners != null) {
+                ArrayList<AnimatorPauseListener> oldListeners = mPauseListeners;
+                anim.mPauseListeners = new ArrayList<AnimatorPauseListener>();
+                int numListeners = oldListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    anim.mPauseListeners.add(oldListeners.get(i));
+                }
+            }
             return anim;
         } catch (CloneNotSupportedException e) {
            throw new AssertionError();
@@ -280,4 +402,29 @@
          */
         void onAnimationRepeat(Animator animation);
     }
+
+    /**
+     * A pause listener receives notifications from an animation when the
+     * animation is {@link #pause() paused} or {@link #resume() resumed}.
+     *
+     * @see #addPauseListener(AnimatorPauseListener)
+     */
+    public static interface AnimatorPauseListener {
+        /**
+         * <p>Notifies that the animation was paused.</p>
+         *
+         * @param animation The animaton being paused.
+         * @see #pause()
+         */
+        void onAnimationPause(Animator animation);
+
+        /**
+         * <p>Notifies that the animation was resumed, after being
+         * previously paused.</p>
+         *
+         * @param animation The animation being resumed.
+         * @see #resume()
+         */
+        void onAnimationResume(Animator animation);
+    }
 }
diff --git a/core/java/android/animation/AnimatorListenerAdapter.java b/core/java/android/animation/AnimatorListenerAdapter.java
index e5d70a4..2ecb8c3 100644
--- a/core/java/android/animation/AnimatorListenerAdapter.java
+++ b/core/java/android/animation/AnimatorListenerAdapter.java
@@ -21,7 +21,8 @@
  * Any custom listener that cares only about a subset of the methods of this listener can
  * simply subclass this adapter class instead of implementing the interface directly.
  */
-public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener {
+public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener,
+        Animator.AnimatorPauseListener {
 
     /**
      * {@inheritDoc}
@@ -51,4 +52,17 @@
     public void onAnimationStart(Animator animation) {
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAnimationPause(Animator animation) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAnimationResume(Animator animation) {
+    }
 }
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index b48853b..018a2d6 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -455,6 +455,36 @@
         }
     }
 
+    @Override
+    public void pause() {
+        boolean previouslyPaused = mPaused;
+        super.pause();
+        if (!previouslyPaused && mPaused) {
+            if (mDelayAnim != null) {
+                mDelayAnim.pause();
+            } else {
+                for (Node node : mNodes) {
+                    node.animation.pause();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void resume() {
+        boolean previouslyPaused = mPaused;
+        super.resume();
+        if (previouslyPaused && !mPaused) {
+            if (mDelayAnim != null) {
+                mDelayAnim.resume();
+            } else {
+                for (Node node : mNodes) {
+                    node.animation.resume();
+                }
+            }
+        }
+    }
+
     /**
      * {@inheritDoc}
      *
@@ -467,6 +497,7 @@
     public void start() {
         mTerminated = false;
         mStarted = true;
+        mPaused = false;
 
         if (mDuration >= 0) {
             // If the duration was set on this AnimatorSet, pass it along to all child animations
@@ -549,6 +580,7 @@
                             mPlayingSet.add(node.animation);
                         }
                     }
+                    mDelayAnim = null;
                 }
             });
             mDelayAnim.start();
@@ -787,6 +819,7 @@
                         }
                     }
                     mAnimatorSet.mStarted = false;
+                    mAnimatorSet.mPaused = false;
                 }
             }
         }
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index e370e4a..6394299 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -80,6 +80,20 @@
      */
     long mSeekTime = -1;
 
+    /**
+     * Set on the next frame after pause() is called, used to calculate a new startTime
+     * or delayStartTime which allows the animator to continue from the point at which
+     * it was paused. If negative, has not yet been set.
+     */
+    private long mPauseTime;
+
+    /**
+     * Set when an animator is resumed. This triggers logic in the next frame which
+     * actually resumes the animator.
+     */
+    private boolean mResumed = false;
+
+
     // The static sAnimationHandler processes the internal timing loop on which all animations
     // are based
     /**
@@ -147,7 +161,7 @@
     private boolean mStarted = false;
 
     /**
-     * Tracks whether we've notified listeners of the onAnimationSTart() event. This can be
+     * Tracks whether we've notified listeners of the onAnimationStart() event. This can be
      * complex to keep track of since we notify listeners at different times depending on
      * startDelay and whether start() was called before end().
      */
@@ -914,6 +928,7 @@
         mPlayingState = STOPPED;
         mStarted = true;
         mStartedDelay = false;
+        mPaused = false;
         AnimationHandler animationHandler = getOrCreateAnimationHandler();
         animationHandler.mPendingAnimations.add(this);
         if (mStartDelay == 0) {
@@ -971,6 +986,24 @@
     }
 
     @Override
+    public void resume() {
+        if (mPaused) {
+            mResumed = true;
+        }
+        super.resume();
+    }
+
+    @Override
+    public void pause() {
+        boolean previouslyPaused = mPaused;
+        super.pause();
+        if (!previouslyPaused && mPaused) {
+            mPauseTime = -1;
+            mResumed = false;
+        }
+    }
+
+    @Override
     public boolean isRunning() {
         return (mPlayingState == RUNNING || mRunning);
     }
@@ -1008,6 +1041,7 @@
         handler.mPendingAnimations.remove(this);
         handler.mDelayedAnims.remove(this);
         mPlayingState = STOPPED;
+        mPaused = false;
         if ((mStarted || mRunning) && mListeners != null) {
             if (!mRunning) {
                 // If it's not yet running, then start listeners weren't called. Call them now.
@@ -1071,6 +1105,18 @@
             mStartedDelay = true;
             mDelayStartTime = currentTime;
         } else {
+            if (mPaused) {
+                if (mPauseTime < 0) {
+                    mPauseTime = currentTime;
+                }
+                return false;
+            } else if (mResumed) {
+                mResumed = false;
+                if (mPauseTime > 0) {
+                    // Offset by the duration that the animation was paused
+                    mDelayStartTime += (currentTime - mPauseTime);
+                }
+            }
             long deltaTime = currentTime - mDelayStartTime;
             if (deltaTime > mStartDelay) {
                 // startDelay ended - start the anim and record the
@@ -1093,7 +1139,7 @@
      *
      * @param currentTime The current time, as tracked by the static timing handler
      * @return true if the animation's duration, including any repetitions due to
-     * <code>repeatCount</code> has been exceeded and the animation should be ended.
+     * <code>repeatCount</code>, has been exceeded and the animation should be ended.
      */
     boolean animationFrame(long currentTime) {
         boolean done = false;
@@ -1148,6 +1194,18 @@
                 mSeekTime = -1;
             }
         }
+        if (mPaused) {
+            if (mPauseTime < 0) {
+                mPauseTime = frameTime;
+            }
+            return false;
+        } else if (mResumed) {
+            mResumed = false;
+            if (mPauseTime > 0) {
+                // Offset by the duration that the animation was paused
+                mStartTime += (frameTime - mPauseTime);
+            }
+        }
         // The frame time might be before the start time during the first frame of
         // an animation.  The "current time" must always be on or after the start
         // time to avoid animating frames at negative time intervals.  In practice, this
diff --git a/core/java/android/print/PrintFileDocumentAdapter.java b/core/java/android/print/PrintFileDocumentAdapter.java
index 4503eda..dbc8b6f 100644
--- a/core/java/android/print/PrintFileDocumentAdapter.java
+++ b/core/java/android/print/PrintFileDocumentAdapter.java
@@ -41,7 +41,7 @@
  * spooling the data, so you can deleted the file if it is a
  * temporary one.
  */
-public final class PrintFileDocumentAdapter extends PrintDocumentAdapter {
+public class PrintFileDocumentAdapter extends PrintDocumentAdapter {
 
     private static final String LOG_TAG = "PrintedFileDocumentAdapter";
 
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index debf4ee..f43e4ab3 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -46,6 +46,8 @@
     private final int mGeneration;
     private final int mControllerNumber;
     private final String mName;
+    private final int mVendorId;
+    private final int mProductId;
     private final String mDescriptor;
     private final boolean mIsExternal;
     private final int mSources;
@@ -343,13 +345,15 @@
     };
 
     // Called by native code.
-    private InputDevice(int id, int generation, int controllerNumber, String name,
-            String descriptor, boolean isExternal, int sources, int keyboardType,
+    private InputDevice(int id, int generation, int controllerNumber, String name, int vendorId,
+            int productId, String descriptor, boolean isExternal, int sources, int keyboardType,
             KeyCharacterMap keyCharacterMap, boolean hasVibrator, boolean hasButtonUnderPad) {
         mId = id;
         mGeneration = generation;
         mControllerNumber = controllerNumber;
         mName = name;
+        mVendorId = vendorId;
+        mProductId = productId;
         mDescriptor = descriptor;
         mIsExternal = isExternal;
         mSources = sources;
@@ -364,6 +368,8 @@
         mGeneration = in.readInt();
         mControllerNumber = in.readInt();
         mName = in.readString();
+        mVendorId = in.readInt();
+        mProductId = in.readInt();
         mDescriptor = in.readString();
         mIsExternal = in.readInt() != 0;
         mSources = in.readInt();
@@ -443,6 +449,33 @@
     }
 
     /**
+     * Gets the vendor id for the given device, if available.
+     * <p>
+     * A vendor id uniquely identifies the company who manufactured the device. A value of 0 will
+     * be assigned where a vendor id is not available.
+     * </p>
+     *
+     * @return The vendor id of a given device
+     */
+    public int getVendorId() {
+        return mVendorId;
+    }
+
+    /**
+     * Gets the product id for the given device, if available.
+     * <p>
+     * A product id uniquely identifies which product within the address space of a given vendor,
+     * identified by the device's vendor id. A value of 0 will be assigned where a product id is
+     * not available.
+     * </p>
+     *
+     * @return The product id of a given device
+     */
+    public int getProductId() {
+        return mProductId;
+    }
+
+    /**
      * Gets the input device descriptor, which is a stable identifier for an input device.
      * <p>
      * An input device descriptor uniquely identifies an input device.  Its value
@@ -757,6 +790,8 @@
         out.writeInt(mGeneration);
         out.writeInt(mControllerNumber);
         out.writeString(mName);
+        out.writeInt(mVendorId);
+        out.writeInt(mProductId);
         out.writeString(mDescriptor);
         out.writeInt(mIsExternal ? 1 : 0);
         out.writeInt(mSources);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 0ed846b..07198c75 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3485,7 +3485,8 @@
             mLastY = Integer.MIN_VALUE;
         }
 
-        if (performButtonActionOnTouchDown(ev) && (mTouchMode == TOUCH_MODE_DOWN)) {
+        if (mTouchMode == TOUCH_MODE_DOWN && mMotionPosition != INVALID_POSITION
+                && performButtonActionOnTouchDown(ev)) {
             removeCallbacks(mPendingCheckForTap);
         }
     }
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 70a4daa..6d46cf9 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -610,6 +610,7 @@
     const jchar* glyphs = value->getGlyphs();
     size_t glyphsCount = value->getGlyphsCount();
     jfloat totalAdvance = value->getTotalAdvance();
+    x += xOffsetForTextAlign(paint, totalAdvance);
     const float* positions = value->getPos();
     int bytesCount = glyphsCount * sizeof(jchar);
     const SkRect& r = value->getBounds();
@@ -617,8 +618,7 @@
     bounds.translate(x, y);
 
     renderer->drawText((const char*) glyphs, bytesCount, glyphsCount,
-            x + xOffsetForTextAlign(paint, totalAdvance), y, positions,
-            paint, totalAdvance, bounds);
+            x, y, positions, paint, totalAdvance, bounds);
 }
 
 static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
@@ -646,6 +646,7 @@
     const jchar* glyphs = value->getGlyphs();
     size_t glyphsCount = value->getGlyphsCount();
     jfloat totalAdvance = value->getTotalAdvance();
+    x += xOffsetForTextAlign(paint, totalAdvance);
     const float* positions = value->getPos();
     int bytesCount = glyphsCount * sizeof(jchar);
     const SkRect& r = value->getBounds();
@@ -653,8 +654,7 @@
     bounds.translate(x, y);
 
     renderer->drawText((const char*) glyphs, bytesCount, glyphsCount,
-            x + xOffsetForTextAlign(paint, totalAdvance), y, positions,
-            paint, totalAdvance, bounds);
+            x, y, positions, paint, totalAdvance, bounds);
 }
 
 static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index 5c8e010..bef0f84 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -53,11 +53,15 @@
         return NULL;
     }
 
+    const InputDeviceIdentifier& ident = deviceInfo.getIdentifier();
+
     ScopedLocalRef<jobject> inputDeviceObj(env, env->NewObject(gInputDeviceClassInfo.clazz,
-            gInputDeviceClassInfo.ctor, deviceInfo.getId(), deviceInfo.getGeneration(),
-             deviceInfo.getControllerNumber(), nameObj.get(), descriptorObj.get(),
-            deviceInfo.isExternal(), deviceInfo.getSources(), deviceInfo.getKeyboardType(),
-            kcmObj.get(), deviceInfo.hasVibrator(), deviceInfo.hasButtonUnderPad()));
+                gInputDeviceClassInfo.ctor, deviceInfo.getId(), deviceInfo.getGeneration(),
+                deviceInfo.getControllerNumber(), nameObj.get(),
+                static_cast<int32_t>(ident.vendor), static_cast<int32_t>(ident.product),
+                descriptorObj.get(), deviceInfo.isExternal(), deviceInfo.getSources(),
+                deviceInfo.getKeyboardType(), kcmObj.get(), deviceInfo.hasVibrator(),
+                deviceInfo.hasButtonUnderPad()));
 
     const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
     for (size_t i = 0; i < ranges.size(); i++) {
@@ -88,7 +92,7 @@
 
     GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz,
             "<init>",
-            "(IIILjava/lang/String;Ljava/lang/String;ZIILandroid/view/KeyCharacterMap;ZZ)V");
+            "(IIILjava/lang/String;IILjava/lang/String;ZIILandroid/view/KeyCharacterMap;ZZ)V");
 
     GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz,
             "addMotionRange", "(IIFFFFF)V");
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
index d415e4e..7eb32ee 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
@@ -37,14 +37,12 @@
         button = (Button) getActivity().findViewById(R.id.animatingButton);
         mAnimator = new AnimatorSet();
         ((AnimatorSet)mAnimator).playSequentially(xAnim, yAnim);
-
         super.setUp();
     }
 
     @Override
     protected long getTimeout() {
-        return (xAnim.getDuration() + yAnim.getDuration()) +
-                (xAnim.getStartDelay() + yAnim.getStartDelay()) +
+        return (2 * mAnimator.getDuration()) + (2 * mAnimator.getStartDelay()) +
                 ANIM_DELAY + FUTURE_RELEASE_DELAY;
     }
 
diff --git a/core/tests/coretests/src/android/animation/EventsTest.java b/core/tests/coretests/src/android/animation/EventsTest.java
index 8df711b..28cfe3d 100644
--- a/core/tests/coretests/src/android/animation/EventsTest.java
+++ b/core/tests/coretests/src/android/animation/EventsTest.java
@@ -22,6 +22,7 @@
 import android.test.suitebuilder.annotation.SmallTest;
 
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Tests for the various lifecycle events of Animators. This abstract class is subclassed by
@@ -42,12 +43,15 @@
     protected static final int ANIM_DELAY = 100;
     protected static final int ANIM_MID_DURATION = ANIM_DURATION / 2;
     protected static final int ANIM_MID_DELAY = ANIM_DELAY / 2;
+    protected static final int ANIM_PAUSE_DURATION = ANIM_DELAY;
+    protected static final int ANIM_PAUSE_DELAY = ANIM_DELAY / 2;
     protected static final int FUTURE_RELEASE_DELAY = 50;
+    protected static final int ANIM_FULL_DURATION_SLOP = 100;
 
     private boolean mStarted;  // tracks whether we've received the onAnimationStart() callback
     protected boolean mRunning;  // tracks whether we've started the animator
-    private boolean mCanceled; // trackes whether we've canceled the animator
-    protected Animator.AnimatorListener mFutureListener; // mechanism for delaying the end of the test
+    private boolean mCanceled; // tracks whether we've canceled the animator
+    protected Animator.AnimatorListener mFutureListener; // mechanism for delaying end of the test
     protected FutureWaiter mFuture; // Mechanism for waiting for the UI test to complete
     private Animator.AnimatorListener mListener; // Listener that handles/tests the events
 
@@ -104,6 +108,48 @@
     };
 
     /**
+     * Pauses the given animator. Used to delay pausing until some later time (after the
+     * animator has started playing).
+     */
+    static class Pauser implements Runnable {
+        Animator mAnim;
+        FutureWaiter mFuture;
+        public Pauser(Animator anim, FutureWaiter future) {
+            mAnim = anim;
+            mFuture = future;
+        }
+        @Override
+        public void run() {
+            try {
+                mAnim.pause();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
+            }
+        }
+    };
+
+    /**
+     * Resumes the given animator. Used to delay resuming until some later time (after the
+     * animator has paused for some duration).
+     */
+    static class Resumer implements Runnable {
+        Animator mAnim;
+        FutureWaiter mFuture;
+        public Resumer(Animator anim, FutureWaiter future) {
+            mAnim = anim;
+            mFuture = future;
+        }
+        @Override
+        public void run() {
+            try {
+                mAnim.resume();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
+            }
+        }
+    };
+
+    /**
      * Releases the given Future object when the listener's end() event is called. Specifically,
      * it releases it after some further delay, to give the test time to do other things right
      * after an animation ends.
@@ -555,4 +601,114 @@
         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
      }
 
+    /**
+     * Verify that pausing and resuming an animator ends within
+     * the appropriate timeout duration.
+     */
+    @MediumTest
+    public void testPauseResume() throws Exception {
+        mFutureListener = new FutureReleaseListener(mFuture);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Handler handler = new Handler();
+                    mAnimator.addListener(mFutureListener);
+                    mRunning = true;
+                    mAnimator.start();
+                    handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
+                    handler.postDelayed(new Resumer(mAnimator, mFuture),
+                            ANIM_PAUSE_DELAY + ANIM_PAUSE_DURATION);
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        mFuture.get(getTimeout() + ANIM_PAUSE_DURATION, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Verify that pausing and resuming a startDelayed animator ends within
+     * the appropriate timeout duration.
+     */
+    @MediumTest
+    public void testPauseResumeDelayed() throws Exception {
+        mAnimator.setStartDelay(ANIM_DELAY);
+        mFutureListener = new FutureReleaseListener(mFuture);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Handler handler = new Handler();
+                    mAnimator.addListener(mFutureListener);
+                    mRunning = true;
+                    mAnimator.start();
+                    handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
+                    handler.postDelayed(new Resumer(mAnimator, mFuture),
+                            ANIM_PAUSE_DELAY + ANIM_PAUSE_DURATION);
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        mFuture.get(getTimeout() + ANIM_PAUSE_DURATION + ANIM_FULL_DURATION_SLOP,
+                TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Verify that pausing an animator without resuming it causes a timeout.
+     */
+    @MediumTest
+    public void testPauseTimeout() throws Exception {
+        mFutureListener = new FutureReleaseListener(mFuture);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Handler handler = new Handler();
+                    mAnimator.addListener(mFutureListener);
+                    mRunning = true;
+                    mAnimator.start();
+                    handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        try {
+            mFuture.get(getTimeout() + ANIM_PAUSE_DURATION + ANIM_FULL_DURATION_SLOP,
+                    TimeUnit.MILLISECONDS);
+        } catch (TimeoutException e) {
+            // Expected behavior, swallow the exception
+        }
+    }
+
+    /**
+     * Verify that pausing a startDelayed animator without resuming it causes a timeout.
+     */
+    @MediumTest
+    public void testPauseTimeoutDelayed() throws Exception {
+        mAnimator.setStartDelay(ANIM_DELAY);
+        mFutureListener = new FutureReleaseListener(mFuture);
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Handler handler = new Handler();
+                    mAnimator.addListener(mFutureListener);
+                    mRunning = true;
+                    mAnimator.start();
+                    handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
+                } catch (junit.framework.AssertionFailedError e) {
+                    mFuture.setException(new RuntimeException(e));
+                }
+            }
+        });
+        try {
+            mFuture.get(getTimeout() + ANIM_PAUSE_DURATION + ANIM_FULL_DURATION_SLOP,
+                    TimeUnit.MILLISECONDS);
+        } catch (TimeoutException e) {
+            // Expected behavior, swallow the exception
+        }
+    }
 }
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 1700473..cb6bb2e 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -234,6 +234,7 @@
     Vector<CacheTexture*>* cacheTextures = NULL;
     switch (format) {
         case SkMask::kA8_Format:
+        case SkMask::kBW_Format:
             cacheTextures = &mACacheTextures;
             break;
         case SkMask::kARGB32_Format:
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 55503ce..cbed3e4 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -233,9 +233,11 @@
 bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
     switch (glyph.fMaskFormat) {
         case SkMask::kA8_Format:
+        case SkMask::kBW_Format:
             if (mFormat != GL_ALPHA) {
 #if DEBUG_FONT_RENDERER
-                ALOGD("fitBitmap: kA8_Format glyph cannot fit into texture format %x", mFormat);
+                ALOGD("fitBitmap: texture format %x is inappropriate for monochromatic glyphs",
+                        mFormat);
 #endif
                 return false;
             }
@@ -243,7 +245,7 @@
         case SkMask::kARGB32_Format:
             if (mFormat != GL_RGBA) {
 #if DEBUG_FONT_RENDERER
-                ALOGD("fitBitmap: kARGB32_Format glyph cannot fit into texture format %x", mFormat);
+                ALOGD("fitBitmap: texture format %x is inappropriate for colour glyphs", mFormat);
 #endif
                 return false;
             }
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 8634929..0808861 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1684,9 +1684,6 @@
                         setLaunchHomeTaskNextFlag(sourceRecord, null, targetStack);
                         targetStack.resumeTopActivityLocked(null);
                     }
-                    if (r.task == null)  Slog.v(TAG,
-                        "startActivityUncheckedLocked: task left null",
-                        new RuntimeException("here").fillInStackTrace());
                     return ActivityManager.START_DELIVERED_TO_TOP;
                 }
             }