Merge "Fix an incorrect assert that doesn't account for element array size."
diff --git a/api/current.txt b/api/current.txt
index d0176a5..9e94a0d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4670,10 +4670,9 @@
 
   public abstract class AsyncTaskLoader extends android.content.Loader {
     ctor public AsyncTaskLoader(android.content.Context);
-    method public boolean cancelLoad();
-    method protected boolean isLoadInBackgroundCanceled();
+    method public void cancelLoadInBackground();
+    method public boolean isLoadInBackgroundCanceled();
     method public abstract D loadInBackground();
-    method protected void onCancelLoadInBackground();
     method public void onCanceled(D);
     method protected D onLoadInBackground();
     method public void setUpdateThrottle(long);
@@ -5765,7 +5764,9 @@
   public class Loader {
     ctor public Loader(android.content.Context);
     method public void abandon();
+    method public boolean cancelLoad();
     method public java.lang.String dataToString(D);
+    method public void deliverCancellation();
     method public void deliverResult(D);
     method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public void forceLoad();
@@ -5775,23 +5776,30 @@
     method public boolean isReset();
     method public boolean isStarted();
     method protected void onAbandon();
+    method protected boolean onCancelLoad();
     method public void onContentChanged();
     method protected void onForceLoad();
     method protected void onReset();
     method protected void onStartLoading();
     method protected void onStopLoading();
     method public void registerListener(int, android.content.Loader.OnLoadCompleteListener<D>);
+    method public void registerOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
     method public void reset();
     method public final void startLoading();
     method public void stopLoading();
     method public boolean takeContentChanged();
     method public void unregisterListener(android.content.Loader.OnLoadCompleteListener<D>);
+    method public void unregisterOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
   }
 
   public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
     ctor public Loader.ForceLoadContentObserver();
   }
 
+  public static abstract interface Loader.OnLoadCanceledListener {
+    method public abstract void onLoadCanceled(android.content.Loader<D>);
+  }
+
   public static abstract interface Loader.OnLoadCompleteListener {
     method public abstract void onLoadComplete(android.content.Loader<D>, D);
   }
@@ -11631,7 +11639,7 @@
     method public void setNetworkPreference(int);
     method public int startUsingNetworkFeature(int, java.lang.String);
     method public int stopUsingNetworkFeature(int, java.lang.String);
-    field public static final java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
+    field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
     field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
     field public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
     field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
@@ -17575,6 +17583,7 @@
     field public static final java.lang.String ALARM_ALERT = "alarm_alert";
     field public static final java.lang.String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
     field public static final deprecated java.lang.String ANDROID_ID = "android_id";
+    field public static final java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
     field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
     field public static final java.lang.String AUTO_TIME = "auto_time";
     field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 274a9d5..634e4d8 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -960,17 +960,17 @@
         if (anim instanceof ObjectAnimator) {
             ((ObjectAnimator) anim).setCurrentPlayTime(0);
         }
-        if (mListeners != null) {
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator anim) {
-                    currentAppearingAnimations.remove(child);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator anim) {
+                currentAppearingAnimations.remove(child);
+                if (mListeners != null) {
                     for (TransitionListener listener : mListeners) {
                         listener.endTransition(LayoutTransition.this, parent, child, APPEARING);
                     }
                 }
-            });
-        }
+            }
+        });
         currentAppearingAnimations.put(child, anim);
         anim.start();
     }
@@ -998,17 +998,19 @@
         anim.setStartDelay(mDisappearingDelay);
         anim.setDuration(mDisappearingDuration);
         anim.setTarget(child);
-        if (mListeners != null) {
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator anim) {
-                    currentDisappearingAnimations.remove(child);
+        final float preAnimAlpha = child.getAlpha();
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator anim) {
+                currentDisappearingAnimations.remove(child);
+                child.setAlpha(preAnimAlpha);
+                if (mListeners != null) {
                     for (TransitionListener listener : mListeners) {
                         listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
                     }
                 }
-            });
-        }
+            }
+        });
         if (anim instanceof ObjectAnimator) {
             ((ObjectAnimator) anim).setCurrentPlayTime(0);
         }
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 3f28e67..cc1efb9 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -54,7 +54,6 @@
      * Internal constants
      */
     private static float sDurationScale = 1.0f;
-    private static boolean sDurationScaleInitialized = false;
 
     /**
      * Messages sent to timing handler: START is sent when an animation first begins.
@@ -161,7 +160,7 @@
     //
 
     // How long the animation should last in ms
-    private long mDuration = 300;
+    private long mDuration = (long)(300 * sDurationScale);
     private long mUnscaledDuration = 300;
 
     // The amount of time in ms to delay starting the animation after start() is called
@@ -222,21 +221,20 @@
      */
     public static final int INFINITE = -1;
 
+
+    /**
+     * @hide
+     */
+    public static void setDurationScale(float durationScale) {
+        sDurationScale = durationScale;
+    }
+
     /**
      * Creates a new ValueAnimator object. This default constructor is primarily for
      * use internally; the factory methods which take parameters are more generally
      * useful.
      */
     public ValueAnimator() {
-        if (!sDurationScaleInitialized) {
-            // Scale value initialized per-process when first animator is constructed
-            String scaleString = SystemProperties.get("persist.sys.ui.animation");
-            if (!scaleString.isEmpty()) {
-                sDurationScale = Float.parseFloat(scaleString);
-            }
-            sDurationScaleInitialized = true;
-        }
-        mDuration *= sDurationScale;
     }
 
     /**
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index d83d2e6..ff71ee7 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.content.Loader;
+import android.content.Loader.OnLoadCanceledListener;
 import android.os.Bundle;
 import android.util.DebugUtils;
 import android.util.Log;
@@ -219,7 +220,8 @@
     
     boolean mCreatingLoader;
 
-    final class LoaderInfo implements Loader.OnLoadCompleteListener<Object> {
+    final class LoaderInfo implements Loader.OnLoadCompleteListener<Object>,
+            Loader.OnLoadCanceledListener<Object> {
         final int mId;
         final Bundle mArgs;
         LoaderManager.LoaderCallbacks<Object> mCallbacks;
@@ -271,6 +273,7 @@
                 }
                 if (!mListenerRegistered) {
                     mLoader.registerListener(mId, this);
+                    mLoader.registerOnLoadCanceledListener(this);
                     mListenerRegistered = true;
                 }
                 mLoader.startLoading();
@@ -329,11 +332,21 @@
                     // Let the loader know we're done with it
                     mListenerRegistered = false;
                     mLoader.unregisterListener(this);
+                    mLoader.unregisterOnLoadCanceledListener(this);
                     mLoader.stopLoading();
                 }
             }
         }
-        
+
+        void cancel() {
+            if (DEBUG) Log.v(TAG, "  Canceling: " + this);
+            if (mStarted && mLoader != null && mListenerRegistered) {
+                if (!mLoader.cancelLoad()) {
+                    onLoadCanceled(mLoader);
+                }
+            }
+        }
+
         void destroy() {
             if (DEBUG) Log.v(TAG, "  Destroying: " + this);
             mDestroyed = true;
@@ -361,6 +374,7 @@
                 if (mListenerRegistered) {
                     mListenerRegistered = false;
                     mLoader.unregisterListener(this);
+                    mLoader.unregisterOnLoadCanceledListener(this);
                 }
                 mLoader.reset();
             }
@@ -368,8 +382,38 @@
                 mPendingLoader.destroy();
             }
         }
-        
-        @Override public void onLoadComplete(Loader<Object> loader, Object data) {
+
+        @Override
+        public void onLoadCanceled(Loader<Object> loader) {
+            if (DEBUG) Log.v(TAG, "onLoadCanceled: " + this);
+
+            if (mDestroyed) {
+                if (DEBUG) Log.v(TAG, "  Ignoring load canceled -- destroyed");
+                return;
+            }
+
+            if (mLoaders.get(mId) != this) {
+                // This cancellation message is not coming from the current active loader.
+                // We don't care about it.
+                if (DEBUG) Log.v(TAG, "  Ignoring load canceled -- not active");
+                return;
+            }
+
+            LoaderInfo pending = mPendingLoader;
+            if (pending != null) {
+                // There is a new request pending and we were just
+                // waiting for the old one to cancel or complete before starting
+                // it.  So now it is time, switch over to the new loader.
+                if (DEBUG) Log.v(TAG, "  Switching to pending loader: " + pending);
+                mPendingLoader = null;
+                mLoaders.put(mId, null);
+                destroy();
+                installLoader(pending);
+            }
+        }
+
+        @Override
+        public void onLoadComplete(Loader<Object> loader, Object data) {
             if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
             
             if (mDestroyed) {
@@ -632,7 +676,9 @@
                     } else {
                         // Now we have three active loaders... we'll queue
                         // up this request to be processed once one of the other loaders
-                        // finishes.
+                        // finishes or is canceled.
+                        if (DEBUG) Log.v(TAG, "  Current loader is running; attempting to cancel");
+                        info.cancel();
                         if (info.mPendingLoader != null) {
                             if (DEBUG) Log.v(TAG, "  Removing pending loader: " + info.mPendingLoader);
                             info.mPendingLoader.destroy();
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index 944ca6b..da51952 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -53,19 +53,33 @@
     static final boolean DEBUG = false;
 
     final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {
+        private final CountDownLatch mDone = new CountDownLatch(1);
 
-        D result;
+        // Set to true to indicate that the task has been posted to a handler for
+        // execution at a later time.  Used to throttle updates.
         boolean waiting;
 
-        private CountDownLatch done = new CountDownLatch(1);
-
         /* Runs on a worker thread */
         @Override
         protected D doInBackground(Void... params) {
             if (DEBUG) Slog.v(TAG, this + " >>> doInBackground");
-            result = AsyncTaskLoader.this.onLoadInBackground();
-            if (DEBUG) Slog.v(TAG, this + "  <<< doInBackground");
-            return result;
+            try {
+                D data = AsyncTaskLoader.this.onLoadInBackground();
+                if (DEBUG) Slog.v(TAG, this + "  <<< doInBackground");
+                return data;
+            } catch (OperationCanceledException ex) {
+                if (!isCancelled()) {
+                    // onLoadInBackground threw a canceled exception spuriously.
+                    // This is problematic because it means that the LoaderManager did not
+                    // cancel the Loader itself and still expects to receive a result.
+                    // Additionally, the Loader's own state will not have been updated to
+                    // reflect the fact that the task was being canceled.
+                    // So we treat this case as an unhandled exception.
+                    throw ex;
+                }
+                if (DEBUG) Slog.v(TAG, this + "  <<< doInBackground (was canceled)");
+                return null;
+            }
         }
 
         /* Runs on the UI thread */
@@ -75,25 +89,37 @@
             try {
                 AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
             } finally {
-                done.countDown();
+                mDone.countDown();
             }
         }
 
+        /* Runs on the UI thread */
         @Override
-        protected void onCancelled() {
+        protected void onCancelled(D data) {
             if (DEBUG) Slog.v(TAG, this + " onCancelled");
             try {
-                AsyncTaskLoader.this.dispatchOnCancelled(this, result);
+                AsyncTaskLoader.this.dispatchOnCancelled(this, data);
             } finally {
-                done.countDown();
+                mDone.countDown();
             }
         }
 
+        /* Runs on the UI thread, when the waiting task is posted to a handler.
+         * This method is only executed when task execution was deferred (waiting was true). */
         @Override
         public void run() {
             waiting = false;
             AsyncTaskLoader.this.executePendingTask();
         }
+
+        /* Used for testing purposes to wait for the task to complete. */
+        public void waitForLoader() {
+            try {
+                mDone.await();
+            } catch (InterruptedException e) {
+                // Ignore
+            }
+        }
     }
 
     volatile LoadTask mTask;
@@ -109,7 +135,7 @@
 
     /**
      * Set amount to throttle updates by.  This is the minimum time from
-     * when the last {@link #onLoadInBackground()} call has completed until
+     * when the last {@link #loadInBackground()} call has completed until
      * a new load is scheduled.
      *
      * @param delayMS Amount of delay, in milliseconds.
@@ -130,24 +156,9 @@
         executePendingTask();
     }
 
-    /**
-     * Attempt to cancel the current load task. See {@link AsyncTask#cancel(boolean)}
-     * for more info.  Must be called on the main thread of the process.
-     *
-     * <p>Cancelling is not an immediate operation, since the load is performed
-     * in a background thread.  If there is currently a load in progress, this
-     * method requests that the load be cancelled, and notes this is the case;
-     * once the background thread has completed its work its remaining state
-     * will be cleared.  If another load request comes in during this time,
-     * it will be held until the cancelled load is complete.
-     *
-     * @return Returns <tt>false</tt> if the task could not be cancelled,
-     *         typically because it has already completed normally, or
-     *         because {@link #startLoading()} hasn't been called; returns
-     *         <tt>true</tt> otherwise.
-     */
-    public boolean cancelLoad() {
-        if (DEBUG) Slog.v(TAG, "cancelLoad: mTask=" + mTask);
+    @Override
+    protected boolean onCancelLoad() {
+        if (DEBUG) Slog.v(TAG, "onCancelLoad: mTask=" + mTask);
         if (mTask != null) {
             if (mCancellingTask != null) {
                 // There was a pending task already waiting for a previous
@@ -173,7 +184,7 @@
                 if (DEBUG) Slog.v(TAG, "cancelLoad: cancelled=" + cancelled);
                 if (cancelled) {
                     mCancellingTask = mTask;
-                    onCancelLoadInBackground();
+                    cancelLoadInBackground();
                 }
                 mTask = null;
                 return cancelled;
@@ -184,7 +195,10 @@
 
     /**
      * Called if the task was canceled before it was completed.  Gives the class a chance
-     * to properly dispose of the result.
+     * to clean up post-cancellation and to properly dispose of the result.
+     *
+     * @param data The value that was returned by {@link #loadInBackground}, or null
+     * if the task threw {@link OperationCanceledException}.
      */
     public void onCanceled(D data) {
     }
@@ -218,6 +232,8 @@
             if (DEBUG) Slog.v(TAG, "Cancelled task is now canceled!");
             mLastLoadCompleteTime = SystemClock.uptimeMillis();
             mCancellingTask = null;
+            if (DEBUG) Slog.v(TAG, "Delivering cancellation");
+            deliverCancellation();
             executePendingTask();
         }
     }
@@ -240,38 +256,72 @@
     }
 
     /**
+     * Called on a worker thread to perform the actual load and to return
+     * the result of the load operation.
+     *
+     * Implementations should not deliver the result directly, but should return them
+     * from this method, which will eventually end up calling {@link #deliverResult} on
+     * the UI thread.  If implementations need to process the results on the UI thread
+     * they may override {@link #deliverResult} and do so there.
+     *
+     * To support cancellation, this method should periodically check the value of
+     * {@link #isLoadInBackgroundCanceled} and terminate when it returns true.
+     * Subclasses may also override {@link #cancelLoadInBackground} to interrupt the load
+     * directly instead of polling {@link #isLoadInBackgroundCanceled}.
+     *
+     * When the load is canceled, this method may either return normally or throw
+     * {@link OperationCanceledException}.  In either case, the {@link Loader} will
+     * call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the
+     * result object, if any.
+     *
+     * @return The result of the load operation.
+     *
+     * @throws OperationCanceledException if the load is canceled during execution.
+     *
+     * @see #isLoadInBackgroundCanceled
+     * @see #cancelLoadInBackground
+     * @see #onCanceled
      */
     public abstract D loadInBackground();
 
     /**
-     * Called on a worker thread to perform the actual load. Implementations should not deliver the
-     * result directly, but should return them from this method, which will eventually end up
-     * calling {@link #deliverResult} on the UI thread. If implementations need to process
-     * the results on the UI thread they may override {@link #deliverResult} and do so
-     * there.
+     * Calls {@link #loadInBackground()}.
      *
-     * @return Implementations must return the result of their load operation.
+     * This method is reserved for use by the loader framework.
+     * Subclasses should override {@link #loadInBackground} instead of this method.
+     *
+     * @return The result of the load operation.
+     *
+     * @throws OperationCanceledException if the load is canceled during execution.
+     *
+     * @see #loadInBackground
      */
     protected D onLoadInBackground() {
         return loadInBackground();
     }
 
     /**
-     * Override this method to try to abort the computation currently taking
-     * place on a background thread.
+     * Called on the main thread to abort a load in progress.
      *
-     * Note that when this method is called, it is possible that {@link #loadInBackground}
-     * has not started yet or has already completed.
+     * Override this method to abort the current invocation of {@link #loadInBackground}
+     * that is running in the background on a worker thread.
+     *
+     * This method should do nothing if {@link #loadInBackground} has not started
+     * running or if it has already finished.
+     *
+     * @see #loadInBackground
      */
-    protected void onCancelLoadInBackground() {
+    public void cancelLoadInBackground() {
     }
 
     /**
-     * Returns true if the current execution of {@link #loadInBackground()} is being canceled.
+     * Returns true if the current invocation of {@link #loadInBackground} is being canceled.
      *
-     * @return True if the current execution of {@link #loadInBackground()} is being canceled.
+     * @return True if the current invocation of {@link #loadInBackground} is being canceled.
+     *
+     * @see #loadInBackground
      */
-    protected boolean isLoadInBackgroundCanceled() {
+    public boolean isLoadInBackgroundCanceled() {
         return mCancellingTask != null;
     }
 
@@ -288,11 +338,7 @@
     public void waitForLoader() {
         LoadTask task = mTask;
         if (task != null) {
-            try {
-                task.done.await();
-            } catch (InterruptedException e) {
-                // Ignore
-            }
+            task.waitForLoader();
         }
     }
 
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index 6e4aca8..e58fad7 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -76,8 +76,8 @@
     }
 
     @Override
-    protected void onCancelLoadInBackground() {
-        super.onCancelLoadInBackground();
+    public void cancelLoadInBackground() {
+        super.cancelLoadInBackground();
 
         synchronized (this) {
             if (mCancelationSignal != null) {
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index ac05682..3052414 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -52,6 +52,7 @@
 public class Loader<D> {
     int mId;
     OnLoadCompleteListener<D> mListener;
+    OnLoadCanceledListener<D> mOnLoadCanceledListener;
     Context mContext;
     boolean mStarted = false;
     boolean mAbandoned = false;
@@ -100,6 +101,23 @@
     }
 
     /**
+     * Interface that is implemented to discover when a Loader has been canceled
+     * before it finished loading its data.  You do not normally need to implement
+     * this yourself; it is used in the implementation of {@link android.app.LoaderManager}
+     * to find out when a Loader it is managing has been canceled so that it
+     * can schedule the next Loader.  This interface should only be used if a
+     * Loader is not being used in conjunction with LoaderManager.
+     */
+    public interface OnLoadCanceledListener<D> {
+        /**
+         * Called on the thread that created the Loader when the load is canceled.
+         *
+         * @param loader the loader that canceled the load
+         */
+        public void onLoadCanceled(Loader<D> loader);
+    }
+
+    /**
      * Stores away the application context associated with context.
      * Since Loaders can be used across multiple activities it's dangerous to
      * store the context directly; always use {@link #getContext()} to retrieve
@@ -127,6 +145,18 @@
     }
 
     /**
+     * Informs the registered {@link OnLoadCanceledListener} that the load has been canceled.
+     * Should only be called by subclasses.
+     *
+     * Must be called from the process's main thread.
+     */
+    public void deliverCancellation() {
+        if (mOnLoadCanceledListener != null) {
+            mOnLoadCanceledListener.onLoadCanceled(this);
+        }
+    }
+
+    /**
      * @return an application context retrieved from the Context passed to the constructor.
      */
     public Context getContext() {
@@ -171,6 +201,40 @@
     }
 
     /**
+     * Registers a listener that will receive callbacks when a load is canceled.
+     * The callback will be called on the process's main thread so it's safe to
+     * pass the results to widgets.
+     *
+     * Must be called from the process's main thread.
+     *
+     * @param listener The listener to register.
+     */
+    public void registerOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
+        if (mOnLoadCanceledListener != null) {
+            throw new IllegalStateException("There is already a listener registered");
+        }
+        mOnLoadCanceledListener = listener;
+    }
+
+    /**
+     * Unregisters a listener that was previously added with
+     * {@link #registerOnLoadCanceledListener}.
+     *
+     * Must be called from the process's main thread.
+     *
+     * @param listener The listener to unregister.
+     */
+    public void unregisterOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
+        if (mOnLoadCanceledListener == null) {
+            throw new IllegalStateException("No listener register");
+        }
+        if (mOnLoadCanceledListener != listener) {
+            throw new IllegalArgumentException("Attempting to unregister the wrong listener");
+        }
+        mOnLoadCanceledListener = null;
+    }
+
+    /**
      * Return whether this load has been started.  That is, its {@link #startLoading()}
      * has been called and no calls to {@link #stopLoading()} or
      * {@link #reset()} have yet been made.
@@ -234,6 +298,43 @@
     }
 
     /**
+     * Attempt to cancel the current load task.
+     * Must be called on the main thread of the process.
+     *
+     * <p>Cancellation is not an immediate operation, since the load is performed
+     * in a background thread.  If there is currently a load in progress, this
+     * method requests that the load be canceled, and notes this is the case;
+     * once the background thread has completed its work its remaining state
+     * will be cleared.  If another load request comes in during this time,
+     * it will be held until the canceled load is complete.
+     *
+     * @return Returns <tt>false</tt> if the task could not be canceled,
+     * typically because it has already completed normally, or
+     * because {@link #startLoading()} hasn't been called; returns
+     * <tt>true</tt> otherwise.  When <tt>true</tt> is returned, the task
+     * is still running and the {@link OnLoadCanceledListener} will be called
+     * when the task completes.
+     */
+    public boolean cancelLoad() {
+        return onCancelLoad();
+    }
+
+    /**
+     * Subclasses must implement this to take care of requests to {@link #cancelLoad()}.
+     * This will always be called from the process's main thread.
+     *
+     * @return Returns <tt>false</tt> if the task could not be canceled,
+     * typically because it has already completed normally, or
+     * because {@link #startLoading()} hasn't been called; returns
+     * <tt>true</tt> otherwise.  When <tt>true</tt> is returned, the task
+     * is still running and the {@link OnLoadCanceledListener} will be called
+     * when the task completes.
+     */
+    protected boolean onCancelLoad() {
+        return false;
+    }
+
+    /**
      * Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously
      * loaded data set and load a new one.  This simply calls through to the
      * implementation's {@link #onForceLoad()}.  You generally should only call this
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index b69d9bf..0022118 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -21,6 +21,7 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.OperationApplicationException;
+import android.content.OperationCanceledException;
 import android.database.sqlite.SQLiteAbortException;
 import android.database.sqlite.SQLiteConstraintException;
 import android.database.sqlite.SQLiteDatabase;
@@ -107,6 +108,9 @@
             code = 9;
         } else if (e instanceof OperationApplicationException) {
             code = 10;
+        } else if (e instanceof OperationCanceledException) {
+            code = 11;
+            logException = false;
         } else {
             reply.writeException(e);
             Log.e(TAG, "Writing exception to parcel", e);
@@ -178,6 +182,8 @@
                 throw new SQLiteDiskIOException(msg);
             case 9:
                 throw new SQLiteException(msg);
+            case 11:
+                throw new OperationCanceledException(msg);
             default:
                 reply.readException(code, msg);
         }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a569317..2eef8f4 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -142,8 +142,19 @@
      * If an application uses the network in the background, it should listen
      * for this broadcast and stop using the background data if the value is
      * {@code false}.
+     * <p>
+     *
+     * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, availability
+     *             of background data depends on several combined factors, and
+     *             this broadcast is no longer sent. Instead, when background
+     *             data is unavailable, {@link #getActiveNetworkInfo()} will now
+     *             appear disconnected. During first boot after a platform
+     *             upgrade, this broadcast will be sent once if
+     *             {@link #getBackgroundDataSetting()} was {@code false} before
+     *             the upgrade.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @Deprecated
     public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED =
             "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f14d27e..207810c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1678,6 +1678,13 @@
         public static final String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
 
         /**
+         * Scaling factor for Animator-based animations. This affects both the start delay and
+         * duration of all such animations. Setting to 0 will cause animations to end immediately.
+         * The default value is 1.
+         */
+        public static final String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
+
+        /**
          * Scaling factor for normal window animations. Setting to 0 will disable window
          * animations.
          * @hide
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 63de128..c86ea77 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -26,7 +26,7 @@
 import android.util.Log;
 
 /**
- * Coodinates animations and drawing for UI on a particular thread.
+ * Coordinates animations and drawing for UI on a particular thread.
  * @hide
  */
 public final class Choreographer extends Handler {
@@ -94,8 +94,8 @@
     }
 
     /**
-     * Gets the choreographer for this thread.
-     * Must be called on the UI thread.
+     * Gets the choreographer for the calling thread.  Must be called from
+     * a thread that already has a {@link android.os.Looper} associated with it.
      *
      * @return The choreographer for this thread.
      * @throws IllegalStateException if the thread does not have a looper.
@@ -163,6 +163,15 @@
     }
 
     /**
+     * Return true if {@link #scheduleAnimation()} has been called but
+     * {@link OnAnimateListener#onAnimate() OnAnimateListener.onAnimate()} has
+     * not yet been called.
+     */
+    public boolean isAnimationScheduled() {
+        return mAnimationScheduled;
+    }
+
+    /**
      * Schedules drawing to occur on the next frame synchronization boundary.
      * Must be called on the UI thread.
      */
@@ -180,6 +189,15 @@
         }
     }
 
+    /**
+     * Return true if {@link #scheduleDraw()} has been called but
+     * {@link OnDrawListener#onDraw() OnDrawListener.onDraw()} has
+     * not yet been called.
+     */
+    public boolean isDrawScheduled() {
+        return mDrawScheduled;
+    }
+
     @Override
     public void handleMessage(Message msg) {
         switch (msg.what) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d80d080..7ba17b3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3761,8 +3761,14 @@
     }
 
     /**
-     * Called when this view wants to give up focus. This will cause
-     * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called.
+     * Called when this view wants to give up focus. If focus is cleared
+     * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called.
+     * <p>
+     * <strong>Note:</strong> When a View clears focus the framework is trying
+     * to give focus to the first focusable View from the top. Hence, if this
+     * View is the first from the top that can take focus, then its focus will
+     * not be cleared nor will the focus change callback be invoked.
+     * </p>
      */
     public void clearFocus() {
         if (DBG) {
@@ -7306,6 +7312,7 @@
      * 
      * @return The degrees of rotation.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getRotation() {
         return mTransformationInfo != null ? mTransformationInfo.mRotation : 0;
     }
@@ -7347,6 +7354,7 @@
      * 
      * @return The degrees of Y rotation.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getRotationY() {
         return mTransformationInfo != null ? mTransformationInfo.mRotationY : 0;
     }
@@ -7393,6 +7401,7 @@
      * 
      * @return The degrees of X rotation.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getRotationX() {
         return mTransformationInfo != null ? mTransformationInfo.mRotationX : 0;
     }
@@ -7440,6 +7449,7 @@
      * @see #getPivotY()
      * @return The scaling factor.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getScaleX() {
         return mTransformationInfo != null ? mTransformationInfo.mScaleX : 1;
     }
@@ -7478,6 +7488,7 @@
      * @see #getPivotY()
      * @return The scaling factor.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getScaleY() {
         return mTransformationInfo != null ? mTransformationInfo.mScaleY : 1;
     }
@@ -7516,6 +7527,7 @@
      * @see #getPivotY()
      * @return The x location of the pivot point.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getPivotX() {
         return mTransformationInfo != null ? mTransformationInfo.mPivotX : 0;
     }
@@ -7560,6 +7572,7 @@
      * @see #getPivotY()
      * @return The y location of the pivot point.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getPivotY() {
         return mTransformationInfo != null ? mTransformationInfo.mPivotY : 0;
     }
@@ -7600,6 +7613,7 @@
      * <p>By default this is 1.0f.
      * @return The opacity of the view.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getAlpha() {
         return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1;
     }
@@ -7613,6 +7627,10 @@
      * equivalent to calling {@link #setLayerType(int, android.graphics.Paint)} and
      * setting a hardware layer.</p>
      *
+     * <p>Note that setting alpha to a translucent value (0 < alpha < 1) may have
+     * performance implications. It is generally best to use the alpha property sparingly and
+     * transiently, as in the case of fading animations.</p>
+     *
      * @param alpha The opacity of the view.
      *
      * @see #setLayerType(int, android.graphics.Paint)
@@ -7910,6 +7928,7 @@
      *
      * @return The visual x position of this view, in pixels.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getX() {
         return mLeft + (mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0);
     }
@@ -7932,6 +7951,7 @@
      *
      * @return The visual y position of this view, in pixels.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getY() {
         return mTop + (mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0);
     }
@@ -7955,6 +7975,7 @@
      *
      * @return The horizontal position of this view relative to its left position, in pixels.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getTranslationX() {
         return mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0;
     }
@@ -7991,6 +8012,7 @@
      * @return The vertical position of this view relative to its top position,
      * in pixels.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getTranslationY() {
         return mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0;
     }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index eefebd5..cbf4b5a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.animation.LayoutTransition;
+import android.animation.ValueAnimator;
 import android.app.ActivityManagerNative;
 import android.content.ClipDescription;
 import android.content.ComponentCallbacks;
@@ -323,8 +324,11 @@
             if (!mInitialized) {
                 try {
                     InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
-                    sWindowSession = Display.getWindowManager().openSession(
+                    IWindowManager windowManager = Display.getWindowManager();
+                    sWindowSession = windowManager.openSession(
                             imm.getClient(), imm.getInputContext());
+                    float animatorScale = windowManager.getAnimationScale(2);
+                    ValueAnimator.setDurationScale(animatorScale);
                     mInitialized = true;
                 } catch (RemoteException e) {
                 }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index e20d12a..67fd059 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1651,6 +1651,7 @@
                 // are focusable
                 if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) {
                     final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild &&
+                            focusLayoutRestoreView != null &&
                             focusLayoutRestoreView.requestFocus()) || sel.requestFocus();
                     if (!focusWasTaken) {
                         // selected item didn't take focus, fine, but still want
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b514bf5..16b7ff3 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2061,7 +2061,7 @@
         </attr>
         <!-- Direction of the text. A heuristic is used to determine the resolved text direction
              of paragraphs. -->
-        <attr name="textDirection" format="integer">
+         <attr name="textDirection" format="integer">
             <!-- Default -->
             <enum name="inherit" value="0" />
             <!-- Default for the root view. The first strong directional character determines the
@@ -2072,16 +2072,12 @@
                  it is LTR if it contains any strong LTR characters.  If there are neither, the
                  paragraph direction is the view’s resolved layout direction. -->
             <enum name="anyRtl" value="2" />
-            <!-- The paragraph direction is the same as the one held by a 60% majority of the
-                 characters. If there is no majority then the paragraph direction is the resolved
-                 layout direction of the View. -->
-            <enum name="charCount" value="3" />
             <!-- The paragraph direction is left to right. -->
-            <enum name="ltr" value="4" />
+            <enum name="ltr" value="3" />
             <!-- The paragraph direction is right to left. -->
-            <enum name="rtl" value="5" />
+            <enum name="rtl" value="4" />
             <!-- The paragraph direction is coming from the system Locale. -->
-            <enum name="locale" value="6" />
+            <enum name="locale" value="5" />
         </attr>
     </declare-styleable>
 
diff --git a/docs/html/index.jd b/docs/html/index.jd
index fdf860a..b9d6758 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -1,5 +1,5 @@
 home=true
-metaDescription=The official site for Android developers. Provides the Android SDK and documentation for app developers and designers.
+page.metaDescription=The official site for Android developers. Provides the Android SDK and documentation for app developers and designers.
 @jd:body
 
 
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 6b12c14..74a1e62 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -248,7 +248,7 @@
     static sp<IAudioPolicyService> gAudioPolicyService;
 
     // mapping between stream types and outputs
-    static DefaultKeyedVector<int, audio_io_handle_t> gStreamOutputMap;
+    static DefaultKeyedVector<audio_stream_type_t, audio_io_handle_t> gStreamOutputMap;
     // list of output descriptors containing cached parameters
     // (sampling rate, framecount, channel count...)
     static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs;
diff --git a/include/utils/threads.h b/include/utils/threads.h
index ab3e8cd..b4a8b7c 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -526,6 +526,12 @@
     // Do not call from this object's thread; will return WOULD_BLOCK in that case.
             status_t    join();
 
+#ifdef HAVE_ANDROID_OS
+    // Return the thread's kernel ID, same as the thread itself calling gettid() or
+    // androidGetTid(), or -1 if the thread is not running.
+            pid_t       getTid() const;
+#endif
+
 protected:
     // exitPending() returns true if requestExit() has been called.
             bool        exitPending() const;
@@ -551,8 +557,10 @@
     volatile bool           mExitPending;
     volatile bool           mRunning;
             sp<Thread>      mHoldSelf;
-#if HAVE_ANDROID_OS
-            int             mTid;
+#ifdef HAVE_ANDROID_OS
+    // legacy for debugging, not used by getTid() as it is set by the child thread
+    // and so is not initialized until the child reaches that point
+            pid_t           mTid;
 #endif
 };
 
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index afc8ba0..929dd68 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -206,7 +206,6 @@
         return false;
     }
 
-    rsAssert(bcWrapper.getHeaderVersion() == 0);
     if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
         sdkVersion = bcWrapper.getTargetAPI();
     }
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 544ab74..24cf504 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -98,7 +98,8 @@
 
 LOCAL_C_INCLUDES += \
 		external/zlib \
-		external/icu4c/common
+		external/icu4c/common \
+		bionic/libc/private
 
 LOCAL_LDLIBS += -lpthread
 
@@ -114,7 +115,10 @@
 
 ifeq ($(TARGET_OS),linux)
 include $(CLEAR_VARS)
-LOCAL_C_INCLUDES += external/zlib external/icu4c/common
+LOCAL_C_INCLUDES += \
+		external/zlib \
+		external/icu4c/common \
+		bionic/libc/private
 LOCAL_LDLIBS := -lrt -ldl -lpthread
 LOCAL_MODULE := libutils
 LOCAL_SRC_FILES := $(commonSources) BackupData.cpp BackupHelpers.cpp
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index e343c62..ab207f5 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -34,6 +34,9 @@
 # include <pthread.h>
 # include <sched.h>
 # include <sys/resource.h>
+#ifdef HAVE_ANDROID_OS
+# include <bionic_pthread.h>
+#endif
 #elif defined(HAVE_WIN32_THREADS)
 # include <windows.h>
 # include <stdint.h>
@@ -86,7 +89,7 @@
     char *          threadName;
 
     // we use this trampoline when we need to set the priority with
-    // nice/setpriority.
+    // nice/setpriority, and name with prctl.
     static int trampoline(const thread_data_t* t) {
         thread_func_t f = t->entryFunction;
         void* u = t->userData;
@@ -141,8 +144,13 @@
 
 #ifdef HAVE_ANDROID_OS  /* valgrind is rejecting RT-priority create reqs */
     if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {
-        // We could avoid the trampoline if there was a way to get to the
-        // android_thread_id_t (pid) from pthread_t
+        // Now that the pthread_t has a method to find the associated
+        // android_thread_id_t (pid) from pthread_t, it would be possible to avoid
+        // this trampoline in some cases as the parent could set the properties
+        // for the child.  However, there would be a race condition because the
+        // child becomes ready immediately, and it doesn't work for the name.
+        // prctl(PR_SET_NAME) only works for self; prctl(PR_SET_THREAD_NAME) was
+        // proposed but not yet accepted.
         thread_data_t* t = new thread_data_t;
         t->priority = threadPriority;
         t->threadName = threadName ? strdup(threadName) : NULL;
@@ -178,6 +186,13 @@
     return 1;
 }
 
+#ifdef HAVE_ANDROID_OS
+static pthread_t android_thread_id_t_to_pthread(android_thread_id_t thread)
+{
+    return (pthread_t) thread;
+}
+#endif
+
 android_thread_id_t androidGetThreadId()
 {
     return (android_thread_id_t)pthread_self();
@@ -909,6 +924,23 @@
     return mStatus;
 }
 
+#ifdef HAVE_ANDROID_OS
+pid_t Thread::getTid() const
+{
+    // mTid is not defined until the child initializes it, and the caller may need it earlier
+    Mutex::Autolock _l(mLock);
+    pid_t tid;
+    if (mRunning) {
+        pthread_t pthread = android_thread_id_t_to_pthread(mThread);
+        tid = __pthread_gettid(pthread);
+    } else {
+        ALOGW("Thread (this=%p): getTid() is undefined before run()", this);
+        tid = -1;
+    }
+    return tid;
+}
+#endif
+
 bool Thread::exitPending() const
 {
     Mutex::Autolock _l(mLock);
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index b640e9a..1c13fff 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -314,10 +314,8 @@
 
     private final String mExternalStoragePath;
 
-    // WARNING: Bulk inserts sounded like a great idea and gave us a good performance improvement,
-    // but unfortunately it also introduced a number of bugs. All the known bugs were fixed,
-    // but we need more testing before enabling.
-    private static final boolean ENABLE_BULK_INSERTS = false;
+    /** whether to use bulk inserts or individual inserts for each item */
+    private static final boolean ENABLE_BULK_INSERTS = true;
 
     // used when scanning the image database so we know whether we have to prune
     // old thumbnail files
diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
index 77d40b6..7f7c7e1 100755
--- a/media/libeffects/preprocessing/Android.mk
+++ b/media/libeffects/preprocessing/Android.mk
@@ -13,7 +13,7 @@
 LOCAL_C_INCLUDES += \
     external/webrtc/src \
     external/webrtc/src/modules/interface \
-    external/webrtc/src/modules/audio_processing/main/interface \
+    external/webrtc/src/modules/audio_processing/interface \
     system/media/audio_effects/include
 
 LOCAL_C_INCLUDES += $(call include-path-for, speex)
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index e988e06..9fd6764 100755
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -24,8 +24,8 @@
 #include <audio_effects/effect_aec.h>
 #include <audio_effects/effect_agc.h>
 #include <audio_effects/effect_ns.h>
-#include "modules/interface/module_common_types.h"
-#include "modules/audio_processing/main/interface/audio_processing.h"
+#include <module_common_types.h>
+#include <audio_processing.h>
 #include "speex/speex_resampler.h"
 
 
@@ -220,8 +220,8 @@
 // Automatic Gain Control (AGC)
 //------------------------------------------------------------------------------
 
-static const int kAgcDefaultTargetLevel = 0;
-static const int kAgcDefaultCompGain = 90;
+static const int kAgcDefaultTargetLevel = 3;
+static const int kAgcDefaultCompGain = 9;
 static const bool kAgcDefaultLimiter = true;
 
 int  AgcInit (preproc_effect_t *effect)
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 124032b..df5017b 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -35,7 +35,8 @@
 sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
 audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
 // Cached values
-DefaultKeyedVector<int, audio_io_handle_t> AudioSystem::gStreamOutputMap(0);
+
+DefaultKeyedVector<audio_stream_type_t, audio_io_handle_t> AudioSystem::gStreamOutputMap(0);
 DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(0);
 
 // Cached values for recording queries, all protected by gLock
@@ -404,7 +405,7 @@
 void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, int ioHandle, void *param2) {
     ALOGV("ioConfigChanged() event %d", event);
     OutputDescriptor *desc;
-    uint32_t stream;
+    audio_stream_type_t stream;
 
     if (ioHandle == 0) return;
 
@@ -413,7 +414,7 @@
     switch (event) {
     case STREAM_CONFIG_CHANGED:
         if (param2 == 0) break;
-        stream = *(uint32_t *)param2;
+        stream = *(audio_stream_type_t *)param2;
         ALOGV("ioConfigChanged() STREAM_CONFIG_CHANGED stream %d, output %d", stream, ioHandle);
         if (gStreamOutputMap.indexOfKey(stream) >= 0) {
             gStreamOutputMap.replaceValueFor(stream, ioHandle);
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 5cc3f78..f3ef3de 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -144,8 +144,8 @@
         return ERROR_UNSUPPORTED;
     }
 
-    uint32_t *dst_ptr = (uint32_t *)dst.mBits
-        + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+    uint16_t *dst_ptr = (uint16_t *)dst.mBits
+        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
     const uint8_t *src_ptr = (const uint8_t *)src.mBits
         + (src.mCropTop * dst.mWidth + src.mCropLeft) * 2;
@@ -182,11 +182,15 @@
                 | ((kAdjustedClip[g2] >> 2) << 5)
                 | (kAdjustedClip[b2] >> 3);
 
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+            if (x + 1 < src.cropWidth()) {
+                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+            } else {
+                dst_ptr[x] = rgb1;
+            }
         }
 
         src_ptr += src.mWidth * 2;
-        dst_ptr += dst.mWidth / 2;
+        dst_ptr += dst.mWidth;
     }
 
     return OK;
@@ -290,15 +294,14 @@
         const BitmapParams &src, const BitmapParams &dst) {
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((dst.mWidth & 3) == 0
-            && (src.mCropLeft & 1) == 0
+    if (!((src.mCropLeft & 1) == 0
             && src.cropWidth() == dst.cropWidth()
             && src.cropHeight() == dst.cropHeight())) {
         return ERROR_UNSUPPORTED;
     }
 
-    uint32_t *dst_ptr = (uint32_t *)dst.mBits
-        + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+    uint16_t *dst_ptr = (uint16_t *)dst.mBits
+        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
     const uint8_t *src_y =
         (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
@@ -340,7 +343,11 @@
                 | ((kAdjustedClip[g2] >> 2) << 5)
                 | (kAdjustedClip[r2] >> 3);
 
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+            if (x + 1 < src.cropWidth()) {
+                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+            } else {
+                dst_ptr[x] = rgb1;
+            }
         }
 
         src_y += src.mWidth;
@@ -349,7 +356,7 @@
             src_u += src.mWidth;
         }
 
-        dst_ptr += dst.mWidth / 2;
+        dst_ptr += dst.mWidth;
     }
 
     return OK;
@@ -361,15 +368,14 @@
 
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((dst.mWidth & 3) == 0
-            && (src.mCropLeft & 1) == 0
+    if (!((src.mCropLeft & 1) == 0
             && src.cropWidth() == dst.cropWidth()
             && src.cropHeight() == dst.cropHeight())) {
         return ERROR_UNSUPPORTED;
     }
 
-    uint32_t *dst_ptr = (uint32_t *)dst.mBits
-        + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+    uint16_t *dst_ptr = (uint16_t *)dst.mBits
+        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
     const uint8_t *src_y =
         (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
@@ -411,7 +417,11 @@
                 | ((kAdjustedClip[g2] >> 2) << 5)
                 | (kAdjustedClip[r2] >> 3);
 
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+            if (x + 1 < src.cropWidth()) {
+                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+            } else {
+                dst_ptr[x] = rgb1;
+            }
         }
 
         src_y += src.mWidth;
@@ -420,7 +430,7 @@
             src_u += src.mWidth;
         }
 
-        dst_ptr += dst.mWidth / 2;
+        dst_ptr += dst.mWidth;
     }
 
     return OK;
@@ -430,15 +440,14 @@
         const BitmapParams &src, const BitmapParams &dst) {
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((dst.mWidth & 3) == 0
-            && (src.mCropLeft & 1) == 0
+    if (!((src.mCropLeft & 1) == 0
             && src.cropWidth() == dst.cropWidth()
             && src.cropHeight() == dst.cropHeight())) {
         return ERROR_UNSUPPORTED;
     }
 
-    uint32_t *dst_ptr = (uint32_t *)dst.mBits
-        + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+    uint16_t *dst_ptr = (uint16_t *)dst.mBits
+        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
     const uint8_t *src_y = (const uint8_t *)src.mBits;
 
@@ -478,7 +487,11 @@
                 | ((kAdjustedClip[g2] >> 2) << 5)
                 | (kAdjustedClip[b2] >> 3);
 
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+            if (x + 1 < src.cropWidth()) {
+                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+            } else {
+                dst_ptr[x] = rgb1;
+            }
         }
 
         src_y += src.mWidth;
@@ -487,7 +500,7 @@
             src_u += src.mWidth;
         }
 
-        dst_ptr += dst.mWidth / 2;
+        dst_ptr += dst.mWidth;
     }
 
     return OK;
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index 0914f32..c79e01f 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -333,8 +333,9 @@
 
 void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &msg) {
     Mutex::Autolock autoLock(mLock);
-
-    switch (msg->what()) {
+    uint32_t msgType = msg->what();
+    ALOGV("msgType = %d", msgType);
+    switch (msgType) {
         case kWhatSendCommand:
         {
             int32_t cmd, param;
@@ -354,27 +355,27 @@
             CHECK(mState == OMX_StateExecuting && mTargetState == mState);
 
             bool found = false;
-            for (size_t i = 0; i < mPorts.size(); ++i) {
-                PortInfo *port = &mPorts.editItemAt(i);
+            size_t portIndex = (kWhatEmptyThisBuffer == msgType)?
+                    header->nInputPortIndex: header->nOutputPortIndex;
+            PortInfo *port = &mPorts.editItemAt(portIndex);
 
-                for (size_t j = 0; j < port->mBuffers.size(); ++j) {
-                    BufferInfo *buffer = &port->mBuffers.editItemAt(j);
+            for (size_t j = 0; j < port->mBuffers.size(); ++j) {
+                BufferInfo *buffer = &port->mBuffers.editItemAt(j);
 
-                    if (buffer->mHeader == header) {
-                        CHECK(!buffer->mOwnedByUs);
+                if (buffer->mHeader == header) {
+                    CHECK(!buffer->mOwnedByUs);
 
-                        buffer->mOwnedByUs = true;
+                    buffer->mOwnedByUs = true;
 
-                        CHECK((msg->what() == kWhatEmptyThisBuffer
-                                    && port->mDef.eDir == OMX_DirInput)
-                                || (port->mDef.eDir == OMX_DirOutput));
+                    CHECK((msgType == kWhatEmptyThisBuffer
+                            && port->mDef.eDir == OMX_DirInput)
+                            || (port->mDef.eDir == OMX_DirOutput));
 
-                        port->mQueue.push_back(buffer);
-                        onQueueFilled(i);
+                    port->mQueue.push_back(buffer);
+                    onQueueFilled(portIndex);
 
-                        found = true;
-                        break;
-                    }
+                    found = true;
+                    break;
                 }
             }
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 2d856ad..0c44f3f 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1740,7 +1740,7 @@
 
     // FIXME - Current mixer implementation only supports stereo output: Always
     // Allocate a stereo buffer even if HW output is mono.
-    if (mMixBuffer != NULL) delete[] mMixBuffer;
+    delete[] mMixBuffer;
     mMixBuffer = new int16_t[mFrameCount * 2];
     memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
 
@@ -2461,6 +2461,8 @@
             }
             if (status == NO_ERROR && reconfig) {
                 delete mAudioMixer;
+                // for safety in case readOutputParameters() accesses mAudioMixer (it doesn't)
+                mAudioMixer = NULL;
                 readOutputParameters();
                 mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
                 for (size_t i = 0; i < mTracks.size() ; i++) {
@@ -4065,7 +4067,7 @@
     mAudioFlinger->removeClient_l(mPid);
 }
 
-const sp<MemoryDealer>& AudioFlinger::Client::heap() const
+sp<MemoryDealer> AudioFlinger::Client::heap() const
 {
     return mMemoryDealer;
 }
@@ -4282,10 +4284,8 @@
 AudioFlinger::RecordThread::~RecordThread()
 {
     delete[] mRsmpInBuffer;
-    if (mResampler != NULL) {
-        delete mResampler;
-        delete[] mRsmpOutBuffer;
-    }
+    delete mResampler;
+    delete[] mRsmpOutBuffer;
 }
 
 void AudioFlinger::RecordThread::onFirstRef()
@@ -4829,9 +4829,11 @@
 
 void AudioFlinger::RecordThread::readInputParameters()
 {
-    if (mRsmpInBuffer) delete mRsmpInBuffer;
-    if (mRsmpOutBuffer) delete mRsmpOutBuffer;
-    if (mResampler) delete mResampler;
+    delete mRsmpInBuffer;
+    // mRsmpInBuffer is always assigned a new[] below
+    delete mRsmpOutBuffer;
+    mRsmpOutBuffer = NULL;
+    delete mResampler;
     mResampler = NULL;
 
     mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common);
@@ -6179,7 +6181,7 @@
     }
 }
 
-status_t AudioFlinger::EffectModule::addHandle(sp<EffectHandle>& handle)
+status_t AudioFlinger::EffectModule::addHandle(const sp<EffectHandle>& handle)
 {
     status_t status;
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 766ba44..ece4ba2 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -226,7 +226,7 @@
     public:
                             Client(const sp<AudioFlinger>& audioFlinger, pid_t pid);
         virtual             ~Client();
-        const sp<MemoryDealer>&     heap() const;
+        sp<MemoryDealer>    heap() const;
         pid_t               pid() const { return mPid; }
         sp<AudioFlinger>    audioFlinger() { return mAudioFlinger; }
 
@@ -1107,7 +1107,7 @@
         void        setThread(const wp<ThreadBase>& thread) { mThread = thread; }
         wp<ThreadBase>& thread() { return mThread; }
 
-        status_t addHandle(sp<EffectHandle>& handle);
+        status_t addHandle(const sp<EffectHandle>& handle);
         void disconnect(const wp<EffectHandle>& handle, bool unpiniflast);
         size_t removeHandle (const wp<EffectHandle>& handle);
 
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index a8102e5..a01c6a8 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -1127,9 +1127,7 @@
         }
     }
 
-    if (buff != NULL) {
-        delete [] buff;
-    }
+    delete [] buff;
 }
 #endif
 
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 2df1385..7695d2b 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -649,7 +649,7 @@
         release_wake_lock(mName.string());
     }
     mAudioCommands.clear();
-    if (mpToneGenerator != NULL) delete mpToneGenerator;
+    delete mpToneGenerator;
 }
 
 void AudioPolicyService::AudioCommandThread::onFirstRef()
@@ -682,8 +682,7 @@
                     ToneData *data = (ToneData *)command->mParam;
                     ALOGV("AudioCommandThread() processing start tone %d on stream %d",
                             data->mType, data->mStream);
-                    if (mpToneGenerator != NULL)
-                        delete mpToneGenerator;
+                    delete mpToneGenerator;
                     mpToneGenerator = new ToneGenerator(data->mStream, 1.0);
                     mpToneGenerator->startTone(data->mType);
                     delete data;
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 7930caf..414ed1e 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -121,6 +121,7 @@
 
     private static final int MSG_PERFORM_POLL = 1;
     private static final int MSG_UPDATE_IFACES = 2;
+    private static final int MSG_REGISTER_GLOBAL_ALERT = 3;
 
     /** Flags to control detail level of poll event. */
     private static final int FLAG_PERSIST_NETWORK = 0x1;
@@ -600,7 +601,7 @@
                 mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget();
 
                 // re-arm global alert for next update
-                registerGlobalAlert();
+                mHandler.obtainMessage(MSG_REGISTER_GLOBAL_ALERT).sendToTarget();
             }
         }
     };
@@ -951,6 +952,10 @@
                     updateIfaces();
                     return true;
                 }
+                case MSG_REGISTER_GLOBAL_ALERT: {
+                    registerGlobalAlert();
+                    return true;
+                }
                 default: {
                     return false;
                 }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 19d94a1..620d74c 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -95,6 +95,7 @@
 import android.util.Slog;
 import android.util.SparseIntArray;
 import android.util.TypedValue;
+import android.view.Choreographer;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.IApplicationToken;
@@ -141,7 +142,8 @@
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
-        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
+        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
+        Choreographer.OnAnimateListener {
     static final String TAG = "WindowManager";
     static final boolean DEBUG = false;
     static final boolean DEBUG_ADD_REMOVE = false;
@@ -456,7 +458,7 @@
     int mDeferredRotationPauseCount;
 
     boolean mLayoutNeeded = true;
-    boolean mAnimationPending = false;
+    boolean mTraversalScheduled = false;
     boolean mDisplayFrozen = false;
     boolean mWaitingForConfig = false;
     boolean mWindowsFreezingScreen = false;
@@ -503,7 +505,9 @@
     final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics();
     final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics();
 
-    H mH = new H();
+    final H mH = new H();
+
+    final Choreographer mChoreographer = Choreographer.getInstance();
 
     WindowState mCurrentFocus = null;
     WindowState mLastFocus = null;
@@ -559,6 +563,7 @@
 
     float mWindowAnimationScale = 1.0f;
     float mTransitionAnimationScale = 1.0f;
+    float mAnimatorDurationScale = 1.0f;
 
     final InputManager mInputManager;
 
@@ -691,6 +696,7 @@
             Looper.prepare();
             WindowManagerService s = new WindowManagerService(mContext, mPM,
                     mHaveInputMethods, mAllowBootMessages);
+            s.mChoreographer.addOnAnimateListener(s);
             android.os.Process.setThreadPriority(
                     android.os.Process.THREAD_PRIORITY_DISPLAY);
             android.os.Process.setCanSelfBackground(false);
@@ -774,6 +780,8 @@
                 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
         mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
                 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
+        mAnimatorDurationScale = Settings.System.getFloat(context.getContentResolver(),
+                Settings.System.ANIMATOR_DURATION_SCALE, mTransitionAnimationScale);
 
         // Track changes to DevicePolicyManager state so we can enable/disable keyguard.
         IntentFilter filter = new IntentFilter();
@@ -4657,6 +4665,7 @@
         switch (which) {
             case 0: mWindowAnimationScale = fixScale(scale); break;
             case 1: mTransitionAnimationScale = fixScale(scale); break;
+            case 2: mAnimatorDurationScale = fixScale(scale); break;
         }
 
         // Persist setting
@@ -4676,6 +4685,9 @@
             if (scales.length >= 2) {
                 mTransitionAnimationScale = fixScale(scales[1]);
             }
+            if (scales.length >= 3) {
+                mAnimatorDurationScale = fixScale(scales[2]);
+            }
         }
 
         // Persist setting
@@ -4686,12 +4698,14 @@
         switch (which) {
             case 0: return mWindowAnimationScale;
             case 1: return mTransitionAnimationScale;
+            case 2: return mAnimatorDurationScale;
         }
         return 0;
     }
 
     public float[] getAnimationScales() {
-        return new float[] { mWindowAnimationScale, mTransitionAnimationScale };
+        return new float[] { mWindowAnimationScale, mTransitionAnimationScale,
+                mAnimatorDurationScale };
     }
 
     public int getSwitchState(int sw) {
@@ -5390,7 +5404,7 @@
                 if (mScreenRotationAnimation.setRotation(rotation, mFxSession,
                         MAX_ANIMATION_DURATION, mTransitionAnimationScale,
                         mCurDisplayWidth, mCurDisplayHeight)) {
-                    requestAnimationLocked(0);
+                    mChoreographer.scheduleAnimation();
                 }
             }
             Surface.setOrientation(0, rotation);
@@ -6513,7 +6527,7 @@
     final class H extends Handler {
         public static final int REPORT_FOCUS_CHANGE = 2;
         public static final int REPORT_LOSING_FOCUS = 3;
-        public static final int ANIMATE = 4;
+        public static final int DO_TRAVERSAL = 4;
         public static final int ADD_STARTING = 5;
         public static final int REMOVE_STARTING = 6;
         public static final int FINISHED_STARTING = 7;
@@ -6607,9 +6621,9 @@
                     }
                 } break;
 
-                case ANIMATE: {
+                case DO_TRAVERSAL: {
                     synchronized(mWindowMap) {
-                        mAnimationPending = false;
+                        mTraversalScheduled = false;
                         performLayoutAndPlaceSurfacesLocked();
                     }
                 } break;
@@ -6825,12 +6839,14 @@
                             Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
                     Settings.System.putFloat(mContext.getContentResolver(),
                             Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
+                    Settings.System.putFloat(mContext.getContentResolver(),
+                            Settings.System.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
                     break;
                 }
 
                 case FORCE_GC: {
                     synchronized(mWindowMap) {
-                        if (mAnimationPending) {
+                        if (mChoreographer.isAnimationScheduled()) {
                             // If we are animating, don't do the gc now but
                             // delay a bit so we don't interrupt the animation.
                             mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
@@ -7389,7 +7405,7 @@
             } else {
                 mInLayout = false;
                 if (mLayoutNeeded) {
-                    requestAnimationLocked(0);
+                    requestTraversalLocked();
                 }
             }
             if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
@@ -8822,10 +8838,9 @@
             needRelayout = adjustWallpaperWindowsLocked() != 0;
         }
         if (needRelayout) {
-            requestAnimationLocked(0);
+            requestTraversalLocked();
         } else if (animating) {
-            final int refreshTimeUs = (int)(1000 / mDisplay.getRefreshRate());
-            requestAnimationLocked(currentTime + refreshTimeUs - SystemClock.uptimeMillis());
+            mChoreographer.scheduleAnimation();
         }
 
         // Finally update all input windows now that the window changes have stabilized.
@@ -8944,10 +8959,17 @@
         }
     }
 
-    void requestAnimationLocked(long delay) {
-        if (!mAnimationPending) {
-            mAnimationPending = true;
-            mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
+    void requestTraversalLocked() {
+        if (!mTraversalScheduled) {
+            mTraversalScheduled = true;
+            mH.sendEmptyMessage(H.DO_TRAVERSAL);
+        }
+    }
+
+    @Override
+    public void onAnimate() {
+        synchronized(mWindowMap) {
+            performLayoutAndPlaceSurfacesLocked();
         }
     }
 
@@ -9267,7 +9289,7 @@
             if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
             if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
                     mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
-                requestAnimationLocked(0);
+                mChoreographer.scheduleAnimation();
             } else {
                 mScreenRotationAnimation = null;
                 updateRotation = true;
@@ -9759,9 +9781,10 @@
             pw.print("  mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation);
                     pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
             pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
-            pw.print("  mAnimationPending="); pw.print(mAnimationPending);
+            pw.print("  mTraversalScheduled="); pw.print(mTraversalScheduled);
                     pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
                     pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
+                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
             pw.print("  mNextAppTransition=0x");
                     pw.print(Integer.toHexString(mNextAppTransition));
                     pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 1067cad..6868cf6 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -1593,7 +1593,7 @@
             mService.applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true);
         }
         if (requestAnim) {
-            mService.requestAnimationLocked(0);
+            mService.mChoreographer.scheduleAnimation();
         }
         return true;
     }
@@ -1634,7 +1634,7 @@
             }
         }
         if (requestAnim) {
-            mService.requestAnimationLocked(0);
+            mService.mChoreographer.scheduleAnimation();
         }
         return true;
     }
diff --git a/tests/BiDiTests/res/layout/basic.xml b/tests/BiDiTests/res/layout/basic.xml
index f503658..7d4d4db 100644
--- a/tests/BiDiTests/res/layout/basic.xml
+++ b/tests/BiDiTests/res/layout/basic.xml
@@ -19,6 +19,10 @@
         android:layout_width="fill_parent"
         android:layout_height="fill_parent">
 
+    <ScrollView
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent">
+
     <LinearLayout android:orientation="vertical"
                   android:layout_width="match_parent"
                   android:layout_height="match_parent">
@@ -131,4 +135,6 @@
 
     </LinearLayout>
 
+    </ScrollView>
+
 </FrameLayout>
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
index 1d4fc84..233cd0d 100644
--- a/tests/BiDiTests/res/values/strings.xml
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -24,11 +24,11 @@
     <string name="button_before_text">Start</string>
     <string name="button_requestlayout_text">Request Layout</string>
     <string name="button_alert_dialog_text">AlertDialog</string>
-    <string name="textview_text">This is a text for a TextView</string>
-    <string name="textview_ltr_text">This is a text for a LTR TextView</string>
-    <string name="textview_rtl_text">This is a text for a RTL TextView</string>
-    <string name="textview_default_text">This is a text for a default TextView</string>
-    <string name="textview_password_default_text">This is a text for a password TextView</string>
+    <string name="textview_text">TextView</string>
+    <string name="textview_ltr_text">LTR TextView</string>
+    <string name="textview_rtl_text">RTL TextView</string>
+    <string name="textview_default_text">Default TextView</string>
+    <string name="textview_password_default_text">Password TextView</string>
     <string name="edittext_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
     <string name="normal_text">Normal String</string>
     <string name="normal_long_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>