Merge "Fix color cube tests."
diff --git a/api/current.txt b/api/current.txt
index 0687456..1eec50e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -19226,6 +19226,7 @@
     field public static final int USAGE_IO_INPUT = 32; // 0x20
     field public static final int USAGE_IO_OUTPUT = 64; // 0x40
     field public static final int USAGE_SCRIPT = 1; // 0x1
+    field public static final int USAGE_SHARED = 128; // 0x80
   }
 
   public static final class Allocation.MipmapControl extends java.lang.Enum {
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index d3839ad..c189ba4 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -22,6 +22,7 @@
 import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
 import static android.net.NetworkIdentity.scrubSubscriberId;
+import static android.net.wifi.WifiInfo.removeDoubleQuotes;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
@@ -279,7 +280,8 @@
     private boolean matchesWifi(NetworkIdentity ident) {
         switch (ident.mType) {
             case TYPE_WIFI:
-                return Objects.equal(mNetworkId, ident.mNetworkId);
+                return Objects.equal(
+                        removeDoubleQuotes(mNetworkId), removeDoubleQuotes(ident.mNetworkId));
             default:
                 return false;
         }
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 123acca..a6e8c70 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -792,8 +792,17 @@
      * the paragraph's primary direction.
      */
     public float getPrimaryHorizontal(int offset) {
+        return getPrimaryHorizontal(offset, false /* not clamped */);
+    }
+
+    /**
+     * Get the primary horizontal position for the specified text offset, but
+     * optionally clamp it so that it doesn't exceed the width of the layout.
+     * @hide
+     */
+    public float getPrimaryHorizontal(int offset, boolean clamped) {
         boolean trailing = primaryIsTrailingPrevious(offset);
-        return getHorizontal(offset, trailing);
+        return getHorizontal(offset, trailing, clamped);
     }
 
     /**
@@ -802,17 +811,26 @@
      * the direction other than the paragraph's primary direction.
      */
     public float getSecondaryHorizontal(int offset) {
-        boolean trailing = primaryIsTrailingPrevious(offset);
-        return getHorizontal(offset, !trailing);
+        return getSecondaryHorizontal(offset, false /* not clamped */);
     }
 
-    private float getHorizontal(int offset, boolean trailing) {
+    /**
+     * Get the secondary horizontal position for the specified text offset, but
+     * optionally clamp it so that it doesn't exceed the width of the layout.
+     * @hide
+     */
+    public float getSecondaryHorizontal(int offset, boolean clamped) {
+        boolean trailing = primaryIsTrailingPrevious(offset);
+        return getHorizontal(offset, !trailing, clamped);
+    }
+
+    private float getHorizontal(int offset, boolean trailing, boolean clamped) {
         int line = getLineForOffset(offset);
 
-        return getHorizontal(offset, trailing, line);
+        return getHorizontal(offset, trailing, line, clamped);
     }
 
-    private float getHorizontal(int offset, boolean trailing, int line) {
+    private float getHorizontal(int offset, boolean trailing, int line, boolean clamped) {
         int start = getLineStart(line);
         int end = getLineEnd(line);
         int dir = getParagraphDirection(line);
@@ -834,6 +852,9 @@
         float wid = tl.measure(offset - start, trailing, null);
         TextLine.recycle(tl);
 
+        if (clamped && wid > mWidth) {
+            wid = mWidth;
+        }
         int left = getParagraphLeft(line);
         int right = getParagraphRight(line);
 
@@ -1257,6 +1278,23 @@
     }
 
     /**
+     * Determine whether we should clamp cursor position. Currently it's
+     * only robust for left-aligned displays.
+     * @hide
+     */
+    public boolean shouldClampCursor(int line) {
+        // Only clamp cursor position in left-aligned displays.
+        switch (getParagraphAlignment(line)) {
+            case ALIGN_LEFT:
+                return true;
+            case ALIGN_NORMAL:
+                return getParagraphDirection(line) > 0;
+            default:
+                return false;
+        }
+
+    }
+    /**
      * Fills in the specified Path with a representation of a cursor
      * at the specified offset.  This will often be a vertical line
      * but can be multiple discontinuous lines in text with multiple
@@ -1270,8 +1308,9 @@
         int top = getLineTop(line);
         int bottom = getLineTop(line+1);
 
-        float h1 = getPrimaryHorizontal(point) - 0.5f;
-        float h2 = isLevelBoundary(point) ? getSecondaryHorizontal(point) - 0.5f : h1;
+        boolean clamped = shouldClampCursor(line);
+        float h1 = getPrimaryHorizontal(point, clamped) - 0.5f;
+        float h2 = isLevelBoundary(point) ? getSecondaryHorizontal(point, clamped) - 0.5f : h1;
 
         int caps = TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_SHIFT_ON) |
                    TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_SELECTING);
@@ -1357,8 +1396,8 @@
                 int en = Math.min(end, there);
 
                 if (st != en) {
-                    float h1 = getHorizontal(st, false, line);
-                    float h2 = getHorizontal(en, true, line);
+                    float h1 = getHorizontal(st, false, line, false /* not clamped */);
+                    float h2 = getHorizontal(en, true, line, false /* not clamped */);
 
                     float left = Math.min(h1, h2);
                     float right = Math.max(h1, h2);
diff --git a/core/java/android/view/SimulatedTrackball.java b/core/java/android/view/SimulatedTrackball.java
index 0eb197e..4ab557a 100644
--- a/core/java/android/view/SimulatedTrackball.java
+++ b/core/java/android/view/SimulatedTrackball.java
@@ -16,13 +16,15 @@
 
 package android.view;
 
+import android.app.SearchManager;
 import android.content.ActivityNotFoundException;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
-import android.os.Handler.Callback;
 import android.os.Message;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.util.Log;
 
 /**
@@ -30,6 +32,8 @@
  * 
  * @see ViewRootImpl
  */
+
+//TODO: Make this class an internal class of ViewRootImpl.java
 class SimulatedTrackball {
 
     private static final String TAG = "SimulatedTrackball";
@@ -43,7 +47,6 @@
     private static final int MSG_FLICK = 313;
     // TODO: Pass touch slop from the input device
     private static final int TOUCH_SLOP = 30;
-
     // The position of the previous touchpad event
     private float mLastTouchpadXPosition;
     private float mLastTouchpadYPosition;
@@ -59,6 +62,8 @@
     // Did the swipe begin in a valid region
     private boolean mEdgeSwipePossible;
 
+    private final Context mContext;
+
     // How quickly keys were sent;
     private int mKeySendRateMs = 0;
     private int mLastKeySent;
@@ -92,7 +97,7 @@
     // How quickly the repeated events die off
     private float mFlickDecay;
 
-    public SimulatedTrackball() {
+    public SimulatedTrackball(Context context) {
         mDistancePerTick = SystemProperties.getInt("persist.vr_dist_tick", 64);
         mDistancePerTickSquared = mDistancePerTick * mDistancePerTick;
         mMaxRepeatDelay = SystemProperties.getInt("persist.vr_repeat_delay", 300);
@@ -102,6 +107,8 @@
                 "persist.sys.vr_flick_decay", "1.3"));
         mTouchSlop = TOUCH_SLOP;
         mTouchSlopSquared = mTouchSlop * mTouchSlop;
+
+        mContext = context;
     }
 
     private final Handler mHandler = new Handler(true /*async*/) {
@@ -167,12 +174,19 @@
                 if (event.getY() < (event.getDevice().getMotionRange(MotionEvent.AXIS_Y).getMax()
                         * .5) && mEdgeSwipePossible) {
                     mEdgeSwipePossible = false;
-                    Intent intent = new Intent("android.search.action.GLOBAL_SEARCH");
-                    intent.addCategory("android.intent.category.DEFAULT");
-                    try {
-                        viewroot.mView.getContext().startActivity(intent);
-                    } catch (ActivityNotFoundException e) {
-                        Log.e(TAG,"Search activity not found.");
+
+                    Intent intent =
+                            ((SearchManager)mContext.getSystemService(Context.SEARCH_SERVICE))
+                            .getAssistIntent(mContext, UserHandle.USER_CURRENT_OR_SELF);
+                    if (intent != null) {
+                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                        try {
+                            mContext.startActivity(intent);
+                        } catch (ActivityNotFoundException e){
+                            Log.e(TAG, "Could not start search activity");
+                        }
+                    } else {
+                        Log.e(TAG, "Could not find a search activity");
                     }
                 }
                 // Find the difference in position between the two most recent
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 080e7c0..97287c3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15509,17 +15509,27 @@
      * handle possible request-during-layout errors correctly.</p>
      */
     public void requestLayout() {
-        ViewRootImpl viewRoot = getViewRootImpl();
-        if (viewRoot != null && viewRoot.isInLayout()) {
-            viewRoot.requestLayoutDuringLayout(this);
-            return;
+        if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {
+            // Only trigger request-during-layout logic if this is the view requesting it,
+            // not the views in its parent hierarchy
+            ViewRootImpl viewRoot = getViewRootImpl();
+            if (viewRoot != null && viewRoot.isInLayout()) {
+                if (!viewRoot.requestLayoutDuringLayout(this)) {
+                    return;
+                }
+            }
+            mAttachInfo.mViewRequestingLayout = this;
         }
+
         mPrivateFlags |= PFLAG_FORCE_LAYOUT;
         mPrivateFlags |= PFLAG_INVALIDATED;
 
         if (mParent != null && !mParent.isLayoutRequested()) {
             mParent.requestLayout();
         }
+        if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) {
+            mAttachInfo.mViewRequestingLayout = null;
+        }
     }
 
     /**
@@ -18000,6 +18010,12 @@
         final Point mPoint = new Point();
 
         /**
+         * Used to track which View originated a requestLayout() call, used when
+         * requestLayout() is called during layout.
+         */
+        View mViewRequestingLayout;
+
+        /**
          * Creates a new set of attachment information with the specified
          * events handler and thread.
          *
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 85fab28..f9f955e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -144,7 +144,7 @@
     final TrackballAxis mTrackballAxisX = new TrackballAxis();
     final TrackballAxis mTrackballAxisY = new TrackballAxis();
 
-    final SimulatedTrackball mSimulatedTrackball = new SimulatedTrackball();
+    final SimulatedTrackball mSimulatedTrackball;
 
     int mLastJoystickXDirection;
     int mLastJoystickYDirection;
@@ -387,6 +387,7 @@
         PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mAttachInfo.mScreenOn = powerManager.isScreenOn();
         loadSystemProperties();
+        mSimulatedTrackball = new SimulatedTrackball(context);
     }
 
     /**
@@ -1894,22 +1895,37 @@
     }
 
     /**
-     * Called by {@link android.view.View#requestLayout()} if the view hiearchy is currently
-     * undergoing a layout pass. requestLayout() should not be called during layout, but if it
-     * is called anyway, we handle the situation here rather than leave the hierarchy in an
-     * indeterminate state. The solution is to queue up all requests during layout, apply those
-     * requests as soon as layout is complete, and then run layout once more immediately. If
+     * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
+     * undergoing a layout pass. requestLayout() should not generally be called during layout,
+     * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
+     * all children in that container hierarchy are measured and laid out at the end of the layout
+     * pass for that container). If requestLayout() is called anyway, we handle it correctly
+     * by registering all requesters during a frame as it proceeds. At the end of the frame,
+     * we check all of those views to see if any still have pending layout requests, which
+     * indicates that they were not correctly handled by their container hierarchy. If that is
+     * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
+     * to blank containers, and force a second request/measure/layout pass in this frame. If
      * more requestLayout() calls are received during that second layout pass, we post those
-     * requests to the next frame, to avoid possible infinite loops.
+     * requests to the next frame to avoid possible infinite loops.
+     *
+     * <p>The return value from this method indicates whether the request should proceed
+     * (if it is a request during the first layout pass) or should be skipped and posted to the
+     * next frame (if it is a request during the second layout pass).</p>
      *
      * @param view the view that requested the layout.
+     *
+     * @return true if request should proceed, false otherwise.
      */
-    void requestLayoutDuringLayout(final View view) {
+    boolean requestLayoutDuringLayout(final View view) {
+        if (view.mParent == null || view.mAttachInfo == null) {
+            // Would not normally trigger another layout, so just let it pass through as usual
+            return true;
+        }
         if (!mHandlingLayoutInLayoutRequest) {
             if (!mLayoutRequesters.contains(view)) {
-                Log.w("View", "requestLayout() called by " + view + " during layout pass");
                 mLayoutRequesters.add(view);
             }
+            return true;
         } else {
             Log.w("View", "requestLayout() called by " + view + " during second layout pass: " +
                     "posting to next frame");
@@ -1919,6 +1935,7 @@
                     view.requestLayout();
                 }
             });
+            return false;
         }
     }
 
@@ -1937,20 +1954,66 @@
         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
         try {
             host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
+
             mInLayout = false;
             int numViewsRequestingLayout = mLayoutRequesters.size();
             if (numViewsRequestingLayout > 0) {
-                // requestLayout() was called during layout: unusual, but try to handle correctly
-                mHandlingLayoutInLayoutRequest = true;
+                // requestLayout() was called during layout.
+                // If no layout-request flags are set on the requesting views, there is no problem.
+                // If some requests are still pending, then we need to clear those flags and do
+                // a full request/measure/layout pass to handle this situation.
+
+                // Check state of layout flags for all requesters
+                ArrayList<View> mValidLayoutRequesters = null;
                 for (int i = 0; i < numViewsRequestingLayout; ++i) {
-                    mLayoutRequesters.get(i).requestLayout();
+                    View view = mLayoutRequesters.get(i);
+                    if ((view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) == View.PFLAG_FORCE_LAYOUT) {
+                        while (view != null && view.mAttachInfo != null && view.mParent != null &&
+                                (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
+                            if ((view.mViewFlags & View.VISIBILITY_MASK) != View.GONE) {
+                                // Only trigger new requests for non-GONE views
+                                Log.w(TAG, "requestLayout() improperly called during " +
+                                        "layout: running second layout pass for " + view);
+                                if (mValidLayoutRequesters == null) {
+                                    mValidLayoutRequesters = new ArrayList<View>();
+                                }
+                                mValidLayoutRequesters.add(view);
+                                break;
+                            }
+                            if (view.mParent instanceof View) {
+                                view = (View) view.mParent;
+                            } else {
+                                view = null;
+                            }
+                        }
+                    }
                 }
-                measureHierarchy(host, lp, mView.getContext().getResources(),
-                        desiredWindowWidth, desiredWindowHeight);
-                // Now run layout one more time
-                mInLayout = true;
-                host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
-                mHandlingLayoutInLayoutRequest = false;
+                if (mValidLayoutRequesters != null) {
+                    // Clear flags throughout hierarchy, walking up from each flagged requester
+                    for (int i = 0; i < numViewsRequestingLayout; ++i) {
+                        View view = mLayoutRequesters.get(i);
+                        while (view != null &&
+                                (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
+                            view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
+                            if (view.mParent instanceof View) {
+                                view = (View) view.mParent;
+                            } else {
+                                view = null;
+                            }
+                        }
+                    }
+                    // Process fresh layout requests, then measure and layout
+                    mHandlingLayoutInLayoutRequest = true;
+                    int numValidRequests = mValidLayoutRequesters.size();
+                    for (int i = 0; i < numValidRequests; ++i) {
+                        mValidLayoutRequesters.get(i).requestLayout();
+                    }
+                    measureHierarchy(host, lp, mView.getContext().getResources(),
+                            desiredWindowWidth, desiredWindowHeight);
+                    mInLayout = true;
+                    host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
+                    mHandlingLayoutInLayoutRequest = false;
+                }
                 mLayoutRequesters.clear();
             }
         } finally {
diff --git a/core/java/android/webkit/GeolocationPermissions.java b/core/java/android/webkit/GeolocationPermissions.java
index 9c0f754..bc3d035 100644
--- a/core/java/android/webkit/GeolocationPermissions.java
+++ b/core/java/android/webkit/GeolocationPermissions.java
@@ -61,7 +61,8 @@
     };
 
     /**
-     * Gets the singleton instance of this class.
+     * Gets the singleton instance of this class. This method cannot be
+     * called before the application instantiates a {@link WebView} instance.
      *
      * @return the singleton {@link GeolocationPermissions} instance
      */
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 9e5a326..ccb84e6 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1278,6 +1278,7 @@
                                 mBrowserFrame = null;
                                 mSettings.onDestroyed();
                                 mNativeClass = 0;
+                                WebCoreThreadWatchdog.unregisterWebView(mWebViewClassic);
                                 mWebViewClassic = null;
                             }
                             break;
@@ -1982,7 +1983,6 @@
             mEventHub.sendMessageAtFrontOfQueue(
                     Message.obtain(null, EventHub.DESTROY));
             mEventHub.blockMessages();
-            WebCoreThreadWatchdog.unregisterWebView(mWebViewClassic);
         }
     }
 
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index ef95af7..41d6033 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1468,20 +1468,24 @@
             middle = (top + bottom) >> 1;
         }
 
-        updateCursorPosition(0, top, middle, getPrimaryHorizontal(layout, hintLayout, offset));
+        boolean clamped = layout.shouldClampCursor(line);
+        updateCursorPosition(0, top, middle,
+                getPrimaryHorizontal(layout, hintLayout, offset, clamped));
 
         if (mCursorCount == 2) {
-            updateCursorPosition(1, middle, bottom, layout.getSecondaryHorizontal(offset));
+            updateCursorPosition(1, middle, bottom,
+                    layout.getSecondaryHorizontal(offset, clamped));
         }
     }
 
-    private float getPrimaryHorizontal(Layout layout, Layout hintLayout, int offset) {
+    private float getPrimaryHorizontal(Layout layout, Layout hintLayout, int offset,
+            boolean clamped) {
         if (TextUtils.isEmpty(layout.getText()) &&
                 hintLayout != null &&
                 !TextUtils.isEmpty(hintLayout.getText())) {
-            return hintLayout.getPrimaryHorizontal(offset);
+            return hintLayout.getPrimaryHorizontal(offset, clamped);
         } else {
-            return layout.getPrimaryHorizontal(offset);
+            return layout.getPrimaryHorizontal(offset, clamped);
         }
     }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0641df6..d635de6 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6553,15 +6553,6 @@
 
         int line = layout.getLineForOffset(offset);
 
-        // FIXME: Is it okay to truncate this, or should we round?
-        final int x = (int)layout.getPrimaryHorizontal(offset);
-        final int top = layout.getLineTop(line);
-        final int bottom = layout.getLineTop(line + 1);
-
-        int left = (int) FloatMath.floor(layout.getLineLeft(line));
-        int right = (int) FloatMath.ceil(layout.getLineRight(line));
-        int ht = layout.getHeight();
-
         int grav;
 
         switch (layout.getParagraphAlignment(line)) {
@@ -6583,8 +6574,32 @@
                 break;
         }
 
+        // We only want to clamp the cursor to fit within the layout width
+        // in left-to-right modes, because in a right to left alignment,
+        // we want to scroll to keep the line-right on the screen, as other
+        // lines are likely to have text flush with the right margin, which
+        // we want to keep visible.
+        // A better long-term solution would probably be to measure both
+        // the full line and a blank-trimmed version, and, for example, use
+        // the latter measurement for centering and right alignment, but for
+        // the time being we only implement the cursor clamping in left to
+        // right where it is most likely to be annoying.
+        final boolean clamped = grav > 0;
+        // FIXME: Is it okay to truncate this, or should we round?
+        final int x = (int)layout.getPrimaryHorizontal(offset, clamped);
+        final int top = layout.getLineTop(line);
+        final int bottom = layout.getLineTop(line + 1);
+
+        int left = (int) FloatMath.floor(layout.getLineLeft(line));
+        int right = (int) FloatMath.ceil(layout.getLineRight(line));
+        int ht = layout.getHeight();
+
         int hspace = mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight();
         int vspace = mBottom - mTop - getExtendedPaddingTop() - getExtendedPaddingBottom();
+        if (!mHorizontallyScrolling && right - left > hspace && right > x) {
+            // If cursor has been clamped, make sure we don't scroll.
+            right = Math.max(x, left + hspace);
+        }
 
         int hslack = (bottom - top) / 2;
         int vslack = hslack;
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 3315045..f8715fe 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -18,7 +18,7 @@
 
 #include <stdio.h>
 
-#include <gui/SurfaceTexture.h>
+#include <gui/GLConsumer.h>
 #include <gui/SurfaceTextureClient.h>
 
 #include <android_runtime/AndroidRuntime.h>
@@ -48,10 +48,10 @@
 // ----------------------------------------------------------------------------
 
 static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
-        const sp<SurfaceTexture>& surfaceTexture)
+        const sp<GLConsumer>& surfaceTexture)
 {
-    SurfaceTexture* const p =
-        (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture);
+    GLConsumer* const p =
+        (GLConsumer*)env->GetIntField(thiz, fields.surfaceTexture);
     if (surfaceTexture.get()) {
         surfaceTexture->incStrong(thiz);
     }
@@ -62,10 +62,10 @@
 }
 
 static void SurfaceTexture_setFrameAvailableListener(JNIEnv* env,
-        jobject thiz, sp<SurfaceTexture::FrameAvailableListener> listener)
+        jobject thiz, sp<GLConsumer::FrameAvailableListener> listener)
 {
-    SurfaceTexture::FrameAvailableListener* const p =
-        (SurfaceTexture::FrameAvailableListener*)
+    GLConsumer::FrameAvailableListener* const p =
+        (GLConsumer::FrameAvailableListener*)
             env->GetIntField(thiz, fields.frameAvailableListener);
     if (listener.get()) {
         listener->incStrong(thiz);
@@ -76,16 +76,16 @@
     env->SetIntField(thiz, fields.frameAvailableListener, (int)listener.get());
 }
 
-sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env,
+sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env,
         jobject thiz)
 {
-    return (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture);
+    return (GLConsumer*)env->GetIntField(thiz, fields.surfaceTexture);
 }
 
 sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(
         JNIEnv* env, jobject thiz)
 {
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
     sp<SurfaceTextureClient> surfaceTextureClient(surfaceTexture != NULL ?
             new SurfaceTextureClient(surfaceTexture->getBufferQueue()) : NULL);
     return surfaceTextureClient;
@@ -99,7 +99,7 @@
 
 // ----------------------------------------------------------------------------
 
-class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener
+class JNISurfaceTextureContext : public GLConsumer::FrameAvailableListener
 {
 public:
     JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz);
@@ -200,7 +200,7 @@
 static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName,
         jobject weakThiz, jboolean allowSynchronous)
 {
-    sp<SurfaceTexture> surfaceTexture(new SurfaceTexture(texName, allowSynchronous));
+    sp<GLConsumer> surfaceTexture(new GLConsumer(texName, allowSynchronous));
     if (surfaceTexture == 0) {
         jniThrowException(env, OutOfResourcesException,
                 "Unable to create native SurfaceTexture");
@@ -223,7 +223,7 @@
 
 static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz)
 {
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
     surfaceTexture->setFrameAvailableListener(0);
     SurfaceTexture_setFrameAvailableListener(env, thiz, 0);
     SurfaceTexture_setSurfaceTexture(env, thiz, 0);
@@ -232,13 +232,13 @@
 static void SurfaceTexture_setDefaultBufferSize(
         JNIEnv* env, jobject thiz, jint width, jint height)
 {
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
     surfaceTexture->setDefaultBufferSize(width, height);
 }
 
 static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
 {
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
     status_t err = surfaceTexture->updateTexImage();
     if (err == INVALID_OPERATION) {
         jniThrowException(env, IllegalStateException, "Unable to update texture contents (see "
@@ -250,20 +250,20 @@
 
 static jint SurfaceTexture_detachFromGLContext(JNIEnv* env, jobject thiz)
 {
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
     return surfaceTexture->detachFromContext();
 }
 
 static jint SurfaceTexture_attachToGLContext(JNIEnv* env, jobject thiz, jint tex)
 {
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
     return surfaceTexture->attachToContext((GLuint)tex);
 }
 
 static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz,
         jfloatArray jmtx)
 {
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
     float* mtx = env->GetFloatArrayElements(jmtx, NULL);
     surfaceTexture->getTransformMatrix(mtx);
     env->ReleaseFloatArrayElements(jmtx, mtx, 0);
@@ -271,13 +271,13 @@
 
 static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz)
 {
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
     return surfaceTexture->getTimestamp();
 }
 
 static void SurfaceTexture_release(JNIEnv* env, jobject thiz)
 {
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
     surfaceTexture->abandon();
 }
 
diff --git a/core/jni/android_emoji_EmojiFactory.cpp b/core/jni/android_emoji_EmojiFactory.cpp
index a658561..4383997 100644
--- a/core/jni/android_emoji_EmojiFactory.cpp
+++ b/core/jni/android_emoji_EmojiFactory.cpp
@@ -3,8 +3,7 @@
 
 #define LOG_TAG "EmojiFactory_jni"
 #include <utils/Log.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
+#include <ScopedUtfChars.h>
 
 #include "EmojiFactory.h"
 #include <nativehelper/JNIHelp.h>
@@ -125,16 +124,13 @@
     return NULL;
   }
 
-  const jchar* jchars = env->GetStringChars(name, NULL);
-  jsize len = env->GetStringLength(name);
-  String8 str(String16(jchars, len));
+  ScopedUtfChars nameUtf(env, name);
 
-  EmojiFactory *factory = gCaller->TryCallGetImplementation(str.string());
+  EmojiFactory *factory = gCaller->TryCallGetImplementation(nameUtf.c_str());
   // EmojiFactory *factory = EmojiFactory::GetImplementation(str.string());
   if (NULL == factory) {
     return NULL;
   }
-  env->ReleaseStringChars(name, jchars);
 
   return create_java_EmojiFactory(env, factory, name);
 }
@@ -151,8 +147,8 @@
   if (NULL == factory) {
     return NULL;
   }
-  String16 name_16(String8(factory->Name()));
-  jstring jname = env->NewString(name_16.string(), name_16.size());
+
+  jstring jname = env->NewStringUTF(factory->Name());
   if (NULL == jname) {
     return NULL;
   }
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index d39f565c..0e0893b 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -27,7 +27,7 @@
 #include <cutils/properties.h>
 #include <utils/Vector.h>
 
-#include <gui/SurfaceTexture.h>
+#include <gui/GLConsumer.h>
 #include <gui/Surface.h>
 #include <camera/Camera.h>
 #include <binder/IMemory.h>
@@ -555,7 +555,7 @@
 
     sp<BufferQueue> bufferQueue = NULL;
     if (jSurfaceTexture != NULL) {
-        sp<SurfaceTexture> surfaceTexture =
+        sp<GLConsumer> surfaceTexture =
             SurfaceTexture_getSurfaceTexture(env, jSurfaceTexture);
         if (surfaceTexture != NULL) {
             bufferQueue = surfaceTexture->getBufferQueue();
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
index 5d24f61..a340fa1 100644
--- a/core/jni/android_media_RemoteDisplay.cpp
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -27,7 +27,7 @@
 
 #include <binder/IServiceManager.h>
 
-#include <gui/ISurfaceTexture.h>
+#include <gui/IGraphicBufferProducer.h>
 
 #include <media/IMediaPlayerService.h>
 #include <media/IRemoteDisplay.h>
@@ -60,14 +60,14 @@
     }
 
 public:
-    virtual void onDisplayConnected(const sp<ISurfaceTexture>& surfaceTexture,
+    virtual void onDisplayConnected(const sp<IGraphicBufferProducer>& bufferProducer,
             uint32_t width, uint32_t height, uint32_t flags) {
         JNIEnv* env = AndroidRuntime::getJNIEnv();
 
-        jobject surfaceObj = android_view_Surface_createFromISurfaceTexture(env, surfaceTexture);
+        jobject surfaceObj = android_view_Surface_createFromISurfaceTexture(env, bufferProducer);
         if (surfaceObj == NULL) {
             ALOGE("Could not create Surface from surface texture %p provided by media server.",
-                    surfaceTexture.get());
+                  bufferProducer.get());
             return;
         }
 
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
index 4e6ee4a..76e42bc 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -98,6 +98,7 @@
     if (!lpToneGen->isInited()) {
         ALOGE("ToneGenerator init failed");
         jniThrowRuntimeException(env, "Init failed");
+        delete lpToneGen;
         return;
     }
 
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 2b265db..9c7124a 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -28,7 +28,7 @@
 #include <EGL/egl.h>
 
 #include <gui/Surface.h>
-#include <gui/SurfaceTexture.h>
+#include <gui/GLConsumer.h>
 #include <gui/SurfaceTextureClient.h>
 
 #include <ui/ANativeObjectBase.h>
@@ -605,7 +605,7 @@
     jint _remaining;
     EGLint *attrib_list = (EGLint *) 0;
     android::sp<ANativeWindow> window;
-    android::sp<android::SurfaceTexture> surfaceTexture;
+    android::sp<android::GLConsumer> surfaceTexture;
 
     if (!attrib_list_ref) {
         _exception = 1;
diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp
index 28746ce..463d3c0 100644
--- a/core/jni/android_util_StringBlock.cpp
+++ b/core/jni/android_util_StringBlock.cpp
@@ -52,6 +52,7 @@
 
     if (osb == NULL || osb->getError() != NO_ERROR) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        delete osb;
         return 0;
     }
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 5d306d2..d8d55b2 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -24,7 +24,7 @@
 
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
-#include <gui/SurfaceTexture.h>
+#include <gui/GLConsumer.h>
 
 #include <androidfw/ResourceTypes.h>
 
@@ -806,7 +806,7 @@
 static void android_view_GLES20Canvas_updateTextureLayer(JNIEnv* env, jobject clazz,
         Layer* layer, jint width, jint height, jboolean isOpaque, jobject surface) {
     float transform[16];
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
+    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
 
     if (surfaceTexture->updateTexImage() == NO_ERROR) {
         surfaceTexture->getTransformMatrix(transform);
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 2767e94..1f15370 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -28,7 +28,7 @@
 #include <gui/ISurfaceComposer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
-#include <gui/SurfaceTexture.h>
+#include <gui/GLConsumer.h>
 
 #include <ui/DisplayInfo.h>
 #include <ui/Rect.h>
@@ -234,7 +234,7 @@
     }
 }
 
-static sp<ISurfaceTexture> getISurfaceTexture(JNIEnv* env, jobject surfaceObj) {
+static sp<IGraphicBufferProducer> getISurfaceTexture(JNIEnv* env, jobject surfaceObj) {
     if (surfaceObj) {
         sp<Surface> surface(getSurface(env, surfaceObj));
         if (surface != NULL) {
@@ -245,12 +245,12 @@
 }
 
 jobject android_view_Surface_createFromISurfaceTexture(JNIEnv* env,
-        const sp<ISurfaceTexture>& surfaceTexture) {
-    if (surfaceTexture == NULL) {
+        const sp<IGraphicBufferProducer>& bufferProducer) {
+    if (bufferProducer == NULL) {
         return NULL;
     }
 
-    sp<Surface> surface(new Surface(surfaceTexture));
+    sp<Surface> surface(new Surface(bufferProducer));
     if (surface == NULL) {
         return NULL;
     }
@@ -258,7 +258,7 @@
     jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz, gSurfaceClassInfo.ctor);
     if (surfaceObj == NULL) {
         if (env->ExceptionCheck()) {
-            ALOGE("Could not create instance of Surface from ISurfaceTexture.");
+            ALOGE("Could not create instance of Surface from IGraphicBufferProducer.");
             LOGE_EX(env);
             env->ExceptionClear();
         }
@@ -289,14 +289,14 @@
 
 static void nativeCreateFromSurfaceTexture(JNIEnv* env, jobject surfaceObj,
         jobject surfaceTextureObj) {
-    sp<SurfaceTexture> st(SurfaceTexture_getSurfaceTexture(env, surfaceTextureObj));
+    sp<GLConsumer> st(SurfaceTexture_getSurfaceTexture(env, surfaceTextureObj));
     if (st == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException",
                 "SurfaceTexture has already been released");
         return;
     }
 
-    sp<ISurfaceTexture> bq = st->getBufferQueue();
+    sp<IGraphicBufferProducer> bq = st->getBufferQueue();
 
     sp<Surface> surface(new Surface(bq));
     if (surface == NULL) {
@@ -667,8 +667,8 @@
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
     if (token == NULL) return;
 
-    sp<ISurfaceTexture> surfaceTexture(getISurfaceTexture(env, surfaceObj));
-    SurfaceComposerClient::setDisplaySurface(token, surfaceTexture);
+    sp<IGraphicBufferProducer> bufferProducer(getISurfaceTexture(env, surfaceObj));
+    SurfaceComposerClient::setDisplaySurface(token, bufferProducer);
 }
 
 static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 854c9ae..87b312f 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -22,7 +22,7 @@
 #include <ui/Region.h>
 #include <ui/Rect.h>
 
-#include <gui/SurfaceTexture.h>
+#include <gui/GLConsumer.h>
 #include <gui/SurfaceTextureClient.h>
 
 #include <SkBitmap.h>
@@ -67,8 +67,8 @@
 static void android_view_TextureView_setDefaultBufferSize(JNIEnv* env, jobject,
     jobject surface, jint width, jint height) {
 
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
-    surfaceTexture->setDefaultBufferSize(width, height);
+    sp<GLConsumer> glConsumer(SurfaceTexture_getSurfaceTexture(env, surface));
+    glConsumer->setDefaultBufferSize(width, height);
 }
 
 static inline SkBitmap::Config convertPixelFormat(int32_t format) {
@@ -101,8 +101,8 @@
 static void android_view_TextureView_createNativeWindow(JNIEnv* env, jobject textureView,
         jobject surface) {
 
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
-    sp<ANativeWindow> window = new SurfaceTextureClient(surfaceTexture->getBufferQueue());
+    sp<GLConsumer> glConsumer(SurfaceTexture_getSurfaceTexture(env, surface));
+    sp<ANativeWindow> window = new SurfaceTextureClient(glConsumer->getBufferQueue());
 
     window->incStrong(0);
     SET_INT(textureView, gTextureViewClassInfo.nativeWindow, jint(window.get()));
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 1c9562e..199d5bf 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -27,7 +27,7 @@
 #include <GLES/gl.h>
 
 #include <gui/Surface.h>
-#include <gui/SurfaceTexture.h>
+#include <gui/GLConsumer.h>
 #include <gui/SurfaceTextureClient.h>
 
 #include <SkBitmap.h>
@@ -353,9 +353,9 @@
         return 0;
     }
     
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(_env, native_window));
+    sp<GLConsumer> glConsumer(SurfaceTexture_getSurfaceTexture(_env, native_window));
 
-    window = new SurfaceTextureClient(surfaceTexture->getBufferQueue());
+    window = new SurfaceTextureClient(glConsumer->getBufferQueue());
     if (window == NULL)
         goto not_valid_surface;
 
diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
index 3ca7b80..b4faa58 100644
--- a/docs/html/develop/index.jd
+++ b/docs/html/develop/index.jd
@@ -121,26 +121,26 @@
 			<div class="feed-frame">
                                 <!-- DEVELOPER NEWS -->
           <ul>
-            <li><a href="http://android-developers.blogspot.com/2012/10/google-play-seller-support-in-india.html">
-              <div class="feed-image" style="background:url('http://4.bp.blogspot.com/-ekT-9XQi0YY/UH7WT2XjSdI/AAAAAAAABwc/fI5QaPi7QEk/s320/india-apps1.png') no-repeat 0 0"></div>
-              <h4>Google Play Seller Support in India</h4>
-              <p>Developers in India can sell paid applications, in-app products, and subscriptions in Google Play, with monthly payouts to their local bank accounts...</p>
+            <li><a href="http://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html">
+              <div class="feed-image" style="background:url('{@docRoot}images/home/play_logo.png') no-repeat 0 0"></div>
+              <h4>Localized Promo Graphics on Google Play</h4>
+              <p>Google Play now lets you provide different promotional graphics, screenshots, and videos for each language you support...</p>
               </a></li>
-            <li><a href="http://android-developers.blogspot.com/2012/09/google-play-services-and-oauth-identity.html">
-              <div class="feed-image" style="background:url('https://lh4.ggpht.com/7z4NItEg-X21zvFGAarKonk-VaysBYthJ30u1JjaQ0-5fjyHNawnmoNeG--4FCACog=w124') no-repeat 0 0"></div>
+            <li><a href="//android-developers.blogspot.com/2012/12/in-app-billing-version-3.html">
+              <div class="feed-image" style="background:url('{@docRoot}images/iab-thumb.png') no-repeat 0 0;background-position:center right;"></div>
+              <h4>In-app Billing Version 3 Now Available</h4>
+              <p>A new version of In-app Billing is available that lets you sell digital goods in your app with just a few lines of code...</p>
+              </a></li>
+            <li><a href="//android-developers.blogspot.com/2012/11/designing-for-tablets-were-here-to-help.html">
+              <div class="feed-image" style="background:url('{@docRoot}design/media/multipane_expand.png') no-repeat 0 0; background-position:right top;"></div>
+              <h4>Designing for Tablets?</h4>
+              <p>Essential resources for everyone in the app development pipeline—from product managers, to designers, to developers, and QA engineers...</p>
+              </a></li>
+            <li><a href="//developer.android.com/google/play-services/index.html">
+              <div class="feed-image" style="background:url('//lh4.ggpht.com/7z4NItEg-X21zvFGAarKonk-VaysBYthJ30u1JjaQ0-5fjyHNawnmoNeG--4FCACog=w124') no-repeat 0 0"></div>
               <h4>Google Play services and OAuth Tools</h4>
               <p>The rollout of Google Play services to all Android 2.2+ devices worldwide is now complete, and all of those devices now have new tools for working with OAuth 2.0 tokens...</p>
               </a></li>
-            <li><a href="http://android-developers.blogspot.com/2012/08/creating-your-own-spelling-checker.html">
-              <div class="feed-image" style="background:url('http://2.bp.blogspot.com/-QKlztEdM1aA/UC1bH6Kv4UI/AAAAAAAAADo/fQS8-EfBYIQ/s320/spell-check-framed-new.png') no-repeat 0 0"></div>
-              <h4>Creating A Spelling Checker Service</h4>
-              <p>If you are an IME developer, the Spelling Checker framework gives you a great way to provide an even better experience for your users...</p>
-              </a></li>
-            <li><a href="http://android-developers.blogspot.com/2012/04/accessibility-are-you-serving-all-your.html">
-              <div class="feed-image"></div>
-              <h4>Accessibility</h4>
-              <p>We recently published some new resources to help developers make their Android applications more accessible... </p>
-              </a></li>                         
           </ul>
                                 <!-- FEATURED DOCS -->
           <ul>
diff --git a/docs/html/distribute/googleplay/about/distribution.jd b/docs/html/distribute/googleplay/about/distribution.jd
index aff5dab..982bb1f 100644
--- a/docs/html/distribute/googleplay/about/distribution.jd
+++ b/docs/html/distribute/googleplay/about/distribution.jd
@@ -24,7 +24,7 @@
 automatic updates of your app, so that your updates are delivered and installed
 as soon as you publish them.</p>
 
-<h2>Reaching the customers you want</h2>
+<h2 id="targeting">Reaching the customers you want</h2>
 
 <p>Google Play does more than connect your app with users&mdash;it helps you
 reach the broadest possible distribution across the Android ecosystem, while
@@ -45,7 +45,12 @@
 <p>When users visit the store, Google Play makes sure that they are in one of
 your targeted countries before downloading your app. You can change your country
 and carrier targeting at any time just by saving changes in the Google Play
-Android Developer Console</p>
+Android Developer Console.</p>
+
+<p>To help you market to users around the world, you
+can <a href="{@docRoot}distribute/googleplay/publish/preparing.html#localize">localize
+your store listing</a>, including app details and description,
+promotional graphics, screenshots, and more.</p>
 
 <div style="float:right;margin-left:18px;border:1px solid #DDD;margin:1.5em;">
 <img src="{@docRoot}images/gp-supported-dev-requirements.png"
diff --git a/docs/html/distribute/googleplay/publish/preparing.jd b/docs/html/distribute/googleplay/publish/preparing.jd
index 9b623e3..097f163 100644
--- a/docs/html/distribute/googleplay/publish/preparing.jd
+++ b/docs/html/distribute/googleplay/publish/preparing.jd
@@ -347,11 +347,12 @@
 needs and start the work of localizing well in advance of your target
 launch date.</p>
 
-<p>There are at least two aspects of localization to consider:</p>
+<p>There are at least three aspects of localization to consider:</p>
 
 <ul>
 <li>Localizing the strings, images, and other resources in your app</li>
-<li>Localizing you app's store listing details on Google Play</li>
+<li>Localizing your app's store listing details on Google Play</li>
+<li>Localizing the app's graphic assets, screenshots, and videos that accompany your store listing.</li>
 </ul>
 
 <p>To get started localizing your app, work with your development team to extract
@@ -361,7 +362,18 @@
 
 <p>To localize your store listing, first create and finalize your app title, description, 
 and promotional text. Collect and send all of these for localization. You can optionally
-translate the "Recent Changes" text for app updates as well.</p>
+translate the "Recent Changes" text for app updates as well. Later you can add your localized
+listing details in the Developer Console, or you can  choose to let Google Play auto-translate
+your listing details into the languages you support.</p>
+
+<p>A key part of making your app listing attractive to a global customer base is
+creating localized versions of your promotional graphics, screenshots and
+videos. For example, your app's feature graphic might include text that should
+be translated, for maximum effectiveness. You can create different versions of
+your promotional graphics for each language and upload them to the Developer
+Console. If you offer a promotional video, you can create localized versions of
+it and then add a link to the correct localized video for each language you
+support.</p>
 
 <p>When your translations are complete, move them into your app resources as needed and test
 that they are loaded properly. Save your app's translated listing details for later,
@@ -377,7 +389,7 @@
 </tr>
 </table>
 
-<h2 id="graphics">12. Prepare promotional graphics</h2>
+<h2 id="graphics">12. Prepare promotional graphics, screenshots, and videos</h2>
 
 <p>When you publish on Google Play, you can supply a variety of high-quality
 graphic assets to showcase your app or brand. After you publish, these appear on
@@ -385,8 +397,16 @@
 These graphic assets are key parts of a successful product details page that
 attracts and engages users, so you should consider having a professional produce
 them for you. Screen shots and videos are also very important, because they show
-what your app looks like, how it's used or played, and what makes it different.
+what your app looks like, how it's used or played, and what makes it different.</p>
 
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h3>Localize your promotional graphics and videos<span class="new"> new!</span></h3>
+<p>Google Play now lets you provide different promotional graphics for each
+language you support. Localizing your graphics helps you reach your global
+user base more effectively and is highly recommended.</p>
+</div>
+</div>
 <p>All of your graphic assets should be designed so that they are easy to see
 and highlight your app or brand in a colorful, interesting way. The assets
 should reference the same logo and icon as users will actually find in the All
@@ -394,8 +414,24 @@
 fit in well with the graphic assets of other apps published by you, which will
 be also be displayed to users on your product details page. </p>
 
-<p>Because these assets are so important, you should get started on them well in
-advance of your target publishing date. </p>
+<p>To help you market your app more effectively to a global audience, Google
+Play lets you create localized versions of your promotional graphics,
+screenshots, and videos and upload them to the Developer Console. When a user
+visits your app's store listing, Google Play displays the promotional graphic
+and video that you've provided for the user's language.</p>
+
+<p>To localize your promotional graphics, you can translate any embedded text, use
+different imagery or presentation, or change your marketing approach to best address the needs
+of users in specific languages. For example, if your feature or promotional graphic
+includes and embedded product name or tag line, you can translate that text
+and add it to a localized version of the promotional graphic.</p>
+
+<p>Because your localized graphic assets and videos are so important, you should get
+started on creating them and localizing them as needed, well in advance of your target
+publishing date. </p>
+
+<p class="note"><strong>Note:</strong> Localized promotional graphics and videos are supported
+in the Developer Console Preview only.</p>
 
 <table>
 <tr>
@@ -403,6 +439,8 @@
 <ul style="margin-top:-.5em;">
 <li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1078870">Graphic Assets for your Application
 </a></strong> &mdash; Details about the graphic assets you need to upload before publishing.</li>
+<li><strong><a href="http://android-developers.blogspot.com/b/post-preview?token=hbE_njsBAAA.dLFzPbe-VFYCS6R3xP16HQ.Z4XO2iUmCqyYpoFPQ4OhiQ&postId=687446965502713273&type=POST">Google Play Featured Image Guidelines
+</a></strong> &mdash; Blog post that highlights key design considerations for your app's featured image.</li>
 </ul>
 </td>
 </tr>
@@ -464,6 +502,10 @@
 page, make sure that you can enter or upload it to the Developer Console, until 
 the page is complete and ready for publishing. </p>
 
+<p>After you've set your app's geographic targeting in the Developer Console,
+remember to add your localized product details, promotional graphics, and so on, for all of the
+languages that you support.</p>
+
 <p>If your app is targeting tablet devices, make sure to include at least one screen
 shot of the app running on a tablet, and highlight your app's support for tablets
 in the app description, release notes, promotional campaigns, and elsewhere.</p>
diff --git a/docs/html/guide/practices/app-design/jni.jd b/docs/html/guide/practices/app-design/jni.jd
deleted file mode 100644
index ddfa0e3..0000000
--- a/docs/html/guide/practices/app-design/jni.jd
+++ /dev/null
@@ -1,719 +0,0 @@
-page.title=JNI Tips
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-<h2>In this document</h2>
-<ol>
-  <li><a href="#JavaVM_and_JNIEnv">JavaVM and JNIEnv</a></li>
-  <li><a href="#threads">Threads</a></li>
-  <li><a href="#jclass_jmethodID_and_jfieldID">jclass, jmethodID, and jfieldID</a></li>
-  <li><a href="#local_and_global_references">Local and Global References</a></li>
-  <li><a href="#UTF_8_and_UTF_16_strings">UTF-8 and UTF-16 Strings</a></li>
-  <li><a href="#arrays">Primitive Arrays</a></li>
-  <li><a href="#region_calls">Region Calls</a></li>
-  <li><a href="#exceptions">Exceptions</a></li>
-  <li><a href="#extended_checking">Extended Checking</a> </li>
-  <li><a href="#native_libraries">Native Libraries</a></li>
-  <li><a href="#64_bit">64-bit Considerations</a></li>
-  <li><a href="#unsupported">Unsupported Features/Backwards Compatibility</a></li>
-  <li><a href="#faq_ULE">FAQ: Why do I get <code>UnsatisfiedLinkError</code></a></li>
-  <li><a href="#faq_FindClass">FAQ: Why didn't <code>FindClass</code> find my class?</a></li>
-  <li><a href="#faq_sharing">FAQ: How do I share raw data with native code?</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>JNI is the Java Native Interface.  It defines a way for managed code
-(written in the Java programming language) to interact with native
-code (written in C/C++).  It's vendor-neutral, has support for loading code from
-dynamic shared libraries, and while cumbersome at times is reasonably efficient.</p>
-
-<p>You really should read through the
-<a href="http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html">JNI spec for J2SE 6</a>
-to get a sense for how JNI works and what features are available.  Some
-aspects of the interface aren't immediately obvious on
-first reading, so you may find the next few sections handy.
-There's a more detailed <a href="http://java.sun.com/docs/books/jni/html/jniTOC.html">JNI Programmer's Guide and Specification</a>.</p>
-
-
-<a name="JavaVM_and_JNIEnv" id="JavaVM_and_JNIEnv"></a>
-<h2>JavaVM and JNIEnv</h2>
-
-<p>JNI defines two key data structures, "JavaVM" and "JNIEnv".  Both of these are essentially
-pointers to pointers to function tables.  (In the C++ version, they're classes with a
-pointer to a function table and a member function for each JNI function that indirects through
-the table.)  The JavaVM provides the "invocation interface" functions,
-which allow you to create and destroy a JavaVM.  In theory you can have multiple JavaVMs per process,
-but Android only allows one.</p>
-
-<p>The JNIEnv provides most of the JNI functions.  Your native functions all receive a JNIEnv as
-the first argument.</p>
-
-<p>The JNIEnv is used for thread-local storage.  For this reason, <strong>you cannot share a JNIEnv between threads</strong>.
-If a piece of code has no other way to get its JNIEnv, you should share
-the JavaVM, and use <code>GetEnv</code> to discover the thread's JNIEnv. (Assuming it has one; see <code>AttachCurrentThread</code> below.)</p>
-
-<p>The C declarations of JNIEnv and JavaVM are different from the C++
-declarations.  The <code>"jni.h"</code> include file provides different typedefs
-depending on whether it's included into C or C++.  For this reason it's a bad idea to
-include JNIEnv arguments in header files included by both languages.  (Put another way: if your
-header file requires <code>#ifdef __cplusplus</code>, you may have to do some extra work if anything in
-that header refers to JNIEnv.)</p>
-
-<a name="threads" id="threads"></a>
-<h2>Threads</h2>
-
-<p>All threads are Linux threads, scheduled by the kernel.  They're usually
-started from managed code (using <code>Thread.start</code>),
-but they can also be created elsewhere and then attached to the JavaVM.  For
-example, a thread started with <code>pthread_create</code> can be attached
-with the JNI <code>AttachCurrentThread</code> or
-<code>AttachCurrentThreadAsDaemon</code> functions.  Until a thread is
-attached, it has no JNIEnv, and <strong>cannot make JNI calls</strong>.</p>
-
-<p>Attaching a natively-created thread causes a <code>java.lang.Thread</code>
-object to be constructed and added to the "main" <code>ThreadGroup</code>,
-making it visible to the debugger.  Calling <code>AttachCurrentThread</code>
-on an already-attached thread is a no-op.</p>
-
-<p>Android does not suspend threads executing native code.  If
-garbage collection is in progress, or the debugger has issued a suspend
-request, Android will pause the thread the next time it makes a JNI call.</p>
-
-<p>Threads attached through JNI <strong>must call
-<code>DetachCurrentThread</code> before they exit</strong>.
-If coding this directly is awkward, in Android 2.0 (Eclair) and higher you
-can use <code>pthread_key_create</code> to define a destructor
-function that will be called before the thread exits, and
-call <code>DetachCurrentThread</code> from there.  (Use that
-key with <code>pthread_setspecific</code> to store the JNIEnv in
-thread-local-storage; that way it'll be passed into your destructor as
-the argument.)</p>
-
-
-<a name="jclass_jmethodID_and_jfieldID" id="jclass_jmethodID_and_jfieldID"></a>
-<h2>jclass, jmethodID, and jfieldID</h2>
-
-<p>If you want to access an object's field from native code, you would do the following:</p>
-
-<ul>
-<li> Get the class object reference for the class with <code>FindClass</code></li>
-<li> Get the field ID for the field with <code>GetFieldID</code></li>
-<li> Get the contents of the field with something appropriate, such as
-<code>GetIntField</code></li>
-</ul>
-
-<p>Similarly, to call a method, you'd first get a class object reference and then a method ID.  The IDs are often just
-pointers to internal runtime data structures.  Looking them up may require several string
-comparisons, but once you have them the actual call to get the field or invoke the method
-is very quick.</p>
-
-<p>If performance is important, it's useful to look the values up once and cache the results
-in your native code.  Because there is a limit of one JavaVM per process, it's reasonable
-to store this data in a static local structure.</p>
-
-<p>The class references, field IDs, and method IDs are guaranteed valid until the class is unloaded.  Classes
-are only unloaded if all classes associated with a ClassLoader can be garbage collected,
-which is rare but will not be impossible in Android.  Note however that
-the <code>jclass</code>
-is a class reference and <strong>must be protected</strong> with a call
-to <code>NewGlobalRef</code> (see the next section).</p>
-
-<p>If you would like to cache the IDs when a class is loaded, and automatically re-cache them
-if the class is ever unloaded and reloaded, the correct way to initialize
-the IDs is to add a piece of code that looks like this to the appropriate class:</p>
-
-<pre>    /*
-     * We use a class initializer to allow the native code to cache some
-     * field offsets. This native function looks up and caches interesting
-     * class/field/method IDs. Throws on failure.
-     */
-    private static native void nativeInit();
-
-    static {
-        nativeInit();
-    }</pre>
-
-<p>Create a <code>nativeClassInit</code> method in your C/C++ code that performs the ID lookups.  The code
-will be executed once, when the class is initialized.  If the class is ever unloaded and
-then reloaded, it will be executed again.</p>
-
-<a name="local_and_global_references" id="local_and_global_references"></a>
-<h2>Local and Global References</h2>
-
-<p>Every argument passed to a native method, and almost every object returned
-by a JNI function is a "local reference".  This means that it's valid for the
-duration of the current native method in the current thread.
-<strong>Even if the object itself continues to live on after the native method
-returns, the reference is not valid.</strong>
-<p>This applies to all sub-classes of <code>jobject</code>, including
-<code>jclass</code>, <code>jstring</code>, and <code>jarray</code>.
-(The runtime will warn you about most reference mis-uses when extended JNI
-checks are enabled.)</p>
-<p>The only way to get non-local references is via the functions
-<code>NewGlobalRef</code> and <code>NewWeakGlobalRef</code>.
-
-<p>If you want to hold on to a reference for a longer period, you must use
-a "global" reference.  The <code>NewGlobalRef</code> function takes the
-local reference as an argument and returns a global one.
-The global reference is guaranteed to be valid until you call
-<code>DeleteGlobalRef</code>.</p>
-
-<p>This pattern is commonly used when caching a jclass returned
-from <code>FindClass</code>, e.g.:</p>
-<pre>jclass localClass = env-&gt;FindClass("MyClass");
-jclass globalClass = reinterpret_cast&lt;jclass&gt;(env-&gt;NewGlobalRef(localClass));</pre>
-
-<p>All JNI methods accept both local and global references as arguments.
-It's possible for references to the same object to have different values.
-For example, the return values from consecutive calls to
-<code>NewGlobalRef</code> on the same object may be different.
-<strong>To see if two references refer to the same object,
-you must use the <code>IsSameObject</code> function.</strong>  Never compare
-references with <code>==</code> in native code.</p>
-
-<p>One consequence of this is that you
-<strong>must not assume object references are constant or unique</strong>
-in native code.  The 32-bit value representing an object may be different
-from one invocation of a method to the next, and it's possible that two
-different objects could have the same 32-bit value on consecutive calls.  Do
-not use <code>jobject</code> values as keys.</p>
-
-<p>Programmers are required to "not excessively allocate" local references.  In practical terms this means
-that if you're creating large numbers of local references, perhaps while running through an array of
-objects, you should free them manually with
-<code>DeleteLocalRef</code> instead of letting JNI do it for you.  The
-implementation is only required to reserve slots for
-16 local references, so if you need more than that you should either delete as you go or use
-<code>EnsureLocalCapacity</code>/<code>PushLocalFrame</code> to reserve more.</p>
-
-<p>Note that <code>jfieldID</code>s and <code>jmethodID</code>s are opaque
-types, not object references, and should not be passed to
-<code>NewGlobalRef</code>.  The raw data
-pointers returned by functions like <code>GetStringUTFChars</code>
-and <code>GetByteArrayElements</code> are also not objects. (They may be passed
-between threads, and are valid until the matching Release call.)</p>
-
-<p>One unusual case deserves separate mention.  If you attach a native
-thread with <code>AttachCurrentThread</code>, the code you are running will
-never automatically free local references until the thread detaches.  Any local
-references you create will have to be deleted manually. In general, any native
-code that creates local references in a loop probably needs to do some manual
-deletion.</p>
-
-<a name="UTF_8_and_UTF_16_strings" id="UTF_8_and_UTF_16_strings"></a>
-<h2>UTF-8 and UTF-16 Strings</h2>
-
-<p>The Java programming language uses UTF-16.  For convenience, JNI provides methods that work with <a href="http://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8">Modified UTF-8</a> as well.  The
-modified encoding is useful for C code because it encodes \u0000 as 0xc0 0x80 instead of 0x00.
-The nice thing about this is that you can count on having C-style zero-terminated strings,
-suitable for use with standard libc string functions.  The down side is that you cannot pass
-arbitrary UTF-8 data to JNI and expect it to work correctly.</p>
-
-<p>If possible, it's usually faster to operate with UTF-16 strings. Android
-currently does not require a copy in <code>GetStringChars</code>, whereas
-<code>GetStringUTFChars</code> requires an allocation and a conversion to
-UTF-8.  Note that
-<strong>UTF-16 strings are not zero-terminated</strong>, and \u0000 is allowed,
-so you need to hang on to the string length as well as
-the jchar pointer.</p>
-
-<p><strong>Don't forget to <code>Release</code> the strings you <code>Get</code></strong>.  The
-string functions return <code>jchar*</code> or <code>jbyte*</code>, which
-are C-style pointers to primitive data rather than local references.  They
-are guaranteed valid until <code>Release</code> is called, which means they are not
-released when the native method returns.</p>
-
-<p><strong>Data passed to NewStringUTF must be in Modified UTF-8 format</strong>.  A
-common mistake is reading character data from a file or network stream
-and handing it to <code>NewStringUTF</code> without filtering it.
-Unless you know the data is 7-bit ASCII, you need to strip out high-ASCII
-characters or convert them to proper Modified UTF-8 form.  If you don't,
-the UTF-16 conversion will likely not be what you expect.  The extended
-JNI checks will scan strings and warn you about invalid data, but they
-won't catch everything.</p>
-
-<a name="arrays" id="arrays"></a>
-<h2>Primitive Arrays</h2>
-
-<p>JNI provides functions for accessing the contents of array objects.
-While arrays of objects must be accessed one entry at a time, arrays of
-primitives can be read and written directly as if they were declared in C.</p>
-
-<p>To make the interface as efficient as possible without constraining
-the VM implementation, the <code>Get&lt;PrimitiveType&gt;ArrayElements</code>
-family of calls allows the runtime to either return a pointer to the actual elements, or
-allocate some memory and make a copy.  Either way, the raw pointer returned
-is guaranteed to be valid until the corresponding <code>Release</code> call
-is issued (which implies that, if the data wasn't copied, the array object
-will be pinned down and can't be relocated as part of compacting the heap).
-<strong>You must <code>Release</code> every array you <code>Get</code>.</strong>  Also, if the <code>Get</code>
-call fails, you must ensure that your code doesn't try to <code>Release</code> a NULL
-pointer later.</p>
-
-<p>You can determine whether or not the data was copied by passing in a
-non-NULL pointer for the <code>isCopy</code> argument.  This is rarely
-useful.</p>
-
-<p>The <code>Release</code> call takes a <code>mode</code> argument that can
-have one of three values.  The actions performed by the runtime depend upon
-whether it returned a pointer to the actual data or a copy of it:</p>
-
-<ul>
-    <li><code>0</code>
-    <ul>
-        <li>Actual: the array object is un-pinned.
-        <li>Copy: data is copied back.  The buffer with the copy is freed.
-    </ul>
-    <li><code>JNI_COMMIT</code>
-    <ul>
-        <li>Actual: does nothing.
-        <li>Copy: data is copied back.  The buffer with the copy
-        <strong>is not freed</strong>.
-    </ul>
-    <li><code>JNI_ABORT</code>
-    <ul>
-        <li>Actual: the array object is un-pinned.  Earlier
-        writes are <strong>not</strong> aborted.
-        <li>Copy: the buffer with the copy is freed; any changes to it are lost.
-    </ul>
-</ul>
-
-<p>One reason for checking the <code>isCopy</code> flag is to know if
-you need to call <code>Release</code> with <code>JNI_COMMIT</code>
-after making changes to an array &mdash; if you're alternating between making
-changes and executing code that uses the contents of the array, you may be
-able to
-skip the no-op commit.  Another possible reason for checking the flag is for
-efficient handling of <code>JNI_ABORT</code>.  For example, you might want
-to get an array, modify it in place, pass pieces to other functions, and
-then discard the changes.  If you know that JNI is making a new copy for
-you, there's no need to create another "editable" copy.  If JNI is passing
-you the original, then you do need to make your own copy.</p>
-
-<p>It is a common mistake (repeated in example code) to assume that you can skip the <code>Release</code> call if
-<code>*isCopy</code> is false.  This is not the case.  If no copy buffer was
-allocated, then the original memory must be pinned down and can't be moved by
-the garbage collector.</p>
-
-<p>Also note that the <code>JNI_COMMIT</code> flag does <strong>not</strong> release the array,
-and you will need to call <code>Release</code> again with a different flag
-eventually.</p>
-
-
-<a name="region_calls" id="region_calls"></a>
-<h2>Region Calls</h2>
-
-<p>There is an alternative to calls like <code>Get&lt;Type&gt;ArrayElements</code>
-and <code>GetStringChars</code> that may be very helpful when all you want
-to do is copy data in or out.  Consider the following:</p>
-
-<pre>    jbyte* data = env-&gt;GetByteArrayElements(array, NULL);
-    if (data != NULL) {
-        memcpy(buffer, data, len);
-        env-&gt;ReleaseByteArrayElements(array, data, JNI_ABORT);
-    }</pre>
-
-<p>This grabs the array, copies the first <code>len</code> byte
-elements out of it, and then releases the array.  Depending upon the
-implementation, the <code>Get</code> call will either pin or copy the array
-contents.
-The code copies the data (for perhaps a second time), then calls <code>Release</code>; in this case
-<code>JNI_ABORT</code> ensures there's no chance of a third copy.</p>
-
-<p>One can accomplish the same thing more simply:</p>
-<pre>    env-&gt;GetByteArrayRegion(array, 0, len, buffer);</pre>
-
-<p>This has several advantages:</p>
-<ul>
-    <li>Requires one JNI call instead of 2, reducing overhead.
-    <li>Doesn't require pinning or extra data copies.
-    <li>Reduces the risk of programmer error &mdash; no risk of forgetting
-    to call <code>Release</code> after something fails.
-</ul>
-
-<p>Similarly, you can use the <code>Set&lt;Type&gt;ArrayRegion</code> call
-to copy data into an array, and <code>GetStringRegion</code> or
-<code>GetStringUTFRegion</code> to copy characters out of a
-<code>String</code>.
-
-
-<a name="exceptions" id="exceptions"></a>
-<h2>Exceptions</h2>
-
-<p><strong>You must not call most JNI functions while an exception is pending.</strong>
-Your code is expected to notice the exception (via the function's return value,
-<code>ExceptionCheck</code>, or <code>ExceptionOccurred</code>) and return,
-or clear the exception and handle it.</p>
-
-<p>The only JNI functions that you are allowed to call while an exception is
-pending are:</p>
-<ul>
-    <li><code>DeleteGlobalRef</code>
-    <li><code>DeleteLocalRef</code>
-    <li><code>DeleteWeakGlobalRef</code>
-    <li><code>ExceptionCheck</code>
-    <li><code>ExceptionClear</code>
-    <li><code>ExceptionDescribe</code>
-    <li><code>ExceptionOccurred</code>
-    <li><code>MonitorExit</code>
-    <li><code>PopLocalFrame</code>
-    <li><code>PushLocalFrame</code>
-    <li><code>Release&lt;PrimitiveType&gt;ArrayElements</code>
-    <li><code>ReleasePrimitiveArrayCritical</code>
-    <li><code>ReleaseStringChars</code>
-    <li><code>ReleaseStringCritical</code>
-    <li><code>ReleaseStringUTFChars</code>
-</ul>
-
-<p>Many JNI calls can throw an exception, but often provide a simpler way
-of checking for failure.  For example, if <code>NewString</code> returns
-a non-NULL value, you don't need to check for an exception.  However, if
-you call a method (using a function like <code>CallObjectMethod</code>),
-you must always check for an exception, because the return value is not
-going to be valid if an exception was thrown.</p>
-
-<p>Note that exceptions thrown by interpreted code do not unwind native stack
-frames, and Android does not yet support C++ exceptions.
-The JNI <code>Throw</code> and <code>ThrowNew</code> instructions just
-set an exception pointer in the current thread.  Upon returning to managed
-from native code, the exception will be noted and handled appropriately.</p>
-
-<p>Native code can "catch" an exception by calling <code>ExceptionCheck</code> or
-<code>ExceptionOccurred</code>, and clear it with
-<code>ExceptionClear</code>.  As usual,
-discarding exceptions without handling them can lead to problems.</p>
-
-<p>There are no built-in functions for manipulating the <code>Throwable</code> object
-itself, so if you want to (say) get the exception string you will need to
-find the <code>Throwable</code> class, look up the method ID for
-<code>getMessage "()Ljava/lang/String;"</code>, invoke it, and if the result
-is non-NULL use <code>GetStringUTFChars</code> to get something you can
-hand to <code>printf(3)</code> or equivalent.</p>
-
-
-<a name="extended_checking" id="extended_checking"></a>
-<h2>Extended Checking</h2>
-
-<p>JNI does very little error checking. Errors usually result in a crash. Android also offers a mode called CheckJNI, where the JavaVM and JNIEnv function table pointers are switched to tables of functions that perform an extended series of checks before calling the standard implementation.</p>
-
-<p>The additional checks include:</p>
-
-<ul>
-<li>Arrays: attempting to allocate a negative-sized array.</li>
-<li>Bad pointers: passing a bad jarray/jclass/jobject/jstring to a JNI call, or passing a NULL pointer to a JNI call with a non-nullable argument.</li>
-<li>Class names: passing anything but the “java/lang/String” style of class name to a JNI call.</li>
-<li>Critical calls: making a JNI call between a “critical” get and its corresponding release.</li>
-<li>Direct ByteBuffers: passing bad arguments to <code>NewDirectByteBuffer</code>.</li>
-<li>Exceptions: making a JNI call while there’s an exception pending.</li>
-<li>JNIEnv*s: using a JNIEnv* from the wrong thread.</li>
-<li>jfieldIDs: using a NULL jfieldID, or using a jfieldID to set a field to a value of the wrong type (trying to assign a StringBuilder to a String field, say), or using a jfieldID for a static field to set an instance field or vice versa, or using a jfieldID from one class with instances of another class.</li>
-<li>jmethodIDs: using the wrong kind of jmethodID when making a <code>Call*Method</code> JNI call: incorrect return type, static/non-static mismatch, wrong type for ‘this’ (for non-static calls) or wrong class (for static calls).</li>
-<li>References: using <code>DeleteGlobalRef</code>/<code>DeleteLocalRef</code> on the wrong kind of reference.</li>
-<li>Release modes: passing a bad release mode to a release call (something other than <code>0</code>, <code>JNI_ABORT</code>, or <code>JNI_COMMIT</code>).</li>
-<li>Type safety: returning an incompatible type from your native method (returning a StringBuilder from a method declared to return a String, say).</li>
-<li>UTF-8: passing an invalid <a href="http://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8">Modified UTF-8</a> byte sequence to a JNI call.</li>
-</ul>
-
-<p>(Accessibility of methods and fields is still not checked: access restrictions don't apply to native code.)</p>
-
-<p>There are several ways to enable CheckJNI.</p>
-
-<p>If you’re using the emulator, CheckJNI is on by default.</p>
-
-<p>If you have a rooted device, you can use the following sequence of commands to restart the runtime with CheckJNI enabled:</p>
-
-<pre>adb shell stop
-adb shell setprop dalvik.vm.checkjni true
-adb shell start</pre>
-
-<p>In either of these cases, you’ll see something like this in your logcat output when the runtime starts:</p>
-
-<pre>D AndroidRuntime: CheckJNI is ON</pre>
-
-<p>If you have a regular device, you can use the following command:</p>
-
-<pre>adb shell setprop debug.checkjni 1</pre>
-
-<p>This won’t affect already-running apps, but any app launched from that point on will have CheckJNI enabled. (Change the property to any other value or simply rebooting will disable CheckJNI again.) In this case, you’ll see something like this in your logcat output the next time an app starts:</p>
-
-<pre>D Late-enabling CheckJNI</pre>
-
-
-
-
-<a name="native_libraries" id="native_libraries"></a>
-<h2>Native Libraries</h2>
-
-<p>You can load native code from shared libraries with the standard
-<code>System.loadLibrary</code> call.  The
-preferred way to get at your native code is:</p>
-
-<ul>
-<li> Call <code>System.loadLibrary</code> from a static class
-initializer.  (See the earlier example, where one is used to call
-<code>nativeClassInit</code>.)  The argument is the "undecorated"
-library name, so to load "libfubar.so" you would pass in "fubar".</li>
-<li> Provide a native function: <code><strong>jint JNI_OnLoad(JavaVM* vm, void* reserved)</strong></code></li>
-<li>In <code>JNI_OnLoad</code>, register all of your native methods.  You
-should declare
-the methods "static" so the names don't take up space in the symbol table
-on the device.</li>
-</ul>
-
-<p>The <code>JNI_OnLoad</code> function should look something like this if
-written in C++:</p>
-<pre>jint JNI_OnLoad(JavaVM* vm, void* reserved)
-{
-    JNIEnv* env;
-    if (vm-&gt;GetEnv(reinterpret_cast&lt;void**&gt;(&env), JNI_VERSION_1_6) != JNI_OK) {
-        return -1;
-    }
-
-    // Get jclass with env-&gt;FindClass.
-    // Register methods with env-&gt;RegisterNatives.
-
-    return JNI_VERSION_1_6;
-}</pre>
-
-<p>You can also call <code>System.load</code> with the full path name of the
-shared library.  For Android apps, you may find it useful to get the full
-path to the application's private data storage area from the context object.</p>
-
-<p>This is the recommended approach, but not the only approach.  Explicit
-registration is not required, nor is it necessary that you provide a
-<code>JNI_OnLoad</code> function.
-You can instead use "discovery" of native methods that are named in a
-specific way (see <a href="http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/design.html#wp615">the JNI spec</a> for details), though this is less desirable because if a method signature is wrong you won't know
-about it until the first time the method is actually used.</p>
-
-<p>One other note about <code>JNI_OnLoad</code>: any <code>FindClass</code>
-calls you make from there will happen in the context of the class loader
-that was used to load the shared library.  Normally <code>FindClass</code>
-uses the loader associated with the method at the top of the interpreted
-stack, or if there isn't one (because the thread was just attached) it uses
-the "system" class loader.  This makes
-<code>JNI_OnLoad</code> a convenient place to look up and cache class
-object references.</p>
-
-
-<a name="64_bit" id="64_bit"></a>
-<h2>64-bit Considerations</h2>
-
-<p>Android is currently expected to run on 32-bit platforms.  In theory it
-could be built for a 64-bit system, but that is not a goal at this time.
-For the most part this isn't something that you will need to worry about
-when interacting with native code,
-but it becomes significant if you plan to store pointers to native
-structures in integer fields in an object.  To support architectures
-that use 64-bit pointers, <strong>you need to stash your native pointers in a
-<code>long</code> field rather than an <code>int</code></strong>.
-
-
-<a name="unsupported" id="unsupported"></a>
-<h2>Unsupported Features/Backwards Compatibility</h2>
-
-<p>All JNI 1.6 features are supported, with the following exception:</p>
-<ul>
-    <li><code>DefineClass</code> is not implemented.  Android does not use
-    Java bytecodes or class files, so passing in binary class data
-    doesn't work.</li>
-</ul>
-
-<p>For backward compatibility with older Android releases, you may need to
-be aware of:</p>
-<ul>
-    <li><b>Dynamic lookup of native functions</b>
-    <p>Until Android 2.0 (Eclair), the '$' character was not properly
-    converted to "_00024" during searches for method names.  Working
-    around this requires using explicit registration or moving the
-    native methods out of inner classes.
-    <li><b>Detaching threads</b>
-    <p>Until Android 2.0 (Eclair), it was not possible to use a <code>pthread_key_create</code>
-    destructor function to avoid the "thread must be detached before
-    exit" check.  (The runtime also uses a pthread key destructor function,
-    so it'd be a race to see which gets called first.)
-    <li><b>Weak global references</b>
-    <p>Until Android 2.2 (Froyo), weak global references were not implemented.
-    Older versions will vigorously reject attempts to use them.  You can use
-    the Android platform version constants to test for support.
-    <p>Until Android 4.0 (Ice Cream Sandwich), weak global references could only
-    be passed to <code>NewLocalRef</code>, <code>NewGlobalRef</code>, and
-    <code>DeleteWeakGlobalRef</code>. (The spec strongly encourages
-    programmers to create hard references to weak globals before doing
-    anything with them, so this should not be at all limiting.)
-    <p>From Android 4.0 (Ice Cream Sandwich) on, weak global references can be
-    used like any other JNI references.</li>
-    <li><b>Local references</b>
-    <p>Until Android 4.0 (Ice Cream Sandwich), local references were
-    actually direct pointers. Ice Cream Sandwich added the indirection
-    necessary to support better garbage collectors, but this means that lots
-    of JNI bugs are undetectable on older releases. See
-    <a href="http://android-developers.blogspot.com/2011/11/jni-local-reference-changes-in-ics.html">JNI Local Reference Changes in ICS</a> for more details.
-    <li><b>Determining reference type with <code>GetObjectRefType</code></b>
-    <p>Until Android 4.0 (Ice Cream Sandwich), as a consequence of the use of
-    direct pointers (see above), it was impossible to implement
-    <code>GetObjectRefType</code> correctly. Instead we used a heuristic
-    that looked through the weak globals table, the arguments, the locals
-    table, and the globals table in that order. The first time it found your
-    direct pointer, it would report that your reference was of the type it
-    happened to be examining. This meant, for example, that if 
-    you called <code>GetObjectRefType</code> on a global jclass that happened
-    to be the same as the jclass passed as an implicit argument to your static 
-    native method, you'd get <code>JNILocalRefType</code> rather than
-    <code>JNIGlobalRefType</code>.
-</ul>
-
-
-<a name="faq_ULE" id="faq_ULE"></a>
-<h2>FAQ: Why do I get <code>UnsatisfiedLinkError</code>?</h2>
-
-<p>When working on native code it's not uncommon to see a failure like this:</p>
-<pre>java.lang.UnsatisfiedLinkError: Library foo not found</pre>
-
-<p>In some cases it means what it says &mdash; the library wasn't found.  In
-other cases the library exists but couldn't be opened by <code>dlopen(3)</code>, and
-the details of the failure can be found in the exception's detail message.</p>
-
-<p>Common reasons why you might encounter "library not found" exceptions:</p>
-<ul>
-    <li>The library doesn't exist or isn't accessible to the app.  Use
-    <code>adb shell ls -l &lt;path&gt;</code> to check its presence
-    and permissions.
-    <li>The library wasn't built with the NDK.  This can result in
-    dependencies on functions or libraries that don't exist on the device.
-</ul>
-
-<p>Another class of <code>UnsatisfiedLinkError</code> failures looks like:</p>
-<pre>java.lang.UnsatisfiedLinkError: myfunc
-        at Foo.myfunc(Native Method)
-        at Foo.main(Foo.java:10)</pre>
-
-<p>In logcat, you'll see:</p>
-<pre>W/dalvikvm(  880): No implementation found for native LFoo;.myfunc ()V</pre>
-
-<p>This means that the runtime tried to find a matching method but was
-unsuccessful.  Some common reasons for this are:</p>
-<ul>
-    <li>The library isn't getting loaded.  Check the logcat output for
-    messages about library loading.
-    <li>The method isn't being found due to a name or signature mismatch.  This
-    is commonly caused by:
-    <ul>
-        <li>For lazy method lookup, failing to declare C++ functions
-        with <code>extern "C"</code> and appropriate
-        visibility (<code>JNIEXPORT</code>). Note that prior to Ice Cream
-        Sandwich, the JNIEXPORT macro was incorrect, so using a new GCC with
-        an old <code>jni.h</code> won't work.
-        You can use <code>arm-eabi-nm</code>
-        to see the symbols as they appear in the library; if they look
-        mangled (something like <code>_Z15Java_Foo_myfuncP7_JNIEnvP7_jclass</code>
-        rather than <code>Java_Foo_myfunc</code>), or if the symbol type is
-        a lowercase 't' rather than an uppercase 'T', then you need to
-        adjust the declaration.
-        <li>For explicit registration, minor errors when entering the
-        method signature.  Make sure that what you're passing to the
-        registration call matches the signature in the log file.
-        Remember that 'B' is <code>byte</code> and 'Z' is <code>boolean</code>.
-        Class name components in signatures start with 'L', end with ';',
-        use '/' to separate package/class names, and use '$' to separate
-        inner-class names (<code>Ljava/util/Map$Entry;</code>, say).
-    </ul>
-</ul>
-
-<p>Using <code>javah</code> to automatically generate JNI headers may help
-avoid some problems.
-
-
-<a name="faq_FindClass" id="faq_FindClass"></a>
-<h2>FAQ: Why didn't <code>FindClass</code> find my class?</h2>
-
-<p>Make sure that the class name string has the correct format.  JNI class
-names start with the package name and are separated with slashes,
-such as <code>java/lang/String</code>.  If you're looking up an array class,
-you need to start with the appropriate number of square brackets and
-must also wrap the class with 'L' and ';', so a one-dimensional array of
-<code>String</code> would be <code>[Ljava/lang/String;</code>.</p>
-
-<p>If the class name looks right, you could be running into a class loader
-issue.  <code>FindClass</code> wants to start the class search in the
-class loader associated with your code.  It examines the call stack,
-which will look something like:
-<pre>    Foo.myfunc(Native Method)
-    Foo.main(Foo.java:10)
-    dalvik.system.NativeStart.main(Native Method)</pre>
-
-<p>The topmost method is <code>Foo.myfunc</code>.  <code>FindClass</code>
-finds the <code>ClassLoader</code> object associated with the <code>Foo</code>
-class and uses that.</p>
-
-<p>This usually does what you want.  You can get into trouble if you
-create a thread yourself (perhaps by calling <code>pthread_create</code>
-and then attaching it with <code>AttachCurrentThread</code>).
-Now the stack trace looks like this:</p>
-<pre>    dalvik.system.NativeStart.run(Native Method)</pre>
-
-<p>The topmost method is <code>NativeStart.run</code>, which isn't part of
-your application.  If you call <code>FindClass</code> from this thread, the
-JavaVM will start in the "system" class loader instead of the one associated
-with your application, so attempts to find app-specific classes will fail.</p>
-
-<p>There are a few ways to work around this:</p>
-<ul>
-    <li>Do your <code>FindClass</code> lookups once, in
-    <code>JNI_OnLoad</code>, and cache the class references for later
-    use.  Any <code>FindClass</code> calls made as part of executing
-    <code>JNI_OnLoad</code> will use the class loader associated with
-    the function that called <code>System.loadLibrary</code> (this is a
-    special rule, provided to make library initialization more convenient).
-    If your app code is loading the library, <code>FindClass</code>
-    will use the correct class loader.
-    <li>Pass an instance of the class into the functions that need
-    it, by declaring your native method to take a Class argument and
-    then passing <code>Foo.class</code> in.
-    <li>Cache a reference to the <code>ClassLoader</code> object somewhere
-    handy, and issue <code>loadClass</code> calls directly.  This requires
-    some effort.
-</ul>
-
-
-<a name="faq_sharing" id="faq_sharing"></a>
-<h2>FAQ: How do I share raw data with native code?</h2>
-
-<p>You may find yourself in a situation where you need to access a large
-buffer of raw data from both managed and native code.  Common examples
-include manipulation of bitmaps or sound samples.  There are two
-basic approaches.</p>
-
-<p>You can store the data in a <code>byte[]</code>.  This allows very fast
-access from managed code.  On the native side, however, you're
-not guaranteed to be able to access the data without having to copy it.  In
-some implementations, <code>GetByteArrayElements</code> and
-<code>GetPrimitiveArrayCritical</code> will return actual pointers to the
-raw data in the managed heap, but in others it will allocate a buffer
-on the native heap and copy the data over.</p>
-
-<p>The alternative is to store the data in a direct byte buffer.  These
-can be created with <code>java.nio.ByteBuffer.allocateDirect</code>, or
-the JNI <code>NewDirectByteBuffer</code> function.  Unlike regular
-byte buffers, the storage is not allocated on the managed heap, and can
-always be accessed directly from native code (get the address
-with <code>GetDirectBufferAddress</code>).  Depending on how direct
-byte buffer access is implemented, accessing the data from managed code
-can be very slow.</p>
-
-<p>The choice of which to use depends on two factors:</p>
-<ol>
-    <li>Will most of the data accesses happen from code written in Java
-    or in C/C++?
-    <li>If the data is eventually being passed to a system API, what form
-    must it be in?  (For example, if the data is eventually passed to a
-    function that takes a byte[], doing processing in a direct
-    <code>ByteBuffer</code> might be unwise.)
-</ol>
-
-<p>If there's no clear winner, use a direct byte buffer.  Support for them
-is built directly into JNI, and performance should improve in future releases.</p>
diff --git a/docs/html/guide/topics/security/permissions.jd b/docs/html/guide/topics/security/permissions.jd
index 3013e38..4ad9b7c 100644
--- a/docs/html/guide/topics/security/permissions.jd
+++ b/docs/html/guide/topics/security/permissions.jd
@@ -61,6 +61,7 @@
 are sandboxed in the same way and have the same degree of security from each
 other.</p>
 
+
 <a name="signing"></a>
 <h2>Application Signing</h2>
 
@@ -112,7 +113,7 @@
 <a name="permissions"></a>
 <h2>Using Permissions</h2>
 
-<p>A basic Android application has no permissions associated with it,
+<p>A basic Android application has no permissions associated with it by default,
 meaning it can not do anything that would adversely impact the user experience
 or any data on the device.  To make use of protected features of the device,
 you must include in your <code>AndroidManifest.xml</code> one or more
@@ -165,6 +166,33 @@
 </ul>
 
 
+
+<div class="caution">
+<p><strong>Caution:</strong> Over time,
+new restrictions may be added to the platform such that, in order
+to use certain APIs, your app must request a permission that it previously did not need.
+Because existing apps assume access to those APIs is freely available,
+Android may apply the new permission request to the app's manifest to avoid
+breaking the app on the new platform version.
+Android makes the decision as to whether an app might need the permission based on
+the value provided for the <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a>
+attribute. If the value is lower than the version in which the permission was added, then
+Android adds the permission.</p>
+<p>For example, the {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission was
+added in API level 4 to restrict access to the shared storage space. If your <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a>
+is 3 or lower, this permission is added to your app on newer versions of Android.</p>
+<p>Beware that if this happens to your app, your app listing on Google Play will show these
+required permissions even though your app might not actually require them.</p>
+<p>To avoid this and remove the default permissions you don't need, always update your <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a>
+to be as high as possible. You can see which permissions were added with each release in the
+{@link android.os.Build.VERSION_CODES} documentation.</p>
+</div>
+
+
+
 <a name="declaring"></a>
 <h2>Declaring and Enforcing Permissions</h2>
 
diff --git a/docs/html/guide/topics/ui/controls/text.jd b/docs/html/guide/topics/ui/controls/text.jd
index 2d9d215..654883d 100644
--- a/docs/html/guide/topics/ui/controls/text.jd
+++ b/docs/html/guide/topics/ui/controls/text.jd
@@ -79,15 +79,23 @@
 </pre>
 
 
-<p>There are several different input types available for different situations. You can find
-them all listed with the documentation for <a
-href="{@docRoot}reference/android/widget/TextView.html#attr_android:inputType">{@code
-android:inputType}</a>.</p>
+<p>There are several different input types available for different situations.
+Here are some of the more common values for
+<a href="{@docRoot}reference/android/widget/TextView.html#attr_android:inputType"
+>{@code android:inputType}</a>:</p>
 
-<p class="note"><strong>Tip:</strong> To allow users to input long strings of text with line
-breaks, use the {@code "textMultiLine"} input type. By default, an {@link android.widget.EditText}
-object is restricted to one line of text and scrolls horizontally when the text exceeds the
-available width.</p>
+<dl>
+  <dt>{@code "text"}</dt>
+    <dd>Normal text keyboard.</dd>
+  <dt>{@code "textEmailAddress"}</dt>
+    <dd>Normal text keyboard with the @ character.</dd>
+  <dt>{@code "textUri"}</dt>
+    <dd>Normal text keyboard with the / character.</dd>
+  <dt>{@code "number"}</dt>
+    <dd>Basic number keypad.</dd>
+  <dt>{@code "phone"}</dt>
+    <dd>Phone-style keypad.</dd>
+</dl>
 
 
 <h3 id="Behaviors">Controlling other behaviors</h3>
@@ -98,7 +106,25 @@
 
 <p>The <a href="{@docRoot}reference/android/widget/TextView.html#attr_android:inputType">{@code
 android:inputType}</a> attribute allows bitwise combinations so you can specify both a keyboard
-layout and one or more behaviors at once. For example, here's how you can collect a postal
+layout and one or more behaviors at once.</p>
+
+<p>Here are some of the common input type values that define keyboard behaviors:</p>
+
+<dl>
+  <dt>{@code "textCapSentences"}</dt>
+    <dd>Normal text keyboard that capitalizes the first letter for each new sentence.</dd>
+  <dt>{@code "textCapWords"}</dt>
+    <dd>Normal text keyboard that capitalizes every word. Good for titles or person names.</dd>
+  <dt>{@code "textAutoCorrect"}</dt>
+    <dd>Normal text keyboard that corrects commonly misspelled words.</dd>
+  <dt>{@code "textPassword"}</dt>
+    <dd>Normal text keyboard, but the characters entered turn into dots.</dd>
+  <dt>{@code "textMultiLine"}</dt>
+    <dd>Normal text keyboard that allow users to input long strings of text that include line
+breaks (carriage returns).</dd>
+</dl>
+
+<p>For example, here's how you can collect a postal
 address, capitalize each word, and disable text suggestions:</p>
 
 <pre>
@@ -177,7 +203,7 @@
     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
         boolean handled = false;
         if (actionId == EditorInfo.IME_ACTION_SEND) {
-            // Send the user message
+            sendMessage();
             handled = true;
         }
         return handled;
diff --git a/docs/html/guide/webapps/webview.jd b/docs/html/guide/webapps/webview.jd
index 9ea0a10..ce7fe27 100644
--- a/docs/html/guide/webapps/webview.jd
+++ b/docs/html/guide/webapps/webview.jd
@@ -162,7 +162,7 @@
     Context mContext;
 
     /** Instantiate the interface and set the context */
-    JavaScriptInterface(Context c) {
+    WebAppInterface(Context c) {
         mContext = c;
     }
 
diff --git a/docs/html/images/iab-thumb.png b/docs/html/images/iab-thumb.png
new file mode 100644
index 0000000..91399af
--- /dev/null
+++ b/docs/html/images/iab-thumb.png
Binary files differ
diff --git a/docs/html/images/training/input/ime_autocorrect.png b/docs/html/images/training/input/ime_autocorrect.png
new file mode 100644
index 0000000..fd8371b
--- /dev/null
+++ b/docs/html/images/training/input/ime_autocorrect.png
Binary files differ
diff --git a/docs/html/images/training/input/ime_password.png b/docs/html/images/training/input/ime_password.png
new file mode 100644
index 0000000..6270c30
--- /dev/null
+++ b/docs/html/images/training/input/ime_password.png
Binary files differ
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 23c102e..961afda 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -3,42 +3,42 @@
 page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
 
 sdk.win32_bundle_download=adt-bundle-windows-x86.zip
-sdk.win32_bundle_bytes=417851015
-sdk.win32_bundle_checksum=42d9a6c15113d405a97eed05e6d42e2b
+sdk.win32_bundle_bytes=418030942
+sdk.win32_bundle_checksum=ce32861d8f7c93ff6ff6971bd99d228e
 
 sdk.win64_bundle_download=adt-bundle-windows-x86_64.zip
-sdk.win64_bundle_bytes=417851515
-sdk.win64_bundle_checksum=73bdd1168fce0e36a27255a4335c865d
+sdk.win64_bundle_bytes=418155677
+sdk.win64_bundle_checksum=f09aa4557bd1dc2703fde95dcdd6b92e
 
 sdk.mac64_bundle_download=adt-bundle-mac-x86_64.zip
-sdk.mac64_bundle_bytes=382957959
-sdk.mac64_bundle_checksum=a320f8bbaee8572a36e68c434564bdd0
+sdk.mac64_bundle_bytes=383216991
+sdk.mac64_bundle_checksum=ea6c074ee30c426c503dab5c225a5076
 
 sdk.linux32_bundle_download=adt-bundle-linux-x86.zip
-sdk.linux32_bundle_bytes=411065882
-sdk.linux32_bundle_checksum=39687b06fedfea7487ff0824a4d32ee8
+sdk.linux32_bundle_bytes=411205048
+sdk.linux32_bundle_checksum=e64594cd339b8d9a400b9d16c616b3c3
 
 sdk.linux64_bundle_download=adt-bundle-linux-x86_64.zip
-sdk.linux64_bundle_bytes=411217430
-sdk.linux64_bundle_checksum=b0590fe9c1533da9b20ea65525b77677
+sdk.linux64_bundle_bytes=411478695
+sdk.linux64_bundle_checksum=582bfc9083ff4cbcfacc8223bd8c3be1
 
 
 
-sdk.win_installer=installer_r21-windows.exe
-sdk.win_installer_bytes=77523031
-sdk.win_installer_checksum=29ca8cb8f0bc8db627fa2adc2139a3cc
+sdk.win_installer=installer_r21.0.1-windows.exe
+sdk.win_installer_bytes=76520869
+sdk.win_installer_checksum=e2012262471a2583d4a559b15fcf45ff
 
-sdk.win_download=android-sdk_r21-windows.zip
-sdk.win_bytes=99093893
-sdk.win_checksum=7311452823470365f7975a545f8a2be4
+sdk.win_download=android-sdk_r21.0.1-windows.zip
+sdk.win_bytes=99107847
+sdk.win_checksum=613568d774c3bf25c5d24db16601af83
 
-sdk.mac_download=android-sdk_r21-macosx.zip
-sdk.mac_bytes=65792626
-sdk.mac_checksum=67e46adca90dd18d7291443f6c15d6af
+sdk.mac_download=android-sdk_r21.0.1-macosx.zip
+sdk.mac_bytes=65804128
+sdk.mac_checksum=30401c43a014cd5d6ec9d0c62854a1d9
 
-sdk.linux_download=android-sdk_r21-linux.tgz
-sdk.linux_bytes=91378351
-sdk.linux_checksum=7f8d73b629f808cdcfc9f9900bbd7580
+sdk.linux_download=android-sdk_r21.0.1-linux.tgz
+sdk.linux_bytes=91394975
+sdk.linux_checksum=eaa5a8d76d692d1d027f2bbcee019644
 
 
 
@@ -222,7 +222,7 @@
   <input id="32" onclick="onAgreeChecked()" type="radio" name="bit" value="32">
     <label for="32">32-bit</label>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
   <input id="64" onclick="onAgreeChecked()" type="radio" name="bit" value="64">
-    <label for="64">64-bit</label>  
+    <label for="64">64-bit</label>
 </p>
 <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
 </div>
@@ -241,7 +241,7 @@
 
 <h1 style="margin-top:0">Get the Android SDK</h1>
 
-  
+
 <p>The Android SDK provides you the API libraries and developer tools necessary to build, test,
   and debug apps for Android.</p>
 
@@ -290,7 +290,7 @@
 
 
 
- 
+
 
 <!-- alternative SDK options -->
 <div class="col-13" style="margin:0;">
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index 93d1db6..804030b 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
 page.title=Installing the Eclipse Plugin
-adt.zip.version=21.0.0
-adt.zip.download=ADT-21.0.0.zip
-adt.zip.bytes=13556487
-adt.zip.checksum=7db4eaae5df6a34fd853317a2bd8250b
+adt.zip.version=21.0.1
+adt.zip.download=ADT-21.0.1.zip
+adt.zip.bytes=13569302
+adt.zip.checksum=acfb01bf3fd1240f1fc21488c3dd16bf
 
 @jd:body
 
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index f2ff07c..243683c 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -57,6 +57,125 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>ADT 21.0.1</a> <em>(December 2012)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+<dl>
+  <dt>Dependencies:</dt>
+
+  <dd>
+    <ul>
+      <li>Java 1.6 or higher is required for ADT 21.0.1.</li>
+      <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 21.0.1.</li>
+      <li>ADT 21.0.1 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
+      Tools r21.0.1</a>. If you haven't already installed SDK Tools r21.0.1 into your SDK, use the
+      Android SDK Manager to do so.</li>
+    </ul>
+  </dd>
+
+  <dt>General Notes:</dt>
+  <dd>
+    <ul>
+      <li>Build
+        <ul>
+          <li>Updated build to detect and handle package name conflicts between an application and
+            the libraries it depends on. Libraries cannot share package names unless all of them
+            share the same package name.
+            (<a href="http://code.google.com/p/android/issues/detail?id=40152">Issue 40152</a>,
+             <a href="http://code.google.com/p/android/issues/detail?id=40273">Issue 40273</a>)
+          </li>
+          <li>Added a flag to disable dex merging to deal with cases where merging could generate
+            a broken dex file. If this happens to your project, add the following setting to your
+            {@code project.properties} file: {@code dex.disable.merger=true} This setting
+            causes the build system to revert to the older, slower dex processing that does not
+            pre-dex libraries.</li>
+        </ul>
+      </li>
+    </ul>
+  </dd>
+
+  <dt>Bug fixes:</dt>
+  <dd>
+    <ul>
+      <li>Lint
+        <ul>
+          <li>Corrected check for {@code 0px} values in style XML elements.
+            (<a href="http://code.google.com/p/android/issues/detail?id=39601">Issue 39601</a>)
+            </li>
+          <li>Fixed incorrect flagging of formatting strings.
+            (<a href="http://code.google.com/p/android/issues/detail?id=39758">Issue 39758</a>)
+            </li>
+          <li>Fixed problem where {@code tools:ignore} directive in the manifest file was ignored
+            by the Lint tool.
+            (<a href="http://code.google.com/p/android/issues/detail?id=40136">Issue 40136</a>)
+            </li>
+          <li>Fixed problem with flagging a wakelock release inside a conditional.
+            (<a href="http://code.google.com/p/android/issues/detail?id=40424">Issue 40424</a>)
+            </li>
+          <li>Fixed incorrect reporting of missing {@code layout_width} and {@code layout_height}
+            XML fields.
+            (<a href="http://code.google.com/p/android/issues/detail?id=38958">Issue 38958</a>)
+            </li>
+          <li>Fixed handling of custom namespace attributes.</li>
+          <li>Added fixes for filtering out library project warnings.</li>
+          <li>Removed warnings about missing classes before a build.</li>
+        </ul>
+      </li>
+
+      <li>Android Virtual Device Manager
+        <ul>
+          <li>Fixed handling of {@code devices.xml} file in other locales.
+            (<a href="http://code.google.com/p/android/issues/detail?id=39704">Issue 39704</a>)
+            </li>
+          <li>Fixed problem where the AVD Manager would not allow you to create a new AVD using
+            the <strong>4.0" WVGA</strong> or <strong> 4.65" 720p</strong> device definitions.
+            (<a href="http://code.google.com/p/android/issues/detail?id=39939">Issue 39939</a>)
+            </li>
+          <li>Fixed problem where deleted device definitions were not removed.</li>
+          <li>Fixed incorrect screen resolution setting for the Nexus One device definition.</li>
+          <li>Fixed problem where writing of an AVD settings file does not properly escape
+            {@code \\} path characters.</li>
+        </ul>
+      </li>
+
+      <li>Layout Editor
+        <ul>
+          <li>Fixed problem where layout cannot render strings starting with {@code \@}.
+            (<a href="http://code.google.com/p/android/issues/detail?id=40222">Issue 40222</a>)
+            </li>
+          <li>Fixed preview error when using the {@code android:numColumns} attribute in a layout.
+            (<a href="http://code.google.com/p/android/issues/detail?id=21296">Issue 21296</a>)
+            </li>
+          <li>Fixed compatibility issue with IntelliJ layout preview caused by layout editor
+            deleting the {@code .android/devices.xml} file.</li>
+          <li>Added fixes to editor for {@link android.widget.GridLayout}.</li>
+        </ul>
+      </li>
+
+      <li>Added support for {@code ldrtl} and {@code ldltr} resource qualifiers.</li>
+      <li>Fixed problem where Android XML resources mistakenly get compiled into {@code *.out.xml}
+        output files, causing project errors.
+        (<a href="http://code.google.com/p/android/issues/detail?id=3767">Issue 3767</a>)</li>
+      <li>Fixed error which caused resource refresh operations to fail.
+        (<a href="http://code.google.com/p/android/issues/detail?id=39213">Issue 39213</a>)</li>
+      <li>Updated the Custom View code template handle to library projects properly.</li>
+      <li>Fixed support for library string resources ({@code strings.xml}) when exporting an
+        application that references a library with string resources.
+        (<a href="http://code.google.com/p/android/issues/detail?id=39751">Issue 39751</a>)</li>
+      <li>Fixed problem where bad AVD setting files caused Device Manager and graphical XML editors
+        to crash.
+        (<a href="http://code.google.com/p/android/issues/detail?id=40400">Issue 40400</a>)</li>
+    </ul>
+  </dd>
+
+</dl>
+</div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>ADT 21.0.0</a> <em>(November 2012)</em>
   </p>
 
diff --git a/docs/html/tools/sdk/ndk/index.jd b/docs/html/tools/sdk/ndk/index.jd
index ad4fd7c..f3c9a44 100644
--- a/docs/html/tools/sdk/ndk/index.jd
+++ b/docs/html/tools/sdk/ndk/index.jd
@@ -1,19 +1,18 @@
 ndk=true
 
-ndk.win_download=android-ndk-r8c-windows.zip
-ndk.win_bytes=233787657
-ndk.win_checksum=3ff1570fa4ea865b7702507ea43dbae4
+ndk.win_download=android-ndk-r8d-windows.zip
+ndk.win_bytes=327014028
+ndk.win_checksum=d78ec3d4ec15ad3b18b9f488a5763c23
 
-ndk.mac_download=android-ndk-r8c-darwin-x86.tar.bz2
-ndk.mac_bytes=214270840
-ndk.mac_checksum=74a23e9e058512121835e0d6932e72d5
+ndk.mac_download=android-ndk-r8d-darwin-x86.tar.bz2
+ndk.mac_bytes=308328942
+ndk.mac_checksum=5cd9ef9fb7e03943ee8c9e147e42e571
 
-ndk.linux_download=android-ndk-r8c-linux-x86.tar.bz2
-ndk.linux_bytes=179945337
-ndk.linux_checksum=b0851346ff90c9266bc050016a228319
+ndk.linux_download=android-ndk-r8d-linux-x86.tar.bz2
+ndk.linux_bytes=254644383
+ndk.linux_checksum=e1fa0379a3feb59f2f0865f1a90bd382
 
 page.title=Android NDK
-
 @jd:body
 
 
@@ -250,6 +249,170 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt="">Android NDK, Revision 8d</a> <em>(December 2012)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+    <dl>
+      <dt>Important changes:</dt>
+      <dd>
+        <ul>
+          <li>Added the GNU Compiler Collection (GCC) 4.7 compiler to the NDK. The GCC 4.6 compiler
+            is still the default, so you must to explicitly enable the new version as follows:
+            <ul>
+              <li>For {@code ndk-build}, export the {@code NDK_TOOLCHAIN_VERSION=4.7} variable
+                <em>or</em> add it to {@code Application.mk}.</li>
+              <li>For standalone builds, add the {@code --toolchain=} option to
+                {@code make-standalone-toolchain.sh}, for example:
+                <pre>--toolchain=arm-linux-androideabi-4.7</pre></li>
+            </ul>
+            <p class="note">
+              <strong>Note:</strong> This feature is experimental. Please try it and
+              <a href="http://code.google.com/p/android/issues/list">report any issues</a>.</p>
+          </li>
+          <li>Added {@code stlport} exception support via gabi++.  Note that the new gabi++
+            depends on {@code dlopen} and related code, meaning that:
+            <ul>
+              <li>You can no longer build a <em>static</em> executable using the {@code -static}
+                option or include {@code libstlport_static.a} using
+                {@code APP_STL := stlport_static}. (You can still use the {@code -static} option
+                with a standalone toolchain.) Compiling a <em>dynamic</em> executable using
+                {@code include $(BUILD_EXECUTABLE)} continues to work because the compiler
+                automatically adds the {@code -ldl} option.</li>
+              <li>If your project links using {@code -nostdlib} and {-Wl,--no-undefined}, you
+                must manually include the {@code -ldl} option.</li>
+            </ul>
+              For more information, see {@code CPLUSPLUS-SUPPORT.html}.
+
+              <p class="note">
+                <strong>Note:</strong> This feature is experimental and works better with the GCC
+                4.6/4.7 compilers than with GCC 4.4.3 or Clang 3.1. Please try it and
+                <a href="http://code.google.com/p/android/issues/list">report any issues</a>.</p>
+          </li>
+          <li>Added a {@code -mstack-protector-guard=} option for x86 to choose between a
+            <em>global</em> default path which is compatible with older Android C library (bionic)
+            and a new <em>tls</em> path (%gs:20) for {@code -fstack-protector},
+            {@code -fstack-protector-all} and {@code -fstack-protector-strong} using the GCC 4.6
+            and higher compilers.
+
+            <p class="note">
+              <strong>Note:</strong> The {@code -mstack-protector-guard} setting itself does not
+              enable any {@code -fstack-protector*} options.</p>
+          </li>
+          <li>Added {@code android_setCpu()} function to
+            {@code sources/android/cpufeatures/cpu-features.c} for use when auto-detection via
+            {@code /proc} is not possible in Android 4.1 and higher.
+            (<a href="http://code.google.com/p/chromium/issues/detail?id=164154">Chromium Issue
+            164154</a>)</li>
+        </ul>
+      </dd>
+
+      <dt>Important bug fixes:</dt>
+      <dd>
+        <ul>
+          <li>Fixed unnecessary rebuild of object files when using the {@code ndk-build} script.
+            (<a href="http://code.google.com/p/android/issues/detail?id=39810">Issue 39810</a>)</li>
+          <li>Fixed a linker failure with the NDK 8c release for Mac OS X 10.6.x that produced the
+            following error:
+            <pre>
+dyld: lazy symbol binding failed: Symbol not found: _memmem
+Referenced from: ...../arm-linux-androideabi/bin/ld
+Expected in: /usr/lib/libSystem.B.dylib</pre>
+            This problem was caused by building on Mac OS X 10.7, which produced binaries that were
+            not compatible with Mac OS 10.6.x and the NDK.
+          </li>
+          <li>Removed the {@code -x c++} options from the Clang++ standalone build script.
+          (<a href="http://code.google.com/p/android/issues/detail?id=39089">Issue 39089</a>)</li>
+          <li>Fixed issues using the {@code NDK_TOOLCHAIN_VERSION=clang3.1} option in Cygwin.
+           (<a href="http://code.google.com/p/android/issues/detail?id=39585">Issue 39585</a>)</li>
+          <li>Fixed the {@code make-standalone-toolchain.sh} script to allow generation of a
+            standalone toolchain using the Cygwin or MinGW environments. The resulting toolchain
+            can be used in Cygwin, MingGW or CMD.exe environments.
+            (<a href="http://code.google.com/p/android/issues/detail?id=39915">Issue 39915</a>,
+            <a href="http://code.google.com/p/android/issues/detail?id=39585">Issue 39585</a>)</li>
+          <li>Added missing {@code SL_IID_ANDROIDBUFFERQUEUESOURCE} option in android-14 builds for
+            ARM and X86.
+            (<a href="http://code.google.com/p/android/issues/detail?id=40625">Issue 40625</a>)</li>
+          <li>Fixed x86 CPU detection for the {@code ANDROID_CPU_X86_FEATURE_MOVBE} feature.
+            (<a href="http://code.google.com/p/android/issues/detail?id=39317">Issue 39317</a>)</li>
+          <li>Fixed an issue preventing the Standard Template Library (STL) from using C++
+            sources that do not have a {@code .cpp} file extension.</li>
+          <li>Fixed GCC 4.6 ARM internal compiler error <em>at reload1.c:1061</em>.
+            (<a href="http://code.google.com/p/android/issues/detail?id=20862">Issue 20862</a>)</li>
+          <li>Fixed GCC 4.4.3 ARM internal compiler error <em>at emit-rtl.c:1954</em>.
+            (<a href="http://code.google.com/p/android/issues/detail?id=22336">Issue 22336</a>)</li>
+          <li>Fixed GCC 4.4.3 ARM internal compiler error <em>at postreload.c:396</em>.
+            (<a href="http://code.google.com/p/android/issues/detail?id=22345">Issue 22345</a>)</li>
+          <li>Fixed problem with GCC 4.6/4.7 skipping lambda functions.
+            (<a href="http://code.google.com/p/android/issues/detail?id=35933">Issue 35933</a>)</li>
+        </ul>
+      </dd>
+
+      <dt>Other bug fixes:</dt>
+      <dd>
+        <ul>
+          <li>NDK header file fixes:
+            <ul>
+              <li>Fixed {@code __WINT_TYPE__} and {@code wint_t} to be the same type.</li>
+              <li>Corrected typo in {@code android/bitmap.h}.
+                (<a href="http://code.google.com/p/android/issues/detail?id=15134">Issue 15134</a>)
+              </li>
+              <li>Corrected typo in {@code errno.h}.</li>
+              <li>Added check for the presence of {@code __STDC_VERSION__} in {@code sys/cdefs.h}.
+                (<a href="http://code.google.com/p/android/issues/detail?id=14627">Issue 14627</a>)
+              </li>
+              <li>Reorganized headers in {@code byteswap.h} and {@code dirent.h}.</li>
+              <li>Fixed {@code limits.h} to include {@code page.h} which provides {@code PAGE_SIZE}
+                settings.
+                (<a href="http://code.google.com/p/android/issues/detail?id=39983">Issue 39983</a>)
+              </li>
+              <li>Fixed return type of {@code glGetAttribLocation()} and
+                {@code glGetUniformLocation()} from {@code int} to {@code GLint}.</li>
+              <li>Fixed {@code __BYTE_ORDER} constant for x86 builds.
+                (<a href="http://code.google.com/p/android/issues/detail?id=39824">Issue 39824</a>)
+              </li>
+            </ul>
+          </li>
+          <li>Fixed {@code ndk-build} script to not overwrite {@code -Os} with {@code -O2} for ARM
+            builds.</li>
+          <li>Fixed build scripts to allow overwriting of {@code HOST_AWK}, {@code HOST_SED}, and
+            {@code HOST_MAKE} settings.</li>
+          <li>Fixed issue for {@code ld.gold} on {@code fsck_msdos} builds linking objects built by
+            the Intel C/C++ compiler (ICC).</li>
+          <li>Fixed ARM EHABI support in Clang to conform to specifications.</li>
+          <li>Fixed GNU Debugger (GDB) to shorten the time spent on walking the target's link map
+            during {@code solib} events.
+            (<a href="http://code.google.com/p/android/issues/detail?id=38402">Issue 38402</a>)</li>
+          <li>Fixed missing {@code libgcc.a} file when linking shared libraries.</li>
+        </ul>
+      </dd>
+
+      <dt>Other changes:</dt>
+      <dd>
+        <ul>
+          <li>Backported 64-bit built-in atomic functions for ARM to GCC 4.6.</li>
+          <li>Added documentation for audio output latency, along with other documentation and
+            fixes.</li>
+          <li>Fixed debug builds with Clang so that non-void functions now raise a {@code SIGILL}
+            signal for paths without a return statement.</li>
+          <li>Updated {@code make-standalone-toolchain.sh} to accept the suffix {@code -clang3.1}
+            which is equivalent to adding {@code --llvm-version=3.1} to the GCC 4.6 toolchain.</li>
+          <li>Updated GCC and Clang bug report URL to:
+            <a href="http://source.android.com/source/report-bugs.html">http://source.android.com/source/report-bugs.html</a></li>
+          <li>Added ARM ELF support to {@code llvm-objdump}.</li>
+          <li>Suppressed <em>treating c input as c++</em> warning for Clang builds.</li>
+          <li>Updated build so that only the 32-bit version of {@code libiberty.a} is built and
+            placed in {@code lib32/}.</li>
+        </ul>
+      </dd>
+    </dl>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt="">Android NDK, Revision 8c</a> <em>(November 2012)</em>
   </p>
 
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index afed043..9349a4e 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -28,6 +28,109 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>SDK Tools, Revision 21.0.1</a> <em>(December 2012)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <dl>
+    <dt>Dependencies:</dt>
+    <dd>
+      <ul>
+        <li>Android SDK Platform-tools revision 16 or later.</li>
+        <li>If you are developing in Eclipse with ADT, note that the SDK Tools r21.0.1 is
+          designed for use with ADT 21.0.1 and later. If you haven't already, update your
+        <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 21.0.0.</li>
+        <li>If you are developing outside Eclipse, you must have
+          <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
+    </ul>
+    </dd>
+
+    <dt>General Notes:</dt>
+    <dd>
+      <ul>
+        <li>Build
+          <ul>
+            <li>Updated build to detect and handle package name conflicts between an application and
+              the libraries it depends on. Libraries cannot share package names unless all of them
+              share the same package name.
+              (<a href="http://code.google.com/p/android/issues/detail?id=40152">Issue 40152</a>,
+               <a href="http://code.google.com/p/android/issues/detail?id=40273">Issue 40273</a>)
+            </li>
+            <li>Added a flag to disable dex merging to deal with cases where merging could generate
+              a broken dex file. If this happens to your project, add the following setting to your
+              {@code project.properties} file: {@code dex.disable.merger=true} This setting
+              causes the build system to revert to the older, slower dex processing that does not
+              pre-dex libraries.</li>
+          </ul>
+        </li>
+
+        <li>Renderscript
+          <ul>
+            <li>Added support for
+              <a href="{@docRoot}guide/topics/renderscript/compute.html#filterscript">Filterscript</a>
+              compilation.</li>
+            <li>Added new project setting to control the Renderscript compilation target separately
+              from an Android project. Adding the following line to a {@code project.properties}
+              file causes Renderscript code to be compiled for Android API Level 17, while the
+              containing application can target a different (lower) API level:
+              <pre>renderscript.target = 17</pre>
+              Previously, the Renderscript compilation target was tied to the
+              {@code android:minSdkVersion} setting in the manifest.
+              (<a href="http://code.google.com/p/android/issues/detail?id=40487">Issue 40487</a>)
+            </li>
+          </ul>
+        </li>
+
+      </ul>
+    </dd>
+
+
+    <dt>Bug fixes:</dt>
+    <dd>
+      <ul>
+        <li>Lint
+          <ul>
+            <li>Corrected check for {@code 0px} values in style XML elements.
+              (<a href="http://code.google.com/p/android/issues/detail?id=39601">Issue 39601</a>)
+              </li>
+            <li>Fixed incorrect flagging of formatting strings.
+              (<a href="http://code.google.com/p/android/issues/detail?id=39758">Issue 39758</a>)
+              </li>
+            <li>Fixed problem where {@code tools:ignore} directive in the manifest file was ignored
+              by the Lint tool.
+              (<a href="http://code.google.com/p/android/issues/detail?id=40136">Issue 40136</a>)
+              </li>
+            <li>Fixed problem with flagging a wakelock release inside a conditional.
+              (<a href="http://code.google.com/p/android/issues/detail?id=40424">Issue 40424</a>)
+              </li>
+            <li>Fixed incorrect reporting of missing {@code layout_width} and {@code layout_height}
+              XML fields.
+              (<a href="http://code.google.com/p/android/issues/detail?id=38958">Issue 38958</a>)
+              </li>
+            <li>Fixed handling of custom namespace attributes.</li>
+            <li>Added fixes for filtering out library project warnings.</li>
+            <li>Removed warnings about missing classes before a build.</li>
+          </ul>
+        </li>
+
+        <li>Fixed problem with UI Automator Viewer execution script where Android tools directory
+          is not set.</li>
+        <li>Fixed problem with the SDK Manager so that it auto-selects the most recently released
+          platform on startup.</li>
+        <li>Fixed Java finding script to look for the currently supported version of Java (1.6 or
+          higher).</li>
+        <li>Fixed the SDK Manager launcher in the ADT bundle so that it can properly launch the
+          SDK Manager program when it is placed at the root of the bundle.</li>
+      </ul>
+    </dd>
+    </dl>
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>SDK Tools, Revision 21</a> <em>(November 2012)</em>
   </p>
 
diff --git a/docs/html/training/articles/perf-jni.jd b/docs/html/training/articles/perf-jni.jd
index a21e9fe..2abb000 100644
--- a/docs/html/training/articles/perf-jni.jd
+++ b/docs/html/training/articles/perf-jni.jd
@@ -32,12 +32,11 @@
 code (written in C/C++).  It's vendor-neutral, has support for loading code from
 dynamic shared libraries, and while cumbersome at times is reasonably efficient.</p>
 
-<p>You really should read through the
-<a href="http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html">JNI spec for J2SE 6</a>
+<p>If you're not already familiar with it, read through the
+<a href="http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html">Java Native Interface Specification</a>
 to get a sense for how JNI works and what features are available.  Some
 aspects of the interface aren't immediately obvious on
-first reading, so you may find the next few sections handy.
-There's a more detailed <a href="http://java.sun.com/docs/books/jni/html/jniTOC.html">JNI Programmer's Guide and Specification</a>.</p>
+first reading, so you may find the next few sections handy.</p>
 
 
 <a name="JavaVM_and_JNIEnv" id="JavaVM_and_JNIEnv"></a>
diff --git a/docs/html/training/best-user-input.jd b/docs/html/training/best-user-input.jd
new file mode 100644
index 0000000..7f5ed15
--- /dev/null
+++ b/docs/html/training/best-user-input.jd
@@ -0,0 +1,9 @@
+page.title=Best Practices for User Input
+page.trainingcourse=true
+
+@jd:body
+
+
+
+<p>These classes cover various subjects of user input, such as
+touch screen gestures and text input through on-screen input methods and hardware keyboards.</p>
\ No newline at end of file
diff --git a/docs/html/training/gestures/detector.jd b/docs/html/training/gestures/detector.jd
new file mode 100644
index 0000000..06d0e98
--- /dev/null
+++ b/docs/html/training/gestures/detector.jd
@@ -0,0 +1,341 @@
+page.title=Detecting Common Gestures
+parent.title=Using Touch Gestures
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Tracking Movement
+next.link=movement.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#data">Gather Data</a></li>
+  <li><a href="#detect">Detect Gestures</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+
+<ul>
+   <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
+    </li>
+    <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
+    <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
+    <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
+    <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
+    <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
+</ul>
+
+
+</div>
+</div>
+
+<p>A "touch gesture" occurs when a user places one or more fingers on the touch
+screen, and your application interprets
+that pattern of touches as a particular gesture. There are correspondingly two
+phases to gesture detection:</p>
+
+<ol>
+  <li>Gathering data about touch events.</li>
+  
+  <li>Interpreting the data to see if it meets the criteria for any of the
+gestures your app supports. </li> 
+
+</ol>
+
+<h4>Support Library Classes</h4>
+
+<p>The examples in this lesson use the {@link android.support.v4.view.GestureDetectorCompat}
+and {@link android.support.v4.view.MotionEventCompat} classes. These classes are in the 
+<a href="{@docRoot}tools/extras/support-library.html">Support Library</a>. You should use
+Support Library classes where possible to provide compatibility with devices 
+running Android 1.6 and higher. Note that {@link android.support.v4.view.MotionEventCompat} is <em>not</em> a 
+replacement for the {@link android.view.MotionEvent} class. Rather, it provides static utility 
+methods to which you pass your {@link android.view.MotionEvent} object in order to receive 
+the desired action associated with that event.</p>
+
+<h2 id="data">Gather Data</h2>
+
+<p>When a user places one or more fingers on the screen, this  triggers the
+callback {@link android.view.View#onTouchEvent onTouchEvent()} 
+on the View that received the touch events.
+For each sequence of touch events (position, pressure, size, addition of another finger, etc.) 
+that is ultimately identified as a gesture,
+{@link android.view.View#onTouchEvent onTouchEvent()} is fired several times.</p>
+
+<p>The gesture starts when the user first touches the screen, continues as the system tracks
+the position of the user's finger(s), and ends by capturing the final event of
+the user's fingers leaving the screen. Throughout this interaction, 
+the {@link android.view.MotionEvent} delivered to {@link android.view.View#onTouchEvent onTouchEvent()} 
+provides the details of every interaction. Your app can use the data provided by the {@link android.view.MotionEvent} 
+to determine if a gesture it cares
+about happened.</p>
+
+<h3>Capturing touch events for an Activity or View</h3>
+
+<p><p>To intercept touch events in an Activity or View, override 
+the {@link android.view.View#onTouchEvent onTouchEvent()} callback.</p>
+
+<p>The following snippet uses 
+{@link android.support.v4.view.MotionEventCompat#getActionMasked getActionMasked()}
+to extract the action the user performed from the {@code event} parameter. This gives you the raw 
+data you need to determine if a gesture you care about occurred:</p>
+
+<pre>
+public class MainActivity extends Activity {
+...
+// This example shows an Activity, but you would use the same approach if
+// you were subclassing a View.
+&#64;Override
+public boolean onTouchEvent(MotionEvent event){ 
+        
+    int action = MotionEventCompat.getActionMasked(event);
+        
+    switch(action) {
+        case (MotionEvent.ACTION_DOWN) :
+            Log.d(DEBUG_TAG,"Action was DOWN");
+            return true;
+        case (MotionEvent.ACTION_MOVE) :
+            Log.d(DEBUG_TAG,"Action was MOVE");
+            return true;
+        case (MotionEvent.ACTION_UP) :
+            Log.d(DEBUG_TAG,"Action was UP");
+            return true;
+        case (MotionEvent.ACTION_CANCEL) :
+            Log.d(DEBUG_TAG,"Action was CANCEL");
+            return true;
+        case (MotionEvent.ACTION_OUTSIDE) :
+            Log.d(DEBUG_TAG,"Movement occurred outside bounds " +
+                    "of current screen element");
+            return true;      
+        default : 
+            return super.onTouchEvent(event);
+    }      
+}</pre>
+
+<p>You can then do your own processing on these events to determine if a
+gesture occurred. This is the kind of processing you would have to do for a
+custom gesture. However, if your app uses
+common gestures such as double tap, long press, fling, and so on, you can
+take advantage of the {@link
+android.view.GestureDetector} class. {@link
+android.view.GestureDetector} makes it easy for you to detect common
+gestures without processing the individual touch events yourself. This is
+discussed below in <a href="#detect">Detect Gestures</a>.</p>
+
+<h3>Capturing touch events for a single view</h3>
+
+<p>As an alternative to {@link android.view.View#onTouchEvent onTouchEvent()},
+you can attach an {@link android.view.View.OnTouchListener} object to any {@link
+android.view.View} object using the {@link android.view.View#setOnTouchListener
+setOnTouchListener()} method. This makes it possible to to listen for touch
+events without subclassing an existing {@link android.view.View}. For
+example:</p>
+
+<pre>View myView = findViewById(R.id.my_view); 
+myView.setOnTouchListener(new OnTouchListener() {
+    public boolean onTouch(View v, MotionEvent event) {
+        // ... Respond to touch events       
+        return true;
+    }
+});</pre>
+
+<p>Beware of creating a listener that returns {@code false} for the 
+{@link android.view.MotionEvent#ACTION_DOWN} event. If you do this, the listener will 
+not be called for the subsequent {@link android.view.MotionEvent#ACTION_MOVE} 
+and {@link android.view.MotionEvent#ACTION_UP} string of events. This is because
+{@link android.view.MotionEvent#ACTION_DOWN} is the starting point for all touch events.</p>
+
+<p>If you are creating a custom View, you can override 
+{@link android.view.View#onTouchEvent onTouchEvent()}, 
+as described above.</p>
+
+<h2 id="detect">Detect Gestures</h2>
+
+<p>Android provides the {@link android.view.GestureDetector} class for detecting
+common gestures. Some of the gestures it supports include {@link
+android.view.GestureDetector.OnGestureListener#onDown onDown()}, {@link
+android.view.GestureDetector.OnGestureListener#onLongPress onLongPress()},
+{@link android.view.GestureDetector.OnGestureListener#onFling onFling()}, and so
+on. You can use {@link android.view.GestureDetector} in conjunction with the 
+{@link android.view.View#onTouchEvent onTouchEvent()}
+method described above.</p>
+
+
+<h3>Detecting All Supported Gestures</h3>
+
+<p>When you instantiate a {@link android.support.v4.view.GestureDetectorCompat} 
+object, one of the parameters it takes is a class that implements the 
+{@link android.view.GestureDetector.OnGestureListener} interface.  
+{@link android.view.GestureDetector.OnGestureListener} notifies users when 
+a particular touch event has occurred. To make it possible for your 
+{@link android.view.GestureDetector} object to receive events, you override 
+the View or Activity's {@link android.view.View#onTouchEvent onTouchEvent()} method, 
+and pass along all observed events to the detector instance.</p>
+
+
+<p>In the following snippet, a return value of {@code true} from the individual 
+{@code on<em>&lt;TouchEvent&gt;</em>} methods indicates that you
+have handled the touch event. A return value of {@code false} passes events down
+through the view stack until the touch has been successfully handled.</p>
+
+<p>Run the following snippet to get a feel for how actions are triggered when
+you interact with the touch screen, and what the contents of the {@link
+android.view.MotionEvent} are for each touch event. You will realize how much
+data is being generated for even simple interactions.</p>
+
+<pre>public class MainActivity extends Activity implements 
+        GestureDetector.OnGestureListener,
+        GestureDetector.OnDoubleTapListener{
+    
+    private static final String DEBUG_TAG = "Gestures";
+    private GestureDetectorCompat mDetector; 
+
+    // Called when the activity is first created. 
+    &#64;Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        // Instantiate the gesture detector with the
+        // application context and an implementation of
+        // GestureDetector.OnGestureListener
+        mDetector = new GestureDetectorCompat(this,this);
+        // Set the gesture detector as the double tap
+        // listener.
+        mDetector.setOnDoubleTapListener(this);
+    }
+
+    &#64;Override 
+    public boolean onTouchEvent(MotionEvent event){ 
+        this.mDetector.onTouchEvent(event);
+        // Be sure to call the superclass implementation
+        return super.onTouchEvent(event);
+    }
+
+    &#64;Override
+    public boolean onDown(MotionEvent event) { 
+        Log.d(DEBUG_TAG,"onDown: " + event.toString()); 
+        return true;
+    }
+
+    &#64;Override
+    public boolean onFling(MotionEvent event1, MotionEvent event2, 
+            float velocityX, float velocityY) {
+        Log.d(DEBUG_TAG, "onFling: " + event1.toString()+event2.toString());
+        return true;
+    }
+
+    &#64;Override
+    public void onLongPress(MotionEvent event) {
+        Log.d(DEBUG_TAG, "onLongPress: " + event.toString()); 
+    }
+
+    &#64;Override
+    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
+            float distanceY) {
+        Log.d(DEBUG_TAG, "onScroll: " + e1.toString()+e2.toString());
+        return true;
+    }
+
+    &#64;Override
+    public void onShowPress(MotionEvent event) {
+        Log.d(DEBUG_TAG, "onShowPress: " + event.toString());
+    }
+
+    &#64;Override
+    public boolean onSingleTapUp(MotionEvent event) {
+        Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString());
+        return true;
+    }
+
+    &#64;Override
+    public boolean onDoubleTap(MotionEvent event) {
+        Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString());
+        return true;
+    }
+
+    &#64;Override
+    public boolean onDoubleTapEvent(MotionEvent event) {
+        Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString());
+        return true;
+    }
+
+    &#64;Override
+    public boolean onSingleTapConfirmed(MotionEvent event) {
+        Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString());
+        return true;
+    }
+}</pre>
+
+<h3>Detecting a Subset of Supported Gestures</h3>
+
+<p>If you only want to process a few gestures, you can extend {@link
+android.view.GestureDetector.SimpleOnGestureListener} instead of implementing
+the {@link android.view.GestureDetector.OnGestureListener} interface. </p>
+<p>
+{@link
+android.view.GestureDetector.SimpleOnGestureListener} provides an implementation
+for all of the {@code on<em>&lt;TouchEvent&gt;</em>} methods by returning {@code false}
+for all of them. Thus you can override only the methods you care about.
+For
+example, the snippet below creates a class that extends {@link
+android.view.GestureDetector.SimpleOnGestureListener} and overrides {@link
+android.view.GestureDetector.OnGestureListener#onFling onFling()} and {@link
+android.view.GestureDetector.OnGestureListener#onDown onDown()}.</p>
+
+<p>Whether or not you use {@link android.view.GestureDetector.OnGestureListener}, 
+it's best practice to implement an 
+{@link android.view.GestureDetector.OnGestureListener#onDown onDown()} 
+method that returns {@code true}. This is because all gestures begin with an 
+{@link android.view.GestureDetector.OnGestureListener#onDown onDown()} message. If you return 
+{@code false} from {@link android.view.GestureDetector.OnGestureListener#onDown onDown()}, 
+as {@link android.view.GestureDetector.SimpleOnGestureListener} does by default, 
+the system assumes that you want to ignore the rest of the gesture, and the other methods of 
+{@link android.view.GestureDetector.OnGestureListener} never get called. 
+This has the potential to cause unexpected problems in your app. 
+The only time you should return {@code false} from 
+{@link android.view.GestureDetector.OnGestureListener#onDown onDown()} 
+is if you truly want to ignore an entire gesture. </p>
+
+<pre>public class MainActivity extends Activity { 
+    
+    private GestureDetectorCompat mDetector; 
+
+    &#64;Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        mDetector = new GestureDetectorCompat(this, new MyGestureListener());
+    }
+
+    &#64;Override 
+    public boolean onTouchEvent(MotionEvent event){ 
+        this.mDetector.onTouchEvent(event);
+        return super.onTouchEvent(event);
+    }
+    
+    class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
+        private static final String DEBUG_TAG = "Gestures"; 
+        
+        &#64;Override
+        public boolean onDown(MotionEvent event) { 
+            Log.d(DEBUG_TAG,"onDown: " + event.toString()); 
+            return true;
+        }
+
+        &#64;Override
+        public boolean onFling(MotionEvent event1, MotionEvent event2, 
+                float velocityX, float velocityY) {
+            Log.d(DEBUG_TAG, "onFling: " + event1.toString()+event2.toString());
+            return true;
+        }
+    }
+}
+</pre>
+
+
diff --git a/docs/html/training/gestures/index.jd b/docs/html/training/gestures/index.jd
new file mode 100644
index 0000000..0191450
--- /dev/null
+++ b/docs/html/training/gestures/index.jd
@@ -0,0 +1,94 @@
+page.title=Using Touch Gestures
+trainingnavtop=true
+startpage=true
+next.title=Detect Built-in Gestures
+next.link=detector.html
+
+
+@jd:body
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
+<h2>Dependencies and prerequisites</h2>
+
+<ul>
+  <li>Android 1.6 (API Level 4) or higher</li>
+</ul>
+<h2>You should also read</h2>
+<ul>
+    <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
+    </li>
+    <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
+    <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
+    <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
+    <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
+    <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
+</ul>
+
+
+</div>
+</div>
+
+<p> This class describes how to write apps that allow users to interact with an
+app via touch gestures. Android provides a variety of APIs to
+help you create and detect gestures.</p>
+
+<p>Although your app should not depend on touch gestures for basic behaviors (since the gestures
+may not be available to all users in all contexts), adding touch-based
+interaction to your app can greatly increase its usefulness and appeal.</p>
+
+<p>To
+provide users with a consistent, intuitive experience, your app should follow
+the accepted Android conventions for touch gestures. The <a
+href="http://developer.android.com/design/patterns/gestures.html">Gestures
+design guide</a><a href="{@docRoot}design/patterns/notifications.html"></a>
+shows you how to use common gestures in Android apps. Also see the Design Guide
+for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a>.  </p>
+
+
+<h2>Lessons</h2>
+
+<dl>
+    <dt>
+        <strong><a href="detector.html">Detecting Common Gestures</a></strong>
+    </dt>
+    <dd>
+        Learn how to detect basic touch gestures such as scrolling, flinging, and double-tapping, using 
+       {@link android.view.GestureDetector}.
+    </dd>
+
+<dt>
+        <strong><a href="movement.html">Tracking Movement</a></strong>
+    </dt>
+    <dd>
+        Learn how to track movement.
+    </dd>
+
+<dt>
+        <strong><a href="scroll.html">Animating a Scroll Gesture</a></strong>
+    </dt>
+    <dd>
+        Learn how to use scrollers ({@link android.widget.Scroller} or {@link
+android.widget.OverScroller}) to produce a scrolling animation in response to a
+touch event. </dd>
+
+<dt>
+        <strong><a href="multi.html">Handling Multi-Touch Gestures</a></strong>
+    </dt>
+    <dd>
+        Learn how to detect multi-pointer (finger) gestures.
+    </dd> 
+<dt>
+        <strong><a href="scale.html">Dragging and Scaling</a></strong>
+    </dt>
+    <dd>
+        Learn how to implement touch-based dragging and scaling.
+    </dd>
+
+
+<dt><strong><a href="viewgroup.html">Managing Touch Events in a ViewGroup</a></strong></dt>
+
+    <dd>Learn how to manage touch events in a {@link android.view.ViewGroup} to
+ensure that touch events are correctly dispatched to their target views.</dd>
+</dl>
diff --git a/docs/html/training/gestures/movement.jd b/docs/html/training/gestures/movement.jd
new file mode 100644
index 0000000..f2c49d7
--- /dev/null
+++ b/docs/html/training/gestures/movement.jd
@@ -0,0 +1,151 @@
+page.title=Tracking Movement
+parent.title=Using Touch Gestures
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Animating a Scroll Gesture
+next.link=scroll.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#velocity">Track Velocity</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+
+<ul>
+    <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
+    </li>
+    <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
+    <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
+    <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
+    <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
+    <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
+</ul>
+
+
+</div>
+</div>
+
+<p>This lesson describes how to track movement in touch events.</p>
+
+<p>A new {@link
+android.view.View#onTouchEvent onTouchEvent()} is triggered with an {@link
+android.view.MotionEvent#ACTION_MOVE} event whenever the current touch contact
+position, pressure, or size changes. As described in <a
+href="detector.html">Detecting Common Gestures</a>, all of these events are
+recorded in the {@link android.view.MotionEvent} parameter of {@link
+android.view.View#onTouchEvent onTouchEvent()}.</p>
+
+<p>Because finger-based touch isn't always the most precise form of interaction,
+detecting touch events is often based more on movement than on simple contact.
+To help apps distinguish between movement-based gestures (such as a swipe) and
+non-movement gestures (such as a single tap), Android includes the notion of
+"touch slop." Touch slop refers to the distance in pixels a user's touch can wander
+before the gesture is interpreted as a movement-based gesture. For more discussion of this 
+topic, see <a href="viewgroup.html#vc">Managing Touch Events in a ViewGroup</a>.</p>
+
+
+
+<p>There are several different ways to track movement in a gesture, depending on
+the needs of your application. For example:</p> 
+
+<ul>
+
+<li>The starting and ending position of a pointer (for example, move an
+on-screen object from point A to point B).</li>
+
+<li>The direction the pointer is traveling in, as determined by the x and y coordinates.</li>
+
+<li>History. You can find the size of a gesture's history by calling the {@link
+android.view.MotionEvent} method {@link android.view.MotionEvent#getHistorySize
+getHistorySize()}. You can then obtain the positions, sizes, time, and pressures
+of each of the historical events by using the motion event's {@code
+getHistorical<em>&lt;Value&gt;</em>} methods. History is useful when rendering a trail of the user's finger, 
+such as for touch drawing. See the {@link android.view.MotionEvent} reference for
+details.</li>
+
+<li>The velocity of the pointer as it moves across the touch screen.</li>
+
+</ul>
+
+
+
+<h2 id="velocity">Track Velocity</h2>
+
+<p> You could have a movement-based gesture that is simply based on the distance and/or direction the pointer traveled. But velocity often is a
+determining factor in tracking a gesture's characteristics or even deciding
+whether the gesture occurred. To make velocity calculation easier, Android
+provides the {@link android.view.VelocityTracker} class and the  	
+{@link android.support.v4.view.VelocityTrackerCompat} class in the 
+<a href="{@docRoot}tools/extras/support-library.html">Support Library</a>.
+{@link
+android.view.VelocityTracker} helps you track the velocity of touch events. This
+is useful for gestures in which velocity is part of the criteria for the
+gesture, such as a fling.</p>
+
+
+<p>Here is a simple example that illustrates the purpose of the methods in the 
+{@link android.view.VelocityTracker} API:</p>
+
+<pre>public class MainActivity extends Activity {
+    private static final String DEBUG_TAG = "Velocity";
+        ...
+    private VelocityTracker mVelocityTracker = null;
+    &#64;Override
+    public boolean onTouchEvent(MotionEvent event) {
+        int index = event.getActionIndex();
+        int action = event.getActionMasked();
+        int pointerId = event.getPointerId(index);
+
+        switch(action) {
+            case MotionEvent.ACTION_DOWN:
+                if(mVelocityTracker == null) {
+                    // Retrieve a new VelocityTracker object to watch the velocity of a motion.
+                    mVelocityTracker = VelocityTracker.obtain();
+                }
+                else {
+                    // Reset the velocity tracker back to its initial state.
+                    mVelocityTracker.clear();
+                }
+                // Add a user's movement to the tracker.
+                mVelocityTracker.addMovement(event);
+                break;
+            case MotionEvent.ACTION_MOVE:
+                mVelocityTracker.addMovement(event);
+                // When you want to determine the velocity, call 
+                // computeCurrentVelocity(). Then call getXVelocity() 
+                // and getYVelocity() to retrieve the velocity for each pointer ID. 
+                mVelocityTracker.computeCurrentVelocity(1000);
+                // Log velocity of pixels per second
+                // Best practice to use VelocityTrackerCompat where possible.
+                Log.d("", "X velocity: " + 
+                        VelocityTrackerCompat.getXVelocity(mVelocityTracker, 
+                        pointerId));
+                Log.d("", "Y velocity: " + 
+                        VelocityTrackerCompat.getYVelocity(mVelocityTracker,
+                        pointerId));
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                // Return a VelocityTracker object back to be re-used by others.
+                mVelocityTracker.recycle();
+                break;
+        }
+        return true;
+    }
+}
+</pre>
+
+<p class="note"><strong>Note:</strong> Note that you should calculate velocity after an 
+{@link android.view.MotionEvent#ACTION_MOVE} event, 
+not after {@link android.view.MotionEvent#ACTION_UP}. After an {@link android.view.MotionEvent#ACTION_UP}, 
+the X and Y velocities will be 0.
+</p>
diff --git a/docs/html/training/gestures/multi.jd b/docs/html/training/gestures/multi.jd
new file mode 100644
index 0000000..d4c5b1d
--- /dev/null
+++ b/docs/html/training/gestures/multi.jd
@@ -0,0 +1,168 @@
+page.title=Handling Multi-Touch Gestures
+parent.title=Using Touch Gestures
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Dragging and Scaling
+next.link=scale.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#track">Track Multiple Pointers</a></li>
+  <li><a href="#action">Get a MotionEvent's Action</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+
+<ul>
+   <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
+    </li>
+    <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
+    <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
+    <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
+    <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
+    <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
+</ul>
+
+
+</div>
+</div>
+
+<p>A multi-touch gesture is when multiple pointers (fingers) touch the screen
+at the same time. This lesson describes how to detect gestures that involve
+multiple pointers.</p>
+
+<h2 id="track">Track Multiple Pointers</h2>
+
+<p>When multiple pointers touch the screen at the same time, the system generates the 
+following touch events:</p>
+
+<ul>
+  <li>{@link android.view.MotionEvent#ACTION_DOWN}&mdash;For the first pointer that 
+touches the screen. This starts the gesture. The pointer data for this pointer is 
+always at index 0 in the {@link android.view.MotionEvent}.</li>
+  <li>{@link android.support.v4.view.MotionEventCompat#ACTION_POINTER_DOWN}&mdash;For 
+extra pointers that enter the screen beyond the first. The pointer data for this 
+pointer is at the index returned by {@link android.support.v4.view.MotionEventCompat#getActionIndex getActionIndex()}.</li>
+  <li>{@link android.view.MotionEvent#ACTION_MOVE}&mdash;A change has happened during a press gesture.</li>
+  <li>{@link android.support.v4.view.MotionEventCompat#ACTION_POINTER_UP}&mdash;Sent when a non-primary pointer goes up.</li>
+  <li>{@link android.view.MotionEvent#ACTION_UP}&mdash;Sent when the last pointer leaves the screen.</li>
+</ul>
+
+<p>You keep track of individual pointers within a {@link
+android.view.MotionEvent} via each pointer's index and ID:</p>
+
+<ul>
+<li><strong>Index</strong>: A {@link android.view.MotionEvent} effectively 
+stores information about each pointer in an array. The index of a pointer is its position 
+within this array. Most of the {@link
+android.view.MotionEvent} methods you use to interact with pointers take the
+pointer index as a parameter, not the pointer ID. </li>
+  
+  
+  <li><strong>ID</strong>: Each pointer also has an ID mapping that stays
+persistent across touch events to allow tracking an individual pointer across 
+the entire gesture.</li>
+  
+</ul>
+
+<p>The  order in which individual pointers appear within a motion event is 
+undefined. Thus the index of a pointer can change from one event to the
+next, but the pointer ID of a pointer is guaranteed to remain  constant as long
+as the pointer remains active. Use the  {@link
+android.view.MotionEvent#getPointerId getPointerId()} method to obtain a
+pointer's ID to track the pointer across all subsequent motion events in a
+gesture. Then for successive  motion events, use the {@link
+android.view.MotionEvent#findPointerIndex findPointerIndex()} method to obtain
+the pointer index for a given pointer ID in that motion event. For example:</p>
+
+
+<pre>private int mActivePointerId;
+ 
+public boolean onTouchEvent(MotionEvent event) {
+    ....
+    // Get the pointer ID
+    mActivePointerId = event.getPointerId(0);
+
+    // ... Many touch events later...
+
+    // Use the pointer ID to find the index of the active pointer 
+    // and fetch its position
+    int pointerIndex = event.findPointerIndex(mActivePointerId);
+    // Get the pointer's current position
+    float x = event.getX(pointerIndex);
+    float y = event.getY(pointerIndex);
+}</pre>
+
+<h2 id="action">Get a MotionEvent's Action</h2>
+
+<p>You should always use the method  
+{@link android.view.MotionEvent#getActionMasked getActionMasked()} (or better yet, the compatability version 
+{@link android.support.v4.view.MotionEventCompat#getActionMasked MotionEventCompat.getActionMasked()}) to retrieve 
+the action of a
+{@link android.view.MotionEvent}. Unlike the older {@link android.view.MotionEvent#getAction getAction()} 
+method, {@link android.support.v4.view.MotionEventCompat#getActionMasked getActionMasked()} is designed to work with 
+multiple pointers. It returns the masked action 
+being performed, without including the pointer index bits. You can then use 
+{@link android.support.v4.view.MotionEventCompat#getActionIndex getActionIndex()} to return the index of 
+the pointer associated with the action. This is illustrated in the snippet below.</p>
+
+<p class="note"><strong>Note:</strong> This example uses the 
+{@link android.support.v4.view.MotionEventCompat}
+class. This class is in the 
+<a href="{@docRoot}tools/extras/support-library.html">Support Library</a>. You should use
+{@link android.support.v4.view.MotionEventCompat} to provide the best support for a wide range of
+platforms. Note that {@link android.support.v4.view.MotionEventCompat} is <em>not</em> a 
+replacement for the {@link android.view.MotionEvent} class. Rather, it provides static utility 
+methods to which you pass your {@link android.view.MotionEvent} object in order to receive 
+the desired action associated with that event.</p>
+
+<pre>int action = MotionEventCompat.getActionMasked(event);
+// Get the index of the pointer associated with the action.
+int index = MotionEventCompat.getActionIndex(event);
+int xPos = -1;
+int yPos = -1;
+
+Log.d(DEBUG_TAG,"The action is " + actionToString(action));
+	    
+if (event.getPointerCount() > 1) {
+    Log.d(DEBUG_TAG,"Multitouch event"); 
+    // The coordinates of the current screen contact, relative to 
+    // the responding View or Activity.  
+    xPos = (int)MotionEventCompat.getX(event, index);
+    yPos = (int)MotionEventCompat.getY(event, index);
+
+} else {
+    // Single touch event
+    Log.d(DEBUG_TAG,"Single touch event"); 
+    xPos = (int)MotionEventCompat.getX(event, index);
+    yPos = (int)MotionEventCompat.getY(event, index);
+}
+...
+
+// Given an action int, returns a string description
+public static String actionToString(int action) {
+    switch (action) {
+	        
+        case MotionEvent.ACTION_DOWN: return "Down";
+	case MotionEvent.ACTION_MOVE: return "Move";
+	case MotionEvent.ACTION_POINTER_DOWN: return "Pointer Down";
+	case MotionEvent.ACTION_UP: return "Up";
+	case MotionEvent.ACTION_POINTER_UP: return "Pointer Up";
+	case MotionEvent.ACTION_OUTSIDE: return "Outside";
+	case MotionEvent.ACTION_CANCEL: return "Cancel";
+    }
+    return "";
+}</pre>
+
+ 
+
+
+<p>For more discussion of multi-touch and some examples, see the lesson <a href="scale.html">Dragging and Scaling</a>.
diff --git a/docs/html/training/gestures/scale.jd b/docs/html/training/gestures/scale.jd
new file mode 100644
index 0000000..17e4085
--- /dev/null
+++ b/docs/html/training/gestures/scale.jd
@@ -0,0 +1,240 @@
+page.title=Dragging and Scaling
+parent.title=Using Touch Gestures
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Managing Touch Events in a ViewGroup
+next.link=viewgroup.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#drag">Drag an Object</a></li>
+  <li><a href="#scale">Use Touch to Perform Scaling</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+
+<ul>
+    <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
+    </li>
+    <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
+    <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
+    <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
+    <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
+    <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
+</ul>
+
+
+</div>
+</div>
+<p>This lesson describes how to use touch gestures to drag and scale on-screen
+objects, using {@link android.view.View#onTouchEvent onTouchEvent()} to intercept
+touch events. Here is the original <a
+href="http://code.google.com/p/android-touchexample/">source code</a>
+for the examples used in this lesson.
+</p>
+
+<h2 id="drag">Drag an Object</h2>
+
+<p class="note">If you are targeting Android 3.0 or higher, you can use the built-in drag-and-drop event 
+listeners with {@link android.view.View.OnDragListener}, as described in 
+<a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a>.
+
+<p>A common operation for a touch gesture is to use it to drag an object across
+the screen. The following snippet lets the user drag an on-screen image. Note
+the following:</p>
+
+<ul>
+
+<li>In a drag (or scroll) operation, the app has to keep track of the original pointer
+(finger), even if additional fingers get placed on the screen. For example,
+imagine that while dragging the image around, the user places a second finger on
+the touch screen and lifts the first finger. If your app is just tracking
+individual pointers, it will regard the second pointer as the default and move
+the image to that location.</li>
+
+<li>To prevent this from happening, your app needs to distinguish between the 
+original pointer and any follow-on pointers. To do this, it tracks the 
+{@link android.view.MotionEvent#ACTION_POINTER_DOWN} and 
+{@link android.view.MotionEvent#ACTION_POINTER_UP} events described in 
+<a href="multi.html">Handling Multi-Touch Gestures</a>. 
+{@link android.view.MotionEvent#ACTION_POINTER_DOWN} and 
+{@link android.view.MotionEvent#ACTION_POINTER_UP} are 
+passed to the {@link android.view.View#onTouchEvent onTouchEvent()} callback 
+whenever a secondary pointer goes down or up. </li>
+
+
+<li>In the {@link android.view.MotionEvent#ACTION_POINTER_UP} case, the example
+extracts this index and ensures that the active pointer ID is not referring to a
+pointer that is no longer touching the screen. If it is, the app selects a
+different pointer to be active and saves its current X and Y position. Since
+this saved position is used in the {@link android.view.MotionEvent#ACTION_MOVE}
+case to calculate the distance to move the onscreen object, the app will always
+calculate the distance to move using data from the correct pointer.</li>
+
+</ul>
+
+<p>The following snippet enables a user to drag an object around on the screen. It records the initial
+position of the active pointer, calculates the distance the pointer traveled, and moves the object to the
+new position. It correctly manages the possibility of additional pointers, as described
+above.</p> 
+
+<p>Notice that the snippet uses the {@link android.view.MotionEvent#getActionMasked getActionMasked()} method. 
+You should always use this method (or better yet, the compatability version 
+{@link android.support.v4.view.MotionEventCompat#getActionMasked MotionEventCompat.getActionMasked()}) 
+to retrieve the action of a
+{@link android.view.MotionEvent}. Unlike the older 
+{@link android.view.MotionEvent#getAction getAction()} 
+method, {@link android.support.v4.view.MotionEventCompat#getActionMasked getActionMasked()} 
+is designed to work with multiple pointers. It returns the masked action 
+being performed, without including the pointer index bits.</p>
+
+<pre>// The ‘active pointer’ is the one currently moving our object.
+private int mActivePointerId = INVALID_POINTER_ID;
+
+&#64;Override
+public boolean onTouchEvent(MotionEvent ev) {
+    // Let the ScaleGestureDetector inspect all events.
+    mScaleDetector.onTouchEvent(ev);
+             
+    final int action = MotionEventCompat.getActionMasked(ev); 
+        
+    switch (action) { 
+    case MotionEvent.ACTION_DOWN: {
+        final int pointerIndex = MotionEventCompat.getActionIndex(ev); 
+        final float x = MotionEventCompat.getX(ev, pointerIndex); 
+        final float y = MotionEventCompat.getY(ev, pointerIndex); 
+            
+        // Remember where we started (for dragging)
+        mLastTouchX = x;
+        mLastTouchY = y;
+        // Save the ID of this pointer (for dragging)
+        mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
+        break;
+    }
+            
+    case MotionEvent.ACTION_MOVE: {
+        // Find the index of the active pointer and fetch its position
+        final int pointerIndex = 
+                MotionEventCompat.findPointerIndex(ev, mActivePointerId);  
+            
+        final float x = MotionEventCompat.getX(ev, pointerIndex);
+        final float y = MotionEventCompat.getY(ev, pointerIndex);
+            
+        // Only move if the ScaleGestureDetector isn't processing a gesture.
+        if (!mScaleDetector.isInProgress()) {
+            // Calculate the distance moved
+            final float dx = x - mLastTouchX;
+            final float dy = y - mLastTouchY;
+
+            mPosX += dx;
+            mPosY += dy;
+
+            invalidate();
+        }
+        // Remember this touch position for the next move event
+        mLastTouchX = x;
+        mLastTouchY = y;
+
+        break;
+    }
+            
+    case MotionEvent.ACTION_UP: {
+        mActivePointerId = INVALID_POINTER_ID;
+        break;
+    }
+            
+    case MotionEvent.ACTION_CANCEL: {
+        mActivePointerId = INVALID_POINTER_ID;
+        break;
+    }
+        
+    case MotionEvent.ACTION_POINTER_UP: {
+            
+        final int pointerIndex = MotionEventCompat.getActionIndex(ev); 
+        final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); 
+
+        if (pointerId == mActivePointerId) {
+            // This was our active pointer going up. Choose a new
+            // active pointer and adjust accordingly.
+            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+            mLastTouchX = MotionEventCompat.getX(ev, newPointerIndex); 
+            mLastTouchY = MotionEventCompat.getY(ev, newPointerIndex); 
+            mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
+        }
+        break;
+    }
+    }       
+    return true;
+}</pre>
+
+<h2 id="scale">Use Touch to Perform Scaling</h2>
+
+<p>As discussed in <a href="detector.html">Detecting Common Gestures</a>,
+{@link android.view.GestureDetector} helps you detect common gestures used by
+Android such as scrolling, flinging, and long press. For scaling, Android
+provides {@link android.view.ScaleGestureDetector}. {@link
+android.view.GestureDetector} and {@link android.view.ScaleGestureDetector} can
+be used together when you  want a view to recognize additional gestures.</p>
+
+<p>To report detected  gesture events, gesture detectors use listener objects 
+passed to their constructors. {@link android.view.ScaleGestureDetector} uses 
+{@link android.view.ScaleGestureDetector.OnScaleGestureListener}. 
+Android provides 
+{@link android.view.ScaleGestureDetector.SimpleOnScaleGestureListener} 
+as a helper class that you can extend if you don’t care about all of the reported events.</p>
+
+<p>Here is a snippet that gives you the basic idea of how to perform scaling.
+Here is the original <a
+href="http://code.google.com/p/android-touchexample/">source code</a>
+for the examples.</p>
+
+<pre>private ScaleGestureDetector mScaleDetector;
+private float mScaleFactor = 1.f;
+
+public MyCustomView(Context mContext){
+    ...
+    // View code goes here
+    ...
+    mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
+}
+
+&#64;Override
+public boolean onTouchEvent(MotionEvent ev) {
+    // Let the ScaleGestureDetector inspect all events.
+    mScaleDetector.onTouchEvent(ev);
+    return true;
+}
+
+&#64;Override
+public void onDraw(Canvas canvas) {
+    super.onDraw(canvas);
+
+    canvas.save();
+    canvas.scale(mScaleFactor, mScaleFactor);
+    ...
+    // onDraw() code goes here
+    ...
+    canvas.restore();
+}
+
+private class ScaleListener 
+        extends ScaleGestureDetector.SimpleOnScaleGestureListener {
+    &#64;Override
+    public boolean onScale(ScaleGestureDetector detector) {
+        mScaleFactor *= detector.getScaleFactor();
+
+        // Don't let the object get too small or too large.
+        mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
+
+        invalidate();
+        return true;
+    }
+}</pre>
diff --git a/docs/html/training/gestures/scroll.jd b/docs/html/training/gestures/scroll.jd
new file mode 100644
index 0000000..955495a
--- /dev/null
+++ b/docs/html/training/gestures/scroll.jd
@@ -0,0 +1,161 @@
+page.title=Animating a Scroll Gesture
+parent.title=Using Touch Gestures
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Handling Multi-Touch Gestures
+next.link=multi.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#scroll">Implement Touch-Based Scrolling</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+
+<ul>
+    <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
+    </li>
+    <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
+    <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
+    <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
+    <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
+    <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
+</ul>
+
+
+</div>
+</div>
+
+<p>In Android, scrolling is typically achieved by using the 
+{@link android.widget.ScrollView}
+class. Any standard layout that might extend beyond the bounds of its container should be 
+nested in a {@link android.widget.ScrollView} to provide a scrollable view that's 
+managed by the framework. Implementing a custom scroller should only be 
+necessary for special scenarios. This lesson describes such a scenario: displaying 
+a scrolling effect in response to touch gestures using <em>scrollers</em>.
+
+
+<p>You can use scrollers ({@link android.widget.Scroller} or {@link
+android.widget.OverScroller}) to collect the data you need to produce a
+scrolling animation in response to a touch event. {@link
+android.widget.Scroller} and {@link android.widget.OverScroller} are largely
+interchangeable&mdash;the difference is that {@link android.widget.OverScroller}
+allows temporarily scrolling beyond the minimum/maximum boundaries and springing
+back to the bounds. This is normally rendered using a "glow" effect, provided by
+the {@link android.widget.EdgeEffect} or {@link
+android.support.v4.widget.EdgeEffectCompat} classes. </p>
+
+<p>A scroller is used  to animate scrolling over time, using platform-standard
+scrolling physics (friction, velocity, etc.). The scroller itself doesn't
+actually draw anything. Scrollers track scroll offsets for you over time, but
+they don't  automatically apply those positions to your view. It's your
+responsibility to get and apply new coordinates at a rate that will make the
+scrolling animation look smooth.</p>
+
+<p class="note"><strong>Note:</strong> You generally only need to use scrollers
+when implementing scrolling yourself. {@link android.widget.ScrollView} and
+{@link android.widget.HorizontalScrollView} do all this for you do all of this for you if you nest your layout within them.</p>
+
+<h2 id = "scroll">Implement Touch-Based Scrolling</h2>
+
+
+<p>This snippet illustrates the basics of using a scroller. It uses a 
+{@link android.view.GestureDetector}, and overrides the  
+{@link android.view.GestureDetector.SimpleOnGestureListener} methods 
+{@link android.view.GestureDetector.OnGestureListener#onDown onDown()} and 
+{@link android.view.GestureDetector.OnGestureListener#onFling onFling()}. It also 
+overrides {@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()} 
+to return {@code false} since you don't need to animate a scroll.</p>
+
+
+<p>It's common to use scrollers in conjunction with a fling gesture, but they
+can be used in pretty much any context where you want the UI to display
+scrolling in response to a touch event. For example, you could override {@link
+android.view.View#onTouchEvent onTouchEvent()} to process touch events directly,
+and produce a scrolling effect in response to those touch events.</p>
+
+<pre>
+private OverScroller mScroller = new OverScroller(context);
+
+private GestureDetector.SimpleOnGestureListener mGestureListener
+        = new GestureDetector.SimpleOnGestureListener() {
+    &#64;Override
+    public boolean onDown(MotionEvent e) {
+        // Abort any active scroll animations and invalidate.
+        mScroller.forceFinished(true);
+        // There is also a compatibility version: 
+        // ViewCompat.postInvalidateOnAnimation
+        postInvalidateOnAnimation();
+        return true;
+    }
+
+    &#64;Override
+    public boolean onScroll(MotionEvent e1, MotionEvent e2, 
+            float distanceX, float distanceY) {
+        // You don't use a scroller in onScroll because you don't need to animate
+        // a scroll. The scroll occurs instantly in response to touch feedback.
+        return false;
+    }
+
+    &#64;Override
+    public boolean onFling(MotionEvent e1, MotionEvent e2, 
+            float velocityX, float velocityY) {
+        // Before flinging, abort the current animation.
+        mScroller.forceFinished(true);
+        // Begin the scroll animation
+        mScroller.fling(
+                // Current scroll position
+                startX,
+                startY,
+                // Velocities, negated for natural touch response
+                (int) -velocityX,
+                (int) -velocityY,
+                // Minimum and maximum scroll positions. The minimum scroll 
+                // position is generally zero and the maximum scroll position 
+                // is generally the content size less the screen size. So if the 
+                // content width is 1000 pixels and the screen width is 200  
+                // pixels, the maximum scroll offset should be 800 pixels.
+                minX, maxX,
+                minY, maxY,
+                // The maximum overscroll bounds. This is useful when using
+                // the EdgeEffect class to draw overscroll "glow" overlays.
+                mContentRect.width() / 2,
+                mContentRect.height() / 2);
+        // Invalidate to trigger computeScroll()
+        postInvalidateOnAnimation();
+        return true;
+    }
+};
+
+&#64;Override
+public void computeScroll() {
+    super.computeScroll();
+
+    // Compute the current scroll offsets. If this returns true, then the 
+    // scroll has not yet finished.
+    if (mScroller.computeScrollOffset()) {
+        int currX = mScroller.getCurrX();
+        int currY = mScroller.getCurrY();
+
+        // Actually render the scrolled viewport, or actually scroll the 
+        // view using View.scrollTo.
+
+        // If currX or currY are outside the bounds, render the overscroll 
+        // glow using EdgeEffect.
+
+    } else {
+        // The scroll has finished.
+    }
+}</pre>
+
+<p>For another example of scroller usage, see the <a href="http://github.com/android/platform_frameworks_support/blob/master/v4/java/android/support/v4/view/ViewPager.java">source code</a> for the 
+{@link android.support.v4.view.ViewPager} class. It scrolls in response to flings, 
+and uses scrolling to implement the "snapping to page" animation.</p>
diff --git a/docs/html/training/gestures/viewgroup.jd b/docs/html/training/gestures/viewgroup.jd
new file mode 100644
index 0000000..257a5d8
--- /dev/null
+++ b/docs/html/training/gestures/viewgroup.jd
@@ -0,0 +1,302 @@
+page.title=Managing Touch Events in a ViewGroup
+parent.title=Using Touch Gestures
+parent.link=index.html
+
+trainingnavtop=true
+next.title=
+next.link=
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#intercept">Intercept Touch Events in a ViewGroup</a></li>
+  <li><a href="#vc">Use ViewConfiguration Constants</a></li>
+  <li><a href="#delegate">Extend a Child View's Touchable Area</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+
+<ul>
+    <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
+    </li>
+    <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
+    <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
+    <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
+    <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
+    <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
+</ul>
+
+
+</div>
+</div>
+
+<p>Handling touch events in a {@link android.view.ViewGroup} takes special care,
+because it's common for a {@link android.view.ViewGroup} to have children that
+are targets for different touch events than the {@link android.view.ViewGroup}
+itself. To make sure that each view correctly receives the touch events intended
+for it, override the {@link android.view.ViewGroup#onInterceptTouchEvent
+onInterceptTouchEvent()} method.</p>
+
+<h2 id="intercept">Intercept Touch Events in a ViewGroup</h2>
+
+<p>The {@link android.view.ViewGroup#onInterceptTouchEvent onInterceptTouchEvent()} 
+method is called whenever a touch event is detected on the surface of a 
+{@link android.view.ViewGroup}, including on the surface of its children. If 
+{@link android.view.ViewGroup#onInterceptTouchEvent onInterceptTouchEvent()} 
+returns {@code true}, the {@link android.view.MotionEvent} is intercepted, 
+meaning it will be not be passed on to the child, but rather to the 
+{@link android.view.View#onTouchEvent onTouchEvent()} method of the parent.</p>
+
+<p>The {@link android.view.ViewGroup#onInterceptTouchEvent onInterceptTouchEvent()} 
+method gives a parent the chance to see any touch event before its children do. 
+If you return {@code true} from 
+{@link android.view.ViewGroup#onInterceptTouchEvent onInterceptTouchEvent()}, 
+the child view that was previously handling touch events 
+receives an {@link android.view.MotionEvent#ACTION_CANCEL}, and the events from that 
+point forward are sent to the parent's 
+{@link android.view.View#onTouchEvent onTouchEvent()} method for the usual handling. 
+{@link android.view.ViewGroup#onInterceptTouchEvent onInterceptTouchEvent()} can also 
+return {@code false} and simply spy on events as they travel down the view hierarchy 
+to their usual targets, which will handle the events with their own
+{@link android.view.View#onTouchEvent onTouchEvent()}.
+
+
+<p>In the following snippet, the class {@code MyViewGroup} extends  
+{@link android.view.ViewGroup}. 
+{@code MyViewGroup} contains multiple child views. If you drag your finger across 
+a child view horizontally, the child view should no longer get touch events, and 
+{@code MyViewGroup} should handle touch events by scrolling its contents. However, 
+if you press buttons in the child view, or scroll the child view vertically, 
+the parent shouldn't intercept those touch events, because the child is the 
+intended target. In those cases, 
+{@link android.view.ViewGroup#onInterceptTouchEvent onInterceptTouchEvent()} should
+return {@code false}, and {@code MyViewGroup}'s 
+{@link android.view.View#onTouchEvent onTouchEvent()} won't be called.</p>
+
+<pre>public class MyViewGroup extends ViewGroup {
+
+    private int mTouchSlop;
+
+    ...
+
+    ViewConfiguration vc = ViewConfiguration.get(view.getContext());
+    mTouchSlop = vc.getScaledTouchSlop();
+
+    ...
+
+    &#64;Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        /*
+         * This method JUST determines whether we want to intercept the motion.
+         * If we return true, onTouchEvent will be called and we do the actual
+         * scrolling there.
+         */
+
+
+        final int action = MotionEventCompat.getActionMasked(ev);
+
+        // Always handle the case of the touch gesture being complete.
+        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+            // Release the scroll.
+            mIsScrolling = false;
+            return false; // Do not intercept touch event, let the child handle it
+        }
+
+        switch (action) {
+            case MotionEvent.ACTION_MOVE: {
+                if (mIsScrolling) {
+                    // We're currently scrolling, so yes, intercept the 
+                    // touch event!
+                    return true;
+                }
+
+                // If the user has dragged her finger horizontally more than 
+                // the touch slop, start the scroll
+
+                // left as an exercise for the reader
+                final int xDiff = calculateDistanceX(ev); 
+
+                // Touch slop should be calculated using ViewConfiguration 
+                // constants.
+                if (xDiff > mTouchSlop) { 
+                    // Start scrolling!
+                    mIsScrolling = true;
+                    return true;
+                }
+                break;
+            }
+            ...
+        }
+
+        // In general, we don't want to intercept touch events. They should be 
+        // handled by the child view.
+        return false;
+    }
+
+    &#64;Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        // Here we actually handle the touch event (e.g. if the action is ACTION_MOVE, 
+        // scroll this container).
+        // This method will only be called if the touch event was intercepted in 
+        // onInterceptTouchEvent
+        ...
+    }
+}</pre>
+
+<p>Note that {@link android.view.ViewGroup} also provides a 
+{@link android.view.ViewGroup#requestDisallowInterceptTouchEvent requestDisallowInterceptTouchEvent()} method. 
+The {@link android.view.ViewGroup} calls this method when a child does not want the parent and its 
+ancestors to intercept touch events with 
+{@link android.view.ViewGroup#onInterceptTouchEvent onInterceptTouchEvent()}. 
+</p>
+
+<h2 id="vc">Use ViewConfiguration Constants</h2>
+
+<p>The above snippet uses the current {@link android.view.ViewConfiguration} to initialize
+a variable called {@code mTouchSlop}. You can use the {@link
+android.view.ViewConfiguration} class to access common distances, speeds, and
+times used by the Android system.</p>
+
+
+<p>"Touch slop" refers to the distance in pixels a user's touch can wander
+before the gesture is interpreted as scrolling. Touch slop is typically used to
+prevent accidental scrolling when the user is performing some other touch
+operation, such as touching on-screen elements.</p>
+
+<p>Two other commonly used {@link android.view.ViewConfiguration} methods are 
+{@link android.view.ViewConfiguration#getScaledMinimumFlingVelocity getScaledMinimumFlingVelocity()} 
+and {@link android.view.ViewConfiguration#getScaledMaximumFlingVelocity getScaledMaximumFlingVelocity()}.
+These methods  return the minimum and maximum velocity (respectively) to initiate a fling, 
+as measured in pixels per second. For example:</p>
+
+<pre>ViewConfiguration vc = ViewConfiguration.get(view.getContext());
+private int mSlop = vc.getScaledTouchSlop();
+private int mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
+private int mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
+
+...
+
+case MotionEvent.ACTION_MOVE: {
+    ...
+    float deltaX = motionEvent.getRawX() - mDownX;
+    if (Math.abs(deltaX) > mSlop) {
+        // A swipe occurred, do something
+    }
+
+...
+
+case MotionEvent.ACTION_UP: {
+    ...
+    } if (mMinFlingVelocity <= velocityX && velocityX <= mMaxFlingVelocity
+            && velocityY < velocityX) {
+        // The criteria have been satisfied, do something
+    }
+}</pre>
+
+
+<h2 id="delegate">Extend a Child View's Touchable Area</h2>
+
+<p>Android provides the {@link android.view.TouchDelegate} class to make it possible 
+for a parent to extend the touchable area of a child view beyond the child's bounds. 
+
+This is useful when the child has to be small, but should have a larger touch region. You can
+also use this approach to shrink the child's touch region if need be.</p>
+
+<p>In the following example, an {@link android.widget.ImageButton} is the  
+"delegate view" (that is, the child whose touch area the parent will extend). 
+Here is the layout file:</p>
+
+<pre>
+&lt;RelativeLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
+     android:id=&quot;@+id/parent_layout&quot;
+     android:layout_width=&quot;match_parent&quot;
+     android:layout_height=&quot;match_parent&quot;
+     tools:context=&quot;.MainActivity&quot; &gt;
+ 
+     &lt;ImageButton android:id=&quot;@+id/button&quot;
+          android:layout_width=&quot;wrap_content&quot;
+          android:layout_height=&quot;wrap_content&quot;
+          android:background=&quot;@null&quot;
+          android:src=&quot;@drawable/icon&quot; /&gt;
+&lt;/RelativeLayout&gt;
+</pre>
+
+<p>The snippet below does the following:</p>
+
+<ul>
+<li>Gets the parent view and posts a {@link java.lang.Runnable} on the UI thread. This ensures that the parent lays out its children before calling the {@link android.view.View#getHitRect getHitRect()} method. The {@link android.view.View#getHitRect getHitRect()} method gets the child's hit rectangle (touchable area) in the parent's coordinates.</li>
+<li>Finds the {@link android.widget.ImageButton} child view and calls {@link android.view.View#getHitRect getHitRect()} to get the bounds of the child's touchable area.</li>
+<li>Extends the bounds of the {@link android.widget.ImageButton}'s hit rectangle.</li>
+<li>Instantiates a {@link android.view.TouchDelegate}, passing in the expanded hit rectangle and the {@link android.widget.ImageButton} child view as parameters.</li>
+<li>Sets the {@link android.view.TouchDelegate} on the parent view, such that touches within the touch delegate bounds are routed to the child.</li>
+
+</ul>
+
+In its capacity as touch delegate for the {@link android.widget.ImageButton} child view, the 
+parent view will receive all touch events. If the touch event occurred within the child's hit
+rectangle, the parent will pass the touch 
+event to the child for handling.</p>
+
+
+
+<pre>
+public class MainActivity extends Activity {
+
+    &#64;Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        // Get the parent view
+        View parentView = findViewById(R.id.parent_layout);
+        
+        parentView.post(new Runnable() {
+            // Post in the parent's message queue to make sure the parent
+            // lays out its children before you call getHitRect()
+            &#64;Override
+            public void run() {
+                // The bounds for the delegate view (an ImageButton
+                // in this example)
+                Rect delegateArea = new Rect();
+                ImageButton myButton = (ImageButton) findViewById(R.id.button);
+                myButton.setEnabled(true);
+                myButton.setOnClickListener(new View.OnClickListener() {
+                    &#64;Override
+                    public void onClick(View view) {
+                        Toast.makeText(MainActivity.this, 
+                                "Touch occurred within ImageButton touch region.", 
+                                Toast.LENGTH_SHORT).show();
+                    }
+                });
+     
+                // The hit rectangle for the ImageButton
+                myButton.getHitRect(delegateArea);
+            
+                // Extend the touch area of the ImageButton beyond its bounds
+                // on the right and bottom.
+                delegateArea.right += 100;
+                delegateArea.bottom += 100;
+            
+                // Instantiate a TouchDelegate.
+                // "delegateArea" is the bounds in local coordinates of 
+                // the containing view to be mapped to the delegate view.
+                // "myButton" is the child view that should receive motion
+                // events.
+                TouchDelegate touchDelegate = new TouchDelegate(delegateArea, 
+                        myButton);
+     
+                // Sets the TouchDelegate on the parent view, such that touches 
+                // within the touch delegate bounds are routed to the child.
+                if (View.class.isInstance(myButton.getParent())) {
+                    ((View) myButton.getParent()).setTouchDelegate(touchDelegate);
+                }
+            }
+        });
+    }
+}</pre>
+
diff --git a/docs/html/training/keyboard-input/commands.jd b/docs/html/training/keyboard-input/commands.jd
new file mode 100644
index 0000000..9d2de41
--- /dev/null
+++ b/docs/html/training/keyboard-input/commands.jd
@@ -0,0 +1,113 @@
+page.title=Handling Keyboard Actions
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#SingleKey">Handle Single Key Events</a></li>
+  <li><a href="#ModifierKey">Handle Modifier Keys</a></li>
+</ol>
+
+</div>
+</div>
+
+
+<p>When the user gives focus to an editable text view such as an {@link android.widget.EditText}
+element and the user has a hardware keyboard attached, all
+input is handled by the system. If, however, you'd like to intercept
+or directly handle the keyboard input yourself, you can do so by implementing callback methods
+from the {@link android.view.KeyEvent.Callback} interface, such as {@link
+android.view.KeyEvent.Callback#onKeyDown onKeyDown()} and {@link
+android.view.KeyEvent.Callback#onKeyMultiple onKeyMultiple()}.</p>
+
+<p>Both the {@link
+android.app.Activity} and {@link android.view.View} class implement the
+{@link android.view.KeyEvent.Callback} interface, so you
+should generally override the callback methods in your extension of these classes as
+appropriate.</p>
+
+<p class="note"><strong>Note:</strong> When handling keyboard events with the {@link
+android.view.KeyEvent} class and related APIs, you should expect that such keyboard
+events come only from a hardware keyboard. You should never rely on receiving key events
+for any key on a soft input method (an on-screen keyboard).</p>
+
+
+<h2 id="SingleKey">Handle Single Key Events</h2>
+
+<p>To handle an individual key press, implement {@link
+android.app.Activity#onKeyDown onKeyDown()} or {@link
+android.app.Activity#onKeyUp onKeyUp()} as appropriate. Usually, you should
+use {@link android.app.Activity#onKeyUp onKeyUp()} if you want to be sure that you receive
+only one event. If the user presses and holds the button, then {@link
+android.app.Activity#onKeyDown onKeyDown()} is called multiple times.</p>
+
+<p>For example, this implementation responds to some keyboard keys to control a game:</p>
+
+<pre>
+&#64;Override
+public boolean onKeyUp(int keyCode, KeyEvent event) {
+    switch (keyCode) {
+        case KeyEvent.KEYCODE_D:
+            moveShip(MOVE_LEFT);
+            return true;
+        case KeyEvent.KEYCODE_F:
+            moveShip(MOVE_RIGHT);
+            return true;
+        case KeyEvent.KEYCODE_J:
+            fireMachineGun();
+            return true;
+        case KeyEvent.KEYCODE_K:
+            fireMissile();
+            return true;
+        default:
+            return super.onKeyUp(keyCode, event);
+    }
+}
+</pre>
+
+
+<h2 id="ModifierKey">Handle Modifier Keys</h2>
+
+<p>To respond to modifier key events such as when a key is combined with Shift or Control, you can
+query the {@link android.view.KeyEvent} that's passed to the callback method. Several methods
+provide information about modifier keys such as {@link android.view.KeyEvent#getModifiers()}
+and {@link android.view.KeyEvent#getMetaState()}. However, the simplest solution is to check whether
+the exact modifier key you care about is being pressed with methods such as
+{@link android.view.KeyEvent#isShiftPressed()} and {@link android.view.KeyEvent#isCtrlPressed()}.
+</p>
+
+<p>For example, here's the {@link android.app.Activity#onKeyDown onKeyDown()} implementation
+again, with some extra handling for when the Shift key is held down with one of the keys:</p>
+
+<pre>
+&#64;Override
+public boolean onKeyUp(int keyCode, KeyEvent event) {
+    switch (keyCode) {
+        ...
+        case KeyEvent.KEYCODE_J:
+            if (event.isShiftPressed()) {
+                fireLaser();
+            } else {
+                fireMachineGun();
+            }
+            return true;
+        case KeyEvent.KEYCODE_K:
+            if (event.isShiftPressed()) {
+                fireSeekingMissle();
+            } else {
+                fireMissile();
+            }
+            return true;
+        default:
+            return super.onKeyUp(keyCode, event);
+    }
+}
+</pre>
+
+
+
diff --git a/docs/html/training/keyboard-input/index.jd b/docs/html/training/keyboard-input/index.jd
new file mode 100644
index 0000000..ba4e598
--- /dev/null
+++ b/docs/html/training/keyboard-input/index.jd
@@ -0,0 +1,54 @@
+page.title=Handling Keyboard Input
+
+trainingnavtop=true
+startpage=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
+<h2>Dependencies and prerequisites</h2>
+<ul>
+  <li>Android 1.6 (API Level 3) or higher</li>
+</ul>
+
+</div>
+</div>
+
+<p>The Android system shows an on-screen keyboard&mdash;known as a
+<em>soft input method</em>&mdash;when a text field in your UI receives focus.
+To provide the best user experience, you can specify characteristics
+about the type of input you expect (such as
+whether it's a phone number or email address) and how the input method should behave (such as
+whether it performs auto-correct for spelling mistakes).</p>
+
+<p>In addition to the on-screen input methods, Android also supports hardware keyboards, so it's
+important that your app optimize its user experience for interaction that might occur
+through an attached keyboard.</p>
+
+<p>These topics and more are discussed in the following lessons.</p>
+
+
+<h2>Lessons</h2> 
+ 
+<dl> 
+  <dt><b><a href="style.html">Specifying the Input Method Type</a></b></dt>
+    <dd>Learn how to show certain soft input methods, such as those designed for phone numbers, web
+    addresses, or other formats. Also learn how to specify characteristics such
+    as spelling suggestion behavior and action buttons such as <b>Done</b> or <b>Next</b>.
+    </dd>
+  <dt><b><a href="visibility.html">Handling Input Method Visibility</a></b></dt>
+    <dd>Learn how to specify when to show the soft input method and how
+    your layout should adjust to the reduced screen space.
+    </dd>
+  <dt><b><a href="navigation.html">Supporting Keyboard Navigation</a></b></dt>
+    <dd>Learn how to verify that users can navigate your app using a keyboard
+    and how to make any necessary changes to the navigation order.
+    </dd>
+  <dt><b><a href="commands.html">Handling Keyboard Actions</a></b></dt>
+    <dd>Learn how to respond directly to keyboard input for user actions.
+    </dd>
+ 
+</dl> 
\ No newline at end of file
diff --git a/docs/html/training/keyboard-input/navigation.jd b/docs/html/training/keyboard-input/navigation.jd
new file mode 100644
index 0000000..6e26ab2
--- /dev/null
+++ b/docs/html/training/keyboard-input/navigation.jd
Binary files differ
diff --git a/docs/html/training/keyboard-input/style.jd b/docs/html/training/keyboard-input/style.jd
new file mode 100644
index 0000000..b0e506c
--- /dev/null
+++ b/docs/html/training/keyboard-input/style.jd
@@ -0,0 +1,171 @@
+page.title=Specifying the Input Method Type
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#Type">Specify the Keyboard Type</a></li>
+  <li><a href="#Spelling">Enable Spelling Suggestions and Other Behaviors</a></li>
+  <li><a href="#Action">Specify the Input Method Action</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/ui/controls/text.html">Text Fields</a></li>
+</ul>
+
+</div>
+</div>
+
+
+<p>Every text field expects a certain type of text input, such as an
+email address, phone number, or just plain text. So it's important
+that you specify the input type for each text field in your app
+so the system displays the appropriate soft input method (such as an on-screen keyboard).</p>
+
+<p>Beyond the type of buttons available with an input method, you should specify
+behaviors such as whether the input method provides spelling suggestions,
+capitalizes new sentences, and replaces the carriage return button with an
+action button such as a <b>Done</b> or <b>Next</b>.
+This lesson shows how to specify these characteristics.</p>
+
+
+
+<h2 id="Type">Specify the Keyboard Type</h2>
+
+<p>You should always declare the input method for your text fields by adding
+the <a href="{@docRoot}reference/android/widget/TextView.html#attr_android:inputType"
+>{@code android:inputType}</a> attribute to the {@link android.widget.EditText
+&lt;EditText&gt;} element.</p>
+
+<div class="figure" style="width:300px">
+<img src="{@docRoot}images/ui/edittext-phone.png" alt="" />
+<p class="img-caption"><strong>Figure 1.</strong> The {@code phone} input type.</p>
+</div>
+
+<p>For example, if you'd like an input method for entering a phone number,
+use the {@code "phone"} value:</p>
+<pre>
+&lt;EditText
+    android:id="@+id/phone"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:hint="@string/phone_hint"
+    android:inputType="phone" />
+</pre>
+
+<div class="figure" style="width:300px">
+<img src="{@docRoot}images/training/input/ime_password.png" alt="" />
+<p class="img-caption"><strong>Figure 2.</strong> The {@code textPassword} input type.</p>
+</div>
+
+<p>Or if the text field is for a password, use the {@code "textPassword"} value
+so the text field conceals the user's input:</p>
+<pre>
+&lt;EditText
+    android:id="@+id/password"
+    android:hint="@string/password_hint"
+    android:inputType="textPassword"
+    ... />    
+</pre>
+
+<p>There are several possible values documented with the
+<a href="{@docRoot}reference/android/widget/TextView.html#attr_android:inputType"
+>{@code android:inputType}</a> attribute and
+some of the values can be combined to specify the input method
+appearance and additional behaviors.</p>
+
+
+
+<h2 id="Spelling">Enable Spelling Suggestions and Other Behaviors</h2>
+
+<div class="figure" style="width:300px">
+<img src="{@docRoot}images/training/input/ime_autocorrect.png" alt="" />
+<p class="img-caption"><strong>Figure 3.</strong> Adding {@code textAutoCorrect}
+provides auto-correction for misspellings.</p>
+</div>
+
+<p>The <a href="{@docRoot}reference/android/widget/TextView.html#attr_android:inputType"
+>{@code android:inputType}</a> attribute allows you to specify various behaviors for the
+input method. Most importantly, if your text field is intended for basic text input (such
+as for a text message), you should enable auto spelling correction with the
+{@code "textAutoCorrect"} value.</p>
+
+<p>You can combine different behaviors and input method styles with the
+<a href="{@docRoot}reference/android/widget/TextView.html#attr_android:inputType"
+>{@code android:inputType}</a> attribute. For example,
+here's how to create a text field that capitalizes the first word of a sentence
+and also auto-corrects misspellings:</p>
+
+<pre>
+&lt;EditText
+    android:id="@+id/message"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:inputType=
+        "textCapSentences|textAutoCorrect"
+    ... />
+</pre>
+
+
+
+
+<h2 id="Action">Specify the Input Method Action</h2>
+
+<p>Most soft input methods provide a user action button in the
+bottom corner that's appropriate for the current text field.
+By default, the system uses this button for either a <b>Next</b> or
+<b>Done</b> action unless your text field allows multi-line text (such as with {@code
+android:inputType="textMultiLine"}), in which case the action button is a carriage return.
+However, you can specify additional actions that might be more appropriate for your
+text field, such as <b>Send</b> or <b>Go</b>.</p>
+
+<p>To specify the keyboard action button, use the <a
+href="{@docRoot}reference/android/widget/TextView.html#attr_android:imeOptions">{@code
+android:imeOptions}</a> attribute with an action value such as {@code "actionSend"} or
+{@code "actionSearch"}. For example:</p>
+
+<div class="figure" style="width:300px">
+<img src="{@docRoot}images/ui/edittext-actionsend.png" alt="" />
+<p class="img-caption"><strong>Figure 4.</strong> The Send button appears when you declare
+{@code android:imeOptions="actionSend"}.</p>
+</div>
+
+<pre>
+&lt;EditText
+    android:id="@+id/search"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:hint="@string/search_hint"
+    android:inputType="text"
+    android:imeOptions="actionSend" />
+</pre>
+
+<p>You can then listen for presses on the action button by defining a
+{@link android.widget.TextView.OnEditorActionListener} for the {@link android.widget.EditText}
+element. In your listener, respond to the appropriate IME action ID defined in the
+{@link android.view.inputmethod.EditorInfo} class, such as
+{@link android.view.inputmethod.EditorInfo#IME_ACTION_SEND}. For example:</p>
+
+<pre>
+EditText editText = (EditText) findViewById(R.id.search);
+editText.setOnEditorActionListener(new OnEditorActionListener() {
+    &#64;Override
+    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+        boolean handled = false;
+        if (actionId == EditorInfo.IME_ACTION_SEND) {
+            sendMessage();
+            handled = true;
+        }
+        return handled;
+    }
+});
+</pre>
+
+
+
diff --git a/docs/html/training/keyboard-input/visibility.jd b/docs/html/training/keyboard-input/visibility.jd
new file mode 100644
index 0000000..5dc6fc260
--- /dev/null
+++ b/docs/html/training/keyboard-input/visibility.jd
Binary files differ
diff --git a/docs/html/training/multiple-threads/communicate-ui.jd b/docs/html/training/multiple-threads/communicate-ui.jd
new file mode 100644
index 0000000..d9977d3
--- /dev/null
+++ b/docs/html/training/multiple-threads/communicate-ui.jd
@@ -0,0 +1,263 @@
+page.title=Communicating with the UI Thread
+
+trainingnavtop=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#Handler">Define a Handler on the UI Thread</a></li>
+  <li><a href="#MoveValues">Move Data from a Task to the UI Thread</a>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a></li>
+</ul>
+
+
+<h2>Try it out</h2>
+<div class="download-box">
+    <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a>
+    <p class="filename">ThreadSample.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+    In the previous lesson you learned how to start a task on a thread managed by
+    {@link java.util.concurrent.ThreadPoolExecutor}. This final lesson shows you how to send data
+    from the task to objects running on the user interface (UI) thread. This feature allows your
+    tasks to do background work and then move the results to UI elements such as bitmaps.
+</p>
+<p>
+    Every app has its own special thread that runs UI objects such as {@link android.view.View}
+    objects; this thread is called the UI thread. Only objects running on the UI thread have access
+    to other objects on that thread. Because tasks that you run on a thread from a thread pool
+    <em>aren't</em> running on your UI thread, they don't have access to UI objects. To move data
+    from a background thread to the UI thread, use a {@link android.os.Handler} that's
+    running on the UI thread.
+</p>
+<h2 id="Handler">Define a Handler on the UI Thread</h2>
+<p>
+    {@link android.os.Handler} is part of the Android system's framework for managing threads. A
+    {@link android.os.Handler} object receives messages and runs code to handle the messages.
+    Normally, you create a {@link android.os.Handler} for a new thread, but you can
+    also create a {@link android.os.Handler} that's connected to an existing thread.
+    When you connect a {@link android.os.Handler} to your UI thread, the code that handles messages
+    runs on the UI thread.
+</p>
+<p>
+    Instantiate the {@link android.os.Handler} object in the constructor for the class that
+    creates your thread pools, and store the object in a global variable. Connect it to the UI
+    thread by instantiating it with the {@link android.os.Handler#Handler(Looper) Handler(Looper)}
+    constructor. This constructor uses a {@link android.os.Looper} object, which is another part of
+    the Android system's thread management framework. When you instantiate a
+    {@link android.os.Handler} based on a particular {@link android.os.Looper} instance, the
+    {@link android.os.Handler} runs on the same thread as the {@link android.os.Looper}.
+    For example:
+</p>
+<pre>
+private PhotoManager() {
+...
+    // Defines a Handler object that's attached to the UI thread
+    mHandler = new Handler(Looper.getMainLooper()) {
+    ...
+</pre>
+<p>
+    Inside the {@link android.os.Handler}, override the {@link android.os.Handler#handleMessage
+    handleMessage()} method. The Android system invokes this method when it receives a new message
+    for a thread it's managing; all of the {@link android.os.Handler} objects for a particular
+    thread receive the same message. For example:
+</p>
+<pre>
+        /*
+         * handleMessage() defines the operations to perform when
+         * the Handler receives a new Message to process.
+         */
+        &#64;Override
+        public void handleMessage(Message inputMessage) {
+            // Gets the image task from the incoming Message object.
+            PhotoTask photoTask = (PhotoTask) inputMessage.obj;
+            ...
+        }
+    ...
+    }
+}
+The next section shows how to tell the {@link android.os.Handler} to move data.
+</pre>
+<h2 id="MoveValues">Move Data from a Task to the UI Thread</h2>
+<p>
+    To move data from a task object running on a background thread to an object on the UI thread,
+    start by storing references to the data and the UI object in the task object. Next, pass the
+    task object and a status code to the object that instantiated the {@link android.os.Handler}.
+    In this object, send a {@link android.os.Message} containing the status and the task object to
+    the {@link android.os.Handler}. Because {@link android.os.Handler} is running on the UI thread,
+    it can move the data to the UI object.
+
+<h3>Store data in the task object</h3>
+<p>
+    For example, here's a {@link java.lang.Runnable}, running on a background thread, that decodes a
+    {@link android.graphics.Bitmap} and stores it in its parent object <code>PhotoTask</code>.
+    The {@link java.lang.Runnable} also stores the status code <code>DECODE_STATE_COMPLETED</code>.
+</p>
+<pre>
+// A class that decodes photo files into Bitmaps
+class PhotoDecodeRunnable implements Runnable {
+    ...
+    PhotoDecodeRunnable(PhotoTask downloadTask) {
+        mPhotoTask = downloadTask;
+    }
+    ...
+    // Gets the downloaded byte array
+    byte[] imageBuffer = mPhotoTask.getByteBuffer();
+    ...
+    // Runs the code for this task
+    public void run() {
+        ...
+        // Tries to decode the image buffer
+        returnBitmap = BitmapFactory.decodeByteArray(
+                imageBuffer,
+                0,
+                imageBuffer.length,
+                bitmapOptions
+        );
+        ...
+        // Sets the ImageView Bitmap
+        mPhotoTask.setImage(returnBitmap);
+        // Reports a status of "completed"
+        mPhotoTask.handleDecodeState(DECODE_STATE_COMPLETED);
+        ...
+    }
+    ...
+}
+...
+</pre>
+<p>
+    <code>PhotoTask</code> also contains a handle to the {@link android.widget.ImageView} that
+    displays the {@link android.graphics.Bitmap}. Even though references to
+    the {@link android.graphics.Bitmap} and {@link android.widget.ImageView} are in the same object,
+    you can't assign the {@link android.graphics.Bitmap} to the {@link android.widget.ImageView},
+    because you're not currently running on the UI thread.
+</p>
+<p>
+    Instead, the next step is to send this status to the <code>PhotoTask</code> object.
+</p>
+<h3>Send status up the object hierarchy</h3>
+<p>
+    <code>PhotoTask</code> is the next higher object in the hierarchy. It maintains references to
+    the decoded data and the {@link android.view.View} object that will show the data. It receives
+    a status code from <code>PhotoDecodeRunnable</code> and passes it along to the object that
+    maintains thread pools and instantiates {@link android.os.Handler}:
+</p>
+<pre>
+public class PhotoTask {
+    ...
+    // Gets a handle to the object that creates the thread pools
+    sPhotoManager = PhotoManager.getInstance();
+    ...
+    public void handleDecodeState(int state) {
+        int outState;
+        // Converts the decode state to the overall state.
+        switch(state) {
+            case PhotoDecodeRunnable.DECODE_STATE_COMPLETED:
+                outState = PhotoManager.TASK_COMPLETE;
+                break;
+            ...
+        }
+        ...
+        // Calls the generalized state method
+        handleState(outState);
+    }
+    ...
+    // Passes the state to PhotoManager
+    void handleState(int state) {
+        /*
+         * Passes a handle to this task and the
+         * current state to the class that created
+         * the thread pools
+         */
+        sPhotoManager.handleState(this, state);
+    }
+    ...
+}
+</pre>
+<h3>Move data to the UI</h3>
+<p>
+    From the <code>PhotoTask</code> object, the <code>PhotoManager</code> object receives a status
+    code and a handle to the <code>PhotoTask</code> object. Because the status is
+    <code>TASK_COMPLETE</code>, creates a {@link android.os.Message} containing the state and task
+    object and sends it to the {@link android.os.Handler}:
+</p>
+<pre>
+public class PhotoManager {
+    ...
+    // Handle status messages from tasks
+    public void handleState(PhotoTask photoTask, int state) {
+        switch (state) {
+            ...
+            // The task finished downloading and decoding the image
+            case TASK_COMPLETE:
+                /*
+                 * Creates a message for the Handler
+                 * with the state and the task object
+                 */
+                Message completeMessage =
+                        mHandler.obtainMessage(state, photoTask);
+                completeMessage.sendToTarget();
+                break;
+            ...
+        }
+        ...
+    }
+</pre>
+<p>
+    Finally, {@link android.os.Handler#handleMessage Handler.handleMessage()} checks the status
+    code for each incoming {@link android.os.Message}. If the status code is
+    <code>TASK_COMPLETE</code>, then the task is finished, and the <code>PhotoTask</code> object
+    in the {@link android.os.Message} contains both a {@link android.graphics.Bitmap} and an
+    {@link android.widget.ImageView}. Because
+    {@link android.os.Handler#handleMessage Handler.handleMessage()} is
+    running on the UI thread, it can safely move the {@link android.graphics.Bitmap} to the
+    {@link android.widget.ImageView}:
+</p>
+<pre>
+    private PhotoManager() {
+        ...
+            mHandler = new Handler(Looper.getMainLooper()) {
+                &#64;Override
+                public void handleMessage(Message inputMessage) {
+                    // Gets the task from the incoming Message object.
+                    PhotoTask photoTask = (PhotoTask) inputMessage.obj;
+                    // Gets the ImageView for this task
+                    PhotoView localView = photoTask.getPhotoView();
+                    ...
+                    switch (inputMessage.what) {
+                        ...
+                        // The decoding is done
+                        case TASK_COMPLETE:
+                            /*
+                             * Moves the Bitmap from the task
+                             * to the View
+                             */
+                            localView.setImageBitmap(photoTask.getImage());
+                            break;
+                        ...
+                        default:
+                            /*
+                             * Pass along other messages from the UI
+                             */
+                            super.handleMessage(inputMessage);
+                    }
+                    ...
+                }
+                ...
+            }
+            ...
+    }
+...
+}
+</pre>
diff --git a/docs/html/training/multiple-threads/create-threadpool.jd b/docs/html/training/multiple-threads/create-threadpool.jd
new file mode 100644
index 0000000..4a4ddb1
--- /dev/null
+++ b/docs/html/training/multiple-threads/create-threadpool.jd
@@ -0,0 +1,238 @@
+page.title=Creating a Manager for Multiple Threads
+
+trainingnavtop=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#ClassStructure">Define the Thread Pool Class</a>
+  <li><a href="#PoolParameters">Determine the Thread Pool Parameters</a></li>
+  <li><a href="#ThreadPool">Create a Pool of Threads</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a></li>
+</ul>
+
+<h2>Try it out</h2>
+<div class="download-box">
+    <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a>
+    <p class="filename">ThreadSample.zip</p>
+</div>
+
+
+</div>
+</div>
+
+<p>
+    The previous lesson showed how to define a task that executes on a
+    separate thread. If you only want to run the task once, this may be all you need. If you want
+    to run a task repeatedly on different sets of data, but you only need one execution running at a
+    time, an {@link android.app.IntentService} suits your needs. To automatically run tasks
+    as resources become available, or to allow multiple tasks to run at the same time (or both),
+    you need to provide a managed collection of threads. To do this, use an instance of
+    {@link java.util.concurrent.ThreadPoolExecutor}, which runs a task from a queue when a thread
+    in its pool becomes free. To run a task, all you have to do is add it to the queue.
+</p>
+<p>
+    A thread pool can run multiple parallel instances of a task, so you should ensure that your
+    code is thread-safe. Enclose variables that can be accessed by more than one thread in a
+    <code>synchronized</code> block. This approach will prevent one thread from reading the variable
+    while another is writing to it. Typically, this situation arises with static variables, but it
+    also occurs in any object that is only instantiated once. To learn more about this, read the
+    <a href="{@docRoot}http://developer.android.com/guide/components/processes-and-threads.html">
+    Processes and Threads</a> API guide.
+    
+</p>
+<h2 id="ClassStructure">Define the Thread Pool Class</h2>
+<p>
+    Instantiate {@link java.util.concurrent.ThreadPoolExecutor} in its own class. Within this class,
+    do the following:
+</p>
+<dl>
+    <dt>
+        Use static variables for thread pools
+    </dt>
+    <dd>
+        You may only want a single instance of a thread pool for your app, in order to have a
+        single control point for restricted CPU or network resources. If you have different
+        {@link java.lang.Runnable} types, you may want to have a thread pool for each one, but each
+        of these can be a single instance. For example, you can add this as part of your
+        global field declarations:
+<pre>
+public class PhotoManager {
+    ...
+    static  {
+        ...
+        // Creates a single static instance of PhotoManager
+        sInstance = new PhotoManager();
+    }
+    ...
+</pre>
+    </dd>
+    <dt>
+        Use a private constructor
+    </dt>
+    <dd>
+        Making the constructor private ensures that it is a singleton, which means that you don't
+        have to enclose accesses to the class in a <code>synchronized</code> block:
+<pre>
+public class PhotoManager {
+    ...
+    /**
+     * Constructs the work queues and thread pools used to download
+     * and decode images. Because the constructor is marked private,
+     * it's unavailable to other classes, even in the same package.
+     */
+    private PhotoManager() {
+    ...
+    }
+</pre>
+    </dd>
+    <dt>
+        Start your tasks by calling methods in the thread pool class.
+    </dt>
+    <dd>
+        Define a method in the thread pool class that adds a task to a thread pool's queue. For
+        example:
+<pre>
+public class PhotoManager {
+    ...
+    // Called by the PhotoView to get a photo
+    static public PhotoTask startDownload(
+        PhotoView imageView,
+        boolean cacheFlag) {
+        ...
+        // Adds a download task to the thread pool for execution
+        sInstance.
+                mDownloadThreadPool.
+                execute(downloadTask.getHTTPDownloadRunnable());
+        ...
+    }
+</pre>
+    </dd>
+    <dt>
+        Instantiate a {@link android.os.Handler} in the constructor and attach it to your app's
+        UI thread.
+    </dt>
+    <dd>
+        A {@link android.os.Handler} allows your app to safely call the methods of UI objects
+        such as {@link android.view.View} objects. Most UI objects may only be safely altered from
+        the UI thread. This approach is described in more detail in the lesson
+        <a href="communicate-ui.html">Communicate with the UI Thread</a>. For example:
+<pre>
+    private PhotoManager() {
+    ...
+        // Defines a Handler object that's attached to the UI thread
+        mHandler = new Handler(Looper.getMainLooper()) {
+            /*
+             * handleMessage() defines the operations to perform when
+             * the Handler receives a new Message to process.
+             */
+            &#64;Override
+            public void handleMessage(Message inputMessage) {
+                ...
+            }
+        ...
+        }
+    }
+</pre>
+    </dd>
+</dl>
+<h2 id="PoolParameters">Determine the Thread Pool Parameters</h2>
+<p>
+    Once you have the overall class structure, you can start defining the thread pool. To
+    instantiate a {@link java.util.concurrent.ThreadPoolExecutor} object, you need the
+    following values:
+</p>
+<dl>
+    <dt>
+        Initial pool size and maximum pool size
+    </dt>
+    <dd>
+        The initial number of threads to allocate to the pool, and the maximum allowable number.
+        The number of threads you can have in a thread pool depends primarily on the number of cores
+        available for your device. This number is available from the system environment:
+<pre>
+public class PhotoManager {
+...
+    /*
+     * Gets the number of available cores
+     * (not always the same as the maximum number of cores)
+     */
+    private static int NUMBER_OF_CORES =
+            Runtime.getRuntime().availableProcessors();
+}
+</pre>
+        This number may not reflect the number of physical cores in the device; some devices have
+        CPUs that deactivate one or more cores depending on the system load. For these devices,
+        {@link java.lang.Runtime#availableProcessors availableProcessors()} returns the number of
+        <i>active</i> cores, which may be less than the total number of cores.
+    </dd>
+    <dt>
+        Keep alive time and time unit
+    </dt>
+    <dd>
+        The duration that a thread will remain idle before it shuts down. The duration is
+        interpreted by the time unit value, one of the constants defined in
+        {@link java.util.concurrent.TimeUnit}.
+    </dd>
+    <dt>
+        A queue of tasks
+    </dt>
+    <dd>
+        The incoming queue from which {@link java.util.concurrent.ThreadPoolExecutor} takes
+        {@link java.lang.Runnable} objects. To start code on a thread, a thread pool manager takes a
+        {@link java.lang.Runnable} object from a first-in, first-out queue and attaches it to the
+        thread. You provide this queue object when you create the thread pool, using any queue class
+        that implements the {@link java.util.concurrent.BlockingQueue} interface. To match the
+        requirements of your app, you can choose from the available queue implementations; to learn
+        more about them, see the class overview for {@link java.util.concurrent.ThreadPoolExecutor}.
+        This example uses the {@link java.util.concurrent.LinkedBlockingQueue} class:
+<pre>
+public class PhotoManager {
+    ...
+    private PhotoManager() {
+        ...
+        // A queue of Runnables
+        private final BlockingQueue&lt;Runnable&gt; mDecodeWorkQueue;
+        ...
+        // Instantiates the queue of Runnables as a LinkedBlockingQueue
+        mDecodeWorkQueue = new LinkedBlockingQueue&lt;Runnable&gt;();
+        ...
+    }
+    ...
+}
+</pre>
+    </dd>
+</dl>
+<h2 id="ThreadPool">Create a Pool of Threads</h2>
+<p>
+    To create a pool of threads, instantiate a thread pool manager by calling
+    {@link java.util.concurrent.ThreadPoolExecutor#ThreadPoolExecutor ThreadPoolExecutor()}.
+    This creates and manages a constrained group of threads. Because the initial pool size and
+    the maximum pool size are the same, {@link java.util.concurrent.ThreadPoolExecutor} creates
+    all of the thread objects when it is instantiated. For example:
+</p>
+<pre>
+    private PhotoManager() {
+        ...
+        // Sets the amount of time an idle thread waits before terminating
+        private static final int KEEP_ALIVE_TIME = 1;
+        // Sets the Time Unit to seconds
+        private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
+        // Creates a thread pool manager
+        mDecodeThreadPool = new ThreadPoolExecutor(
+                NUMBER_OF_CORES,       // Initial pool size
+                NUMBER_OF_CORES,       // Max pool size
+                KEEP_ALIVE_TIME,
+                KEEP_ALIVE_TIME_UNIT,
+                mDecodeWorkQueue);
+    }
+</pre>
diff --git a/docs/html/training/multiple-threads/define-runnable.jd b/docs/html/training/multiple-threads/define-runnable.jd
new file mode 100644
index 0000000..17640a9
--- /dev/null
+++ b/docs/html/training/multiple-threads/define-runnable.jd
@@ -0,0 +1,110 @@
+page.title=Specifying the Code to Run on a Thread
+
+trainingnavtop=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#ExtendClass">Define a Class that Implements Runnable</a></li>
+  <li><a href="#RunMethod">Implement the run() Method</a>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a></li>
+</ul>
+
+
+<h2>Try it out</h2>
+<div class="download-box">
+    <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a>
+    <p class="filename">ThreadSample.zip</p>
+</div>
+</div>
+
+</div>
+</div>
+
+<p>
+    This lesson shows you how to implement a {@link java.lang.Runnable} class, which runs the code
+    in its {@link java.lang.Runnable#run Runnable.run()} method on a separate thread. You can also
+    pass a {@link java.lang.Runnable} to another object that can then attach it to a thread and
+    run it. One or more {@link java.lang.Runnable} objects that perform a particular operation are
+    sometimes called a <i>task</i>.
+</p>
+<p>
+    {@link java.lang.Thread} and {@link java.lang.Runnable} are basic classes that, on their own,
+    have only limited power. Instead, they're the basis of powerful Android classes such as
+    {@link android.os.HandlerThread}, {@link android.os.AsyncTask}, and
+    {@link android.app.IntentService}. {@link java.lang.Thread} and {@link java.lang.Runnable} are
+    also the basis of the class {@link java.util.concurrent.ThreadPoolExecutor}. This class
+    automatically manages threads and task queues, and can even run multiple threads in parallel.
+</p>
+<h2 id="ExtendClass">Define a Class that Implements Runnable</h2>
+<p>
+    Implementing a class that implements {@link java.lang.Runnable} is straightforward. For example:
+</p>
+<pre>
+public class PhotoDecodeRunnable implements Runnable {
+    ...
+    &#64;Override
+    public void run() {
+        /*
+         * Code you want to run on the thread goes here
+         */
+        ...
+    }
+    ...
+}
+</pre>
+<h2 id="RunMethod">Implement the run() Method</h2>
+<p>
+    In the class, the {@link java.lang.Runnable#run Runnable.run()} method contains the
+    code that's executed. Usually, anything is allowable in a {@link java.lang.Runnable}. Remember,
+    though, that the {@link java.lang.Runnable} won't be running on the UI thread, so it can't
+    directly modify UI objects such as {@link android.view.View} objects. To communicate with
+    the UI thread, you have to use the techniques described in the lesson
+    <a href="communicate-ui.html">Communicate with the UI Thread</a>.
+</p>
+<p>
+    At the beginning of the {@link java.lang.Runnable#run run()} method, set the thread to use
+    background priority by calling
+    {@link android.os.Process#setThreadPriority Process.setThreadPriority()} with
+    {@link android.os.Process#THREAD_PRIORITY_BACKGROUND}. This approach reduces
+    resource competition between the {@link java.lang.Runnable} object's thread and the UI
+    thread.
+</p>
+<p>
+    You should also store a reference to the {@link java.lang.Runnable} object's
+    {@link java.lang.Thread} in the {@link java.lang.Runnable} itself, by calling
+    {@link java.lang.Thread#currentThread() Thread.currentThread()}.
+</p>
+<p>
+    The following snippet shows how to set up the {@link java.lang.Runnable#run run()} method:
+</p>
+<pre>
+class PhotoDecodeRunnable implements Runnable {
+...
+    /*
+     * Defines the code to run for this task.
+     */
+    &#64;Override
+    public void run() {
+        // Moves the current Thread into the background
+        android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
+        ...
+        /*
+         * Stores the current Thread in the the PhotoTask instance,
+         * so that the instance
+         * can interrupt the Thread.
+         */
+        mPhotoTask.setImageDecodeThread(Thread.currentThread());
+        ...
+    }
+...
+}
+</pre>
diff --git a/docs/html/training/multiple-threads/index.jd b/docs/html/training/multiple-threads/index.jd
new file mode 100644
index 0000000..3ea57c5
--- /dev/null
+++ b/docs/html/training/multiple-threads/index.jd
@@ -0,0 +1,83 @@
+page.title=Sending Operations to Multiple Threads
+
+trainingnavtop=true
+startpage=true
+
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
+<h2>Dependencies and prerequisites</h2>
+<ul>
+    <li>Android 3.0 (API Level 11) or higher</li>
+    <li>
+        <a href="{@docRoot}training/load-data-background/index.html">
+        Loading Data in the Background</a> training class
+    </li>
+    <li>
+        <a href="{@docRoot}training/run-background-service/index.html">
+        Running in a Background Service</a> training class
+    </li>
+</ul>
+
+<!-- related docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a></li>
+</ul>
+
+<h2>Try it out</h2>
+<div class="download-box">
+    <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a>
+    <p class="filename">ThreadSample.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+    The speed and efficiency of a long-running, data-intensive operation often improves when you
+    split it into smaller operations running on multiple threads. On a device that has a CPU with
+    multiple processors (cores), the system can run the threads in parallel, rather than making each
+    sub-operation wait for a chance to run. For example, decoding multiple image files in order to
+    display them on a thumbnail screen runs substantially faster when you do each decode on a
+    separate thread.
+</p>
+<p>
+    This class shows you how to set up and use multiple threads in an Android app, using a
+    thread pool object. You'll also learn how to define code to run on a thread and how to
+    communicate between one of these threads and the UI thread.
+</p>
+<h2>Lessons</h2>
+<dl>
+    <dt>
+        <b><a href="define-runnable.html">Specifying the Code to Run on a Thread</a></b>
+    </dt>
+    <dd>
+        Learn how to write code to run on a separate {@link java.lang.Thread}, by
+        defining a class that implements the {@link java.lang.Runnable} interface.
+    </dd>
+    <dt>
+        <b><a href="create-threadpool.html">Creating a Manager for Multiple Threads</a></b>
+    </dt>
+    <dd>
+        Learn how to create an object that manages a pool of {@link java.lang.Thread} objects and
+        a queue of {@link java.lang.Runnable} objects. This object is called a
+        {@link java.util.concurrent.ThreadPoolExecutor}.
+    </dd>
+    <dt>
+        <b><a href="run-code.html">Running Code on a Thread Pool Thread</a></b>
+    </dt>
+    <dd>
+        Learn how to run a {@link java.lang.Runnable} on a thread from the thread pool.
+    </dd>
+    <dt>
+        <b><a href="communicate-ui.html">Communicating with the UI Thread</a></b>
+    </dt>
+    <dd>
+        Learn how to communicate from a thread in the thread pool to the UI thread.
+    </dd>
+</dl>
+
diff --git a/docs/html/training/multiple-threads/run-code.jd b/docs/html/training/multiple-threads/run-code.jd
new file mode 100644
index 0000000..a828828
--- /dev/null
+++ b/docs/html/training/multiple-threads/run-code.jd
@@ -0,0 +1,148 @@
+page.title=Running Code on a Thread Pool Thread
+
+trainingnavtop=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#RunRunnable">Run a Runnable on a Thread in the Thread Pool</a></li>
+  <li><a href="#StopThread">Interrupt Running Code</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a></li>
+</ul>
+
+
+<h2>Try it out</h2>
+<div class="download-box">
+    <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a>
+    <p class="filename">ThreadSample.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>
+    The previous lesson showed you how to define a class that manages thread pools and the tasks
+    that run on them. This lesson shows you how to run a task on a thread pool. To do this,
+    you add the task to the pool's work queue. When a thread becomes available, the
+    {@link java.util.concurrent.ThreadPoolExecutor} takes a task from the queue and runs it on the
+    thread.
+</p>
+<p>
+    This lesson also shows you how to stop a task that's running. You might want to do this if a
+    task starts, but then discovers that its work isn't necessary. Rather than wasting processor
+    time, you can cancel the thread the task is running on. For example, if you are downloading
+    images from the network and using a cache, you probably want to stop a task if it detects that
+    an image is already present in the cache. Depending on how you write your app, you may not be
+    able to detect this before you start the download.
+</p>
+<h2 id="RunRunnable">Run a Task on a Thread in the Thread Pool</h2>
+<p>
+    To start a task object on a thread in a particular thread pool, pass the
+    {@link java.lang.Runnable} to {@link java.util.concurrent.ThreadPoolExecutor#execute
+    ThreadPoolExecutor.execute()}. This call adds the task to the thread pool's work queue. When an
+    idle thread becomes available, the manager takes the task that has been waiting the longest and
+    runs it on the thread:
+</p>
+<pre>
+public class PhotoManager {
+    public void handleState(PhotoTask photoTask, int state) {
+        switch (state) {
+            // The task finished downloading the image
+            case DOWNLOAD_COMPLETE:
+            // Decodes the image
+                mDecodeThreadPool.execute(
+                        photoTask.getPhotoDecodeRunnable());
+            ...
+        }
+        ...
+    }
+    ...
+}
+</pre>
+<p>
+    When {@link java.util.concurrent.ThreadPoolExecutor} starts a {@link java.lang.Runnable} on a
+    thread, it automatically calls the object's {@link java.lang.Runnable#run run()} method.
+</p>
+<h2 id="StopThread">Interrupt Running Code</h2>
+<p>
+    To stop a task, you need to interrupt the task's thread. To prepare to do this, you need to
+    store a handle to the task's thread when you create the task. For example:
+</p>
+<pre>
+class PhotoDecodeRunnable implements Runnable {
+    // Defines the code to run for this task
+    public void run() {
+        /*
+         * Stores the current Thread in the
+         * object that contains PhotoDecodeRunnable
+         */
+        mPhotoTask.setImageDecodeThread(Thread.currentThread());
+        ...
+    }
+    ...
+}
+</pre>
+<p>
+    To interrupt a thread, call {@link java.lang.Thread#interrupt Thread.interrupt()}. Notice that
+    {@link java.lang.Thread} objects are controlled by the system, which can modify them outside of
+    your app's process. For this reason, you need to lock access on a thread before you
+    interrupt it, by placing the access in a <code>synchronized</code> block. For example:
+</p>
+<pre>
+public class PhotoManager {
+    public static void cancelAll() {
+        /*
+         * Creates an array of Runnables that's the same size as the
+         * thread pool work queue
+         */
+        Runnable[] runnableArray = new Runnable[mDecodeWorkQueue.size()];
+        // Populates the array with the Runnables in the queue
+        mDecodeWorkQueue.toArray(runnableArray);
+        // Stores the array length in order to iterate over the array
+        int len = runnableArray.length;
+        /*
+         * Iterates over the array of Runnables and interrupts each one's Thread.
+         */
+        synchronized (sInstance) {
+            // Iterates over the array of tasks
+            for (int runnableIndex = 0; runnableIndex &lt; len; runnableIndex++) {
+                // Gets the current thread
+                Thread thread = runnableArray[taskArrayIndex].mThread;
+                // if the Thread exists, post an interrupt to it
+                if (null != thread) {
+                    thread.interrupt();
+                }
+            }
+        }
+    }
+    ...
+}
+</pre>
+<p>
+    In most cases, {@link java.lang.Thread#interrupt Thread.interrupt()} stops the thread
+    immediately. However, it only stops threads that are waiting, and will not interrupt CPU or
+    network-intensive tasks. To avoid slowing down or locking up the system, you should test for
+    any pending interrupt requests before attempting an operation :
+</p>
+<pre>
+/*
+ * Before continuing, checks to see that the Thread hasn't
+ * been interrupted
+ */
+if (Thread.interrupted()) {
+    return;
+}
+...
+// Decodes a byte array into a Bitmap (CPU-intensive)
+BitmapFactory.decodeByteArray(
+        imageBuffer, 0, imageBuffer.length, bitmapOptions);
+...
+</pre>
diff --git a/docs/html/training/multiple-threads/threadsample.zip b/docs/html/training/multiple-threads/threadsample.zip
new file mode 100644
index 0000000..bdc3ccf
--- /dev/null
+++ b/docs/html/training/multiple-threads/threadsample.zip
Binary files differ
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index c4e0f84..9518046 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -194,6 +194,8 @@
     </ul>
   </li><!-- end getting started -->
   
+  
+  
 
   <li class="nav-section">
     <div class="nav-section-header">
@@ -799,7 +801,81 @@
   </li>
   <!-- End best UX and UI -->
   
+
+  <li class="nav-section">
+    <div class="nav-section-header">
+      <a href="<?cs var:toroot ?>training/best-user-input.html">
+      <span class="small">Best Practices for</span><br/>
+              User Input
+      </a>
+    </div>
+    <ul>
+         
+      <li class="nav-section">
+        <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>training/gestures/index.html"
+             description=
+             "How to write apps that allow users to interact with the touch screen via touch gestures."
+            >Using Touch Gestures</a>
+        </div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/gestures/detector.html">
+            Detecting Common Gestures
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/gestures/movement.html">
+            Tracking Movement
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/gestures/scroll.html">
+            Animating a Scroll Gesture
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/gestures/multi.html">
+            Handling Multi-Touch Gestures
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/gestures/scale.html">
+            Dragging and Scaling
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/gestures/viewgroup.html">
+            Managing Touch Events in a ViewGroup
+          </a>
+          </li>
+        </ul>
+      </li>
       
+      <li class="nav-section">
+        <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>training/keyboard-input/index.html"
+             description=
+             "How to specify the appearance and behaviors of soft input methods (such
+             as on-screen keyboards) and how to optimize the experience with
+             hardware keyboards."
+            >Handling Keyboard Input</a>
+        </div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/keyboard-input/style.html">
+            Specifying the Input Method Type
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/keyboard-input/visibility.html">
+            Handling Input Method Visibility
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/keyboard-input/navigation.html">
+            Supporting Keyboard Navigation
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/keyboard-input/commands.html">
+            Handling Keyboard Actions
+          </a>
+          </li>
+        </ul>
+      </li>
+    </ul>
+  </li> <!-- end of User Input -->    
 
   <li class="nav-section">
     <div class="nav-section-header">
@@ -925,6 +1001,33 @@
           </li>
         </ul>
       </li>
+      <li class="nav-section">
+        <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>training/multiple-threads/index.html"
+             description=
+             "How to improve the performance and scalability of long-running operations by
+              dispatching work to multiple threads.">
+             Sending Operations to Multiple Threads</a>
+        </div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/multiple-threads/define-runnable.html">
+            Specifying the Code to Run on a Thread
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/multiple-threads/create-threadpool.html">
+            Creating a Manager for Multiple Threads
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/multiple-threads/run-code.html">
+            Running Code on a Thread Pool Thread
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/multiple-threads/communicate-ui.html">
+            Communicating with the UI Thread
+          </a>
+          </li>
+        </ul>
+      </li>
       
       <li>
         <a href="<?cs var:toroot ?>training/articles/perf-anr.html"
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index b919ba4..af1a447 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -246,7 +246,7 @@
      * release() frees all the buffers and puts the SurfaceTexture into the
      * 'abandoned' state. Once put in this state the SurfaceTexture can never
      * leave it. When in the 'abandoned' state, all methods of the
-     * ISurfaceTexture interface will fail with the NO_INIT error.
+     * IGraphicBufferProducer interface will fail with the NO_INIT error.
      *
      * Note that while calling this method causes all the buffers to be freed
      * from the perspective of the the SurfaceTexture, if there are additional
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 2ce2f33..5e9872f 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -148,6 +148,19 @@
     public static final int USAGE_IO_OUTPUT = 0x0040;
 
     /**
+     * USAGE_SHARED The allocation's backing store will be inherited
+     * from another object (usually a Bitmap); calling appropriate
+     * copy methods will be significantly faster than if the entire
+     * allocation were copied every time.
+     *
+     * This is set by default for allocations created with
+     * CreateFromBitmap(RenderScript, Bitmap) in API version 18 and
+     * higher.
+     *
+     */
+    public static final int USAGE_SHARED = 0x0080;
+
+    /**
      * Controls mipmap behavior when using the bitmap creation and
      * update functions.
      */
@@ -245,7 +258,8 @@
                        USAGE_GRAPHICS_CONSTANTS |
                        USAGE_GRAPHICS_RENDER_TARGET |
                        USAGE_IO_INPUT |
-                       USAGE_IO_OUTPUT)) != 0) {
+                       USAGE_IO_OUTPUT |
+                       USAGE_SHARED)) != 0) {
             throw new RSIllegalArgumentException("Unknown usage specified.");
         }
 
@@ -1158,7 +1172,7 @@
         // enable optimized bitmap path only with no mipmap and script-only usage
         if (mips == MipmapControl.MIPMAP_NONE &&
             t.getElement().isCompatible(Element.RGBA_8888(rs)) &&
-            usage == USAGE_SCRIPT) {
+            usage == (USAGE_SHARED | USAGE_SCRIPT)) {
             int id = rs.nAllocationCreateBitmapBackedAllocation(t.getID(rs), mips.mID, b, usage);
             if (id == 0) {
                 throw new RSRuntimeException("Load failed.");
@@ -1236,8 +1250,11 @@
     }
 
     /**
-     * Creates a non-mipmapped renderscript allocation to use as a
-     * graphics texture
+     * Creates a RenderScript allocation from a bitmap.
+     *
+     * With target API version 18 or greater, this allocation will be
+     * created with USAGE_SHARED. With target API version 17 or lower,
+     * this allocation will be created with USAGE_GRAPHICS_TEXTURE.
      *
      * @param rs Context to which the allocation will belong.
      * @param b bitmap source for the allocation data
@@ -1246,6 +1263,10 @@
      *
      */
     static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
+        if (rs.getApplicationContext().getApplicationInfo().targetSdkVersion >= 18) {
+            return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
+                                    USAGE_SHARED | USAGE_SCRIPT);
+        }
         return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
                                 USAGE_GRAPHICS_TEXTURE);
     }
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index e0470dc..75c7903 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -42,7 +42,7 @@
 #include <rs.h>
 #include <rsEnv.h>
 #include <gui/Surface.h>
-#include <gui/SurfaceTexture.h>
+#include <gui/GLConsumer.h>
 #include <gui/SurfaceTextureClient.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
 
@@ -242,7 +242,7 @@
     LOG_API("nContextSetSurfaceTexture, con(%p), width(%i), height(%i), surface(%p)", con, width, height, (Surface *)sur);
 
     sp<ANativeWindow> window;
-    sp<SurfaceTexture> st;
+    sp<GLConsumer> st;
     if (sur == 0) {
 
     } else {
@@ -481,9 +481,9 @@
 nAllocationGetSurfaceTextureID2(JNIEnv *_env, jobject _this, RsContext con, jint a, jobject jst)
 {
     LOG_API("nAllocationGetSurfaceTextureID2, con(%p), a(%p)", con, (RsAllocation)a);
-    sp<SurfaceTexture> st = SurfaceTexture_getSurfaceTexture(_env, jst);
+    sp<GLConsumer> st = SurfaceTexture_getSurfaceTexture(_env, jst);
 
-    rsAllocationGetSurfaceTextureID2(con, (RsAllocation)a, st.get(), sizeof(SurfaceTexture *));
+    rsAllocationGetSurfaceTextureID2(con, (RsAllocation)a, st.get(), sizeof(GLConsumer *));
 }
 
 static void
diff --git a/include/android_runtime/android_graphics_SurfaceTexture.h b/include/android_runtime/android_graphics_SurfaceTexture.h
index badf22c..77ccd2a 100644
--- a/include/android_runtime/android_graphics_SurfaceTexture.h
+++ b/include/android_runtime/android_graphics_SurfaceTexture.h
@@ -23,14 +23,14 @@
 
 namespace android {
 
-class SurfaceTexture;
+class GLConsumer;
 
 extern sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(
         JNIEnv* env, jobject thiz);
 extern bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz);
 
-/* Gets the underlying SurfaceTexture from a SurfaceTexture Java object. */
-extern sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz);
+/* Gets the underlying GLConsumer from a SurfaceTexture Java object. */
+extern sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz);
 
 } // namespace android
 
diff --git a/include/android_runtime/android_view_Surface.h b/include/android_runtime/android_view_Surface.h
index df0fe72..b56aff8 100644
--- a/include/android_runtime/android_view_Surface.h
+++ b/include/android_runtime/android_view_Surface.h
@@ -24,7 +24,7 @@
 namespace android {
 
 class Surface;
-class ISurfaceTexture;
+class IGraphicBufferProducer;
 
 /* Gets the underlying ANativeWindow for a Surface. */
 extern sp<ANativeWindow> android_view_Surface_getNativeWindow(
@@ -36,9 +36,9 @@
 /* Gets the underlying Surface from a Surface Java object. */
 extern sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj);
 
-/* Creates a Surface from an ISurfaceTexture. */
+/* Creates a Surface from an IGraphicBufferProducer. */
 extern jobject android_view_Surface_createFromISurfaceTexture(JNIEnv* env,
-        const sp<ISurfaceTexture>& surfaceTexture);
+        const sp<IGraphicBufferProducer>& bufferProducer);
 
 } // namespace android
 
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 653081d..addb4cb 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -4163,7 +4163,7 @@
      * Display in the log the current entries in the audio focus stack
      */
     private void dumpFocusStack(PrintWriter pw) {
-        pw.println("\nAudio Focus stack entries:");
+        pw.println("\nAudio Focus stack entries (last is top of stack):");
         synchronized(mAudioFocusLock) {
             Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
             while(stackIterator.hasNext()) {
@@ -4204,6 +4204,8 @@
         } else {
             // focus is abandoned by a client that's not at the top of the stack,
             // no need to update focus.
+            // (using an iterator on the stack so we can safely remove an entry after having
+            //  evaluated it, traversal order doesn't matter here)
             Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
             while(stackIterator.hasNext()) {
                 FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
@@ -4226,6 +4228,8 @@
         // is the owner of the audio focus part of the client to remove?
         boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
                 mFocusStack.peek().mSourceRef.equals(cb);
+        // (using an iterator on the stack so we can safely remove an entry after having
+        //  evaluated it, traversal order doesn't matter here)
         Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
         while(stackIterator.hasNext()) {
             FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
@@ -4846,7 +4850,7 @@
      * Display in the log the current entries in the remote control focus stack
      */
     private void dumpRCStack(PrintWriter pw) {
-        pw.println("\nRemote Control stack entries:");
+        pw.println("\nRemote Control stack entries (last is top of stack):");
         synchronized(mRCStack) {
             Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
             while(stackIterator.hasNext()) {
@@ -4868,7 +4872,7 @@
      * on RemoteControlClient data
      */
     private void dumpRCCStack(PrintWriter pw) {
-        pw.println("\nRemote Control Client stack entries:");
+        pw.println("\nRemote Control Client stack entries (last is top of stack):");
         synchronized(mRCStack) {
             Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
             while(stackIterator.hasNext()) {
@@ -4910,6 +4914,8 @@
                 RemoteControlStackEntry oldTop = mRCStack.peek();
                 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
                 // iterate over the stack entries
+                // (using an iterator on the stack so we can safely remove an entry after having
+                //  evaluated it, traversal order doesn't matter here)
                 while(stackIterator.hasNext()) {
                     RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
                     if (packageName.equalsIgnoreCase(rcse.mReceiverComponent.getPackageName())) {
@@ -5039,6 +5045,8 @@
      * Update the remote control clients with the new "focused" client generation
      */
     private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) {
+        // (using an iterator on the stack so we can safely remove an entry if needed,
+        //  traversal order doesn't matter here as we update all entries)
         Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
         while(stackIterator.hasNext()) {
             RemoteControlStackEntry se = stackIterator.next();
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index ad05fcf..cd50de4 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -159,23 +159,13 @@
      */
     private final Object mPlayStateLock = new Object();
     /**
-     * The listener the AudioTrack notifies when the playback position reaches a marker
-     * or for periodic updates during the progression of the playback head.
-     *  @see #setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener)
-     */
-    private OnPlaybackPositionUpdateListener mPositionListener = null;
-    /**
-     * Lock to protect event listener updates against event notifications.
-     */
-    private final Object mPositionListenerLock = new Object();
-    /**
      * Size of the native audio buffer.
      */
     private int mNativeBufferSizeInBytes = 0;
     /**
      * Handler for marker events coming from the native code.
      */
-    private NativeEventHandlerDelegate mEventHandlerDelegate = null;
+    private NativeEventHandlerDelegate mEventHandlerDelegate;
     /**
      * Looper associated with the thread that creates the AudioTrack instance.
      */
@@ -737,13 +727,11 @@
      */
     public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener,
                                                     Handler handler) {
-        synchronized (mPositionListenerLock) {
-            mPositionListener = listener;
-        }
         if (listener != null) {
-            mEventHandlerDelegate = new NativeEventHandlerDelegate(this, handler);
+            mEventHandlerDelegate = new NativeEventHandlerDelegate(this, listener, handler);
+        } else {
+            mEventHandlerDelegate = null;
         }
-
     }
 
 
@@ -1149,11 +1137,11 @@
      * (potentially) handled in a different thread
      */
     private class NativeEventHandlerDelegate {
-        private final AudioTrack mAudioTrack;
         private final Handler mHandler;
 
-        NativeEventHandlerDelegate(AudioTrack track, Handler handler) {
-            mAudioTrack = track;
+        NativeEventHandlerDelegate(final AudioTrack track,
+                                   final OnPlaybackPositionUpdateListener listener,
+                                   Handler handler) {
             // find the looper for our new event handler
             Looper looper;
             if (handler != null) {
@@ -1169,22 +1157,18 @@
                 mHandler = new Handler(looper) {
                     @Override
                     public void handleMessage(Message msg) {
-                        if (mAudioTrack == null) {
+                        if (track == null) {
                             return;
                         }
-                        OnPlaybackPositionUpdateListener listener = null;
-                        synchronized (mPositionListenerLock) {
-                            listener = mAudioTrack.mPositionListener;
-                        }
                         switch(msg.what) {
                         case NATIVE_EVENT_MARKER:
                             if (listener != null) {
-                                listener.onMarkerReached(mAudioTrack);
+                                listener.onMarkerReached(track);
                             }
                             break;
                         case NATIVE_EVENT_NEW_POS:
                             if (listener != null) {
-                                listener.onPeriodicNotification(mAudioTrack);
+                                listener.onPeriodicNotification(track);
                             }
                             break;
                         default:
@@ -1216,10 +1200,13 @@
             return;
         }
 
-        if (track.mEventHandlerDelegate != null) {
-            Message m =
-                track.mEventHandlerDelegate.getHandler().obtainMessage(what, arg1, arg2, obj);
-            track.mEventHandlerDelegate.getHandler().sendMessage(m);
+        NativeEventHandlerDelegate delegate = track.mEventHandlerDelegate;
+        if (delegate != null) {
+            Handler handler = delegate.getHandler();
+            if (handler != null) {
+                Message m = handler.obtainMessage(what, arg1, arg2, obj);
+                handler.sendMessage(m);
+            }
         }
 
     }
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 48bea52..e0430b4 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -177,12 +177,6 @@
          *  is applied.
          */
         public static final int VOICE_COMMUNICATION = 7;
-
-        /**
-         * @hide
-         * Audio source for remote submix.
-         */
-        public static final int REMOTE_SUBMIX_SOURCE = 8;
     }
 
     /**
@@ -298,10 +292,7 @@
      * @see android.media.MediaRecorder.AudioSource
      */
     public static final int getAudioSourceMax() {
-        // FIXME disable selection of the remote submxi source selection once test code
-        //       doesn't rely on it
-        return AudioSource.REMOTE_SUBMIX_SOURCE;
-        //return AudioSource.VOICE_COMMUNICATION;
+        return AudioSource.VOICE_COMMUNICATION;
     }
 
     /**
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 423a109..fbbcb0a 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -442,6 +442,7 @@
             mMimeType = mimeType;
             mFileType = 0;
             mFileSize = fileSize;
+            mIsDrm = false;
 
             if (!isDirectory) {
                 if (!noMedia && isNoMediaFile(path)) {
@@ -504,7 +505,6 @@
             mLastModified = lastModified;
             mWriter = null;
             mCompilation = 0;
-            mIsDrm = false;
             mWidth = 0;
             mHeight = 0;
 
@@ -1041,6 +1041,7 @@
             }
 
             if (mDrmManagerClient.canHandle(path, null)) {
+                mIsDrm = true;
                 String drmMimetype = mDrmManagerClient.getOriginalMimeType(path);
                 if (drmMimetype != null) {
                     mMimeType = drmMimetype;
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index dab2de1..f8c945b 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -111,12 +111,12 @@
 
 status_t JMediaCodec::configure(
         const sp<AMessage> &format,
-        const sp<ISurfaceTexture> &surfaceTexture,
+        const sp<IGraphicBufferProducer> &bufferProducer,
         const sp<ICrypto> &crypto,
         int flags) {
     sp<SurfaceTextureClient> client;
-    if (surfaceTexture != NULL) {
-        mSurfaceTextureClient = new SurfaceTextureClient(surfaceTexture);
+    if (bufferProducer != NULL) {
+        mSurfaceTextureClient = new SurfaceTextureClient(bufferProducer);
     } else {
         mSurfaceTextureClient.clear();
     }
@@ -237,15 +237,27 @@
 
     *bufArray = (jobjectArray)env->NewObjectArray(
             buffers.size(), byteBufferClass, NULL);
+    if (*bufArray == NULL) {
+        env->DeleteLocalRef(nativeByteOrderObj);
+        return NO_MEMORY;
+    }
 
     for (size_t i = 0; i < buffers.size(); ++i) {
         const sp<ABuffer> &buffer = buffers.itemAt(i);
 
+        // if this is an ABuffer that doesn't actually hold any accessible memory,
+        // use a null ByteBuffer
+        if (buffer->base() == NULL) {
+            continue;
+        }
         jobject byteBuffer =
             env->NewDirectByteBuffer(
                 buffer->base(),
                 buffer->capacity());
-
+        if (byteBuffer == NULL) {
+            env->DeleteLocalRef(nativeByteOrderObj);
+            return NO_MEMORY;
+        }
         jobject me = env->CallObjectMethod(
                 byteBuffer, orderID, nativeByteOrderObj);
         env->DeleteLocalRef(me);
@@ -382,11 +394,11 @@
         return;
     }
 
-    sp<ISurfaceTexture> surfaceTexture;
+    sp<IGraphicBufferProducer> bufferProducer;
     if (jsurface != NULL) {
         sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
         if (surface != NULL) {
-            surfaceTexture = surface->getSurfaceTexture();
+            bufferProducer = surface->getSurfaceTexture();
         } else {
             jniThrowException(
                     env,
@@ -401,7 +413,7 @@
         crypto = JCrypto::GetCrypto(env, jcrypto);
     }
 
-    err = codec->configure(format, surfaceTexture, crypto, flags);
+    err = codec->configure(format, bufferProducer, crypto, flags);
 
     throwExceptionAsNecessary(env, err);
 }
@@ -715,7 +727,10 @@
         return buffers;
     }
 
-    throwExceptionAsNecessary(env, err);
+    // if we're out of memory, an exception was already thrown
+    if (err != NO_MEMORY) {
+        throwExceptionAsNecessary(env, err);
+    }
 
     return NULL;
 }
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index bc9ad50..a9bb9af 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -30,7 +30,7 @@
 struct AMessage;
 struct AString;
 struct ICrypto;
-struct ISurfaceTexture;
+struct IGraphicBufferProducer;
 struct MediaCodec;
 struct SurfaceTextureClient;
 
@@ -43,7 +43,7 @@
 
     status_t configure(
             const sp<AMessage> &format,
-            const sp<ISurfaceTexture> &surfaceTexture,
+            const sp<IGraphicBufferProducer> &bufferProducer,
             const sp<ICrypto> &crypto,
             int flags);
 
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index ad536f2..5408a1f 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -39,7 +39,7 @@
 #include "android_os_Parcel.h"
 #include "android_util_Binder.h"
 #include <binder/Parcel.h>
-#include <gui/ISurfaceTexture.h>
+#include <gui/IGraphicBufferProducer.h>
 #include <gui/Surface.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -236,10 +236,10 @@
     process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
 }
 
-static sp<ISurfaceTexture>
+static sp<IGraphicBufferProducer>
 getVideoSurfaceTexture(JNIEnv* env, jobject thiz) {
-    ISurfaceTexture * const p = (ISurfaceTexture*)env->GetIntField(thiz, fields.surface_texture);
-    return sp<ISurfaceTexture>(p);
+    IGraphicBufferProducer * const p = (IGraphicBufferProducer*)env->GetIntField(thiz, fields.surface_texture);
+    return sp<IGraphicBufferProducer>(p);
 }
 
 static void
@@ -250,7 +250,7 @@
         return;
     }
 
-    sp<ISurfaceTexture> old_st = getVideoSurfaceTexture(env, thiz);
+    sp<IGraphicBufferProducer> old_st = getVideoSurfaceTexture(env, thiz);
     if (old_st != NULL) {
         old_st->decStrong(thiz);
     }
@@ -269,7 +269,7 @@
 
     decVideoSurfaceRef(env, thiz);
 
-    sp<ISurfaceTexture> new_st;
+    sp<IGraphicBufferProducer> new_st;
     if (jsurface) {
         sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
         if (surface != NULL) {
@@ -313,7 +313,7 @@
 
     // Handle the case where the display surface was set before the mp was
     // initialized. We try again to make it stick.
-    sp<ISurfaceTexture> st = getVideoSurfaceTexture(env, thiz);
+    sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
     mp->setVideoSurfaceTexture(st);
 
     process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
@@ -330,7 +330,7 @@
 
     // Handle the case where the display surface was set before the mp was
     // initialized. We try again to make it stick.
-    sp<ISurfaceTexture> st = getVideoSurfaceTexture(env, thiz);
+    sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
     mp->setVideoSurfaceTexture(st);
 
     process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index 3b325b7..bcab4f3 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -705,7 +705,7 @@
 {
     effect_descriptor_t desc;
     char str[EFFECT_STRING_LEN_MAX];
-    uint32_t numEffects;
+    uint32_t numEffects = 0;
     uint32_t i = 0;
     jstring jdescType;
     jstring jdescUuid;
@@ -714,7 +714,10 @@
     jstring jdescImplementor;
     jobject jdesc;
 
-    AudioEffect::queryNumberEffects(&numEffects);
+    if (AudioEffect::queryNumberEffects(&numEffects) != NO_ERROR) {
+        return NULL;
+    }
+
     jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
     if (ret == NULL) {
         return ret;
diff --git a/media/mca/filterfw/jni/jni_gl_environment.cpp b/media/mca/filterfw/jni/jni_gl_environment.cpp
index 3c596a4..b64004e 100644
--- a/media/mca/filterfw/jni/jni_gl_environment.cpp
+++ b/media/mca/filterfw/jni/jni_gl_environment.cpp
@@ -23,7 +23,7 @@
 #include <media/mediarecorder.h>
 #include "native/core/gl_env.h"
 
-#include <gui/ISurfaceTexture.h>
+#include <gui/IGraphicBufferProducer.h>
 #include <gui/SurfaceTextureClient.h>
 #include <utils/Errors.h>
 #include <system/window.h>
@@ -33,7 +33,7 @@
 using android::filterfw::WindowHandle;
 using android::MediaRecorder;
 using android::sp;
-using android::ISurfaceTexture;
+using android::IGraphicBufferProducer;
 using android::SurfaceTextureClient;
 
 
@@ -284,10 +284,10 @@
     // Ask the mediarecorder to return a handle to a surfacemediasource
     // This will talk to the StageFrightRecorder via MediaRecorderClient
     // over binder calls
-    sp<ISurfaceTexture> surfaceMS = mr->querySurfaceMediaSourceFromMediaServer();
+    sp<IGraphicBufferProducer> surfaceMS = mr->querySurfaceMediaSourceFromMediaServer();
     if (surfaceMS == NULL) {
       ALOGE("GLEnvironment: Error- MediaRecorder returned a null \
-              <ISurfaceTexture> handle.");
+              <IGraphicBufferProducer> handle.");
       return -1;
     }
     sp<SurfaceTextureClient> surfaceTC = new SurfaceTextureClient(surfaceMS);
diff --git a/media/mca/filterfw/jni/jni_gl_environment.h b/media/mca/filterfw/jni/jni_gl_environment.h
index af9c744..9dd7102 100644
--- a/media/mca/filterfw/jni/jni_gl_environment.h
+++ b/media/mca/filterfw/jni/jni_gl_environment.h
@@ -68,7 +68,7 @@
 // The call to hook up the SurfaceMediaSource (in MediaServer)  to the GL.
 // We get a sp<ISurfaceTexure> from the MediaServer and talks to MediaServer
 // over a binder interface. GL hooked up to the MediaServer by using the native
-// window created using the <ISurfaceTexture> handle
+// window created using the <IGraphicBufferProducer> handle
 JNIEXPORT jint JNICALL
 Java_android_filterfw_core_GLEnvironment_nativeAddSurfaceFromMediaRecorder(
                                                       JNIEnv* env,
diff --git a/media/mca/filterfw/native/core/gl_env.cpp b/media/mca/filterfw/native/core/gl_env.cpp
index 738b8e0..8ed82e2 100644
--- a/media/mca/filterfw/native/core/gl_env.cpp
+++ b/media/mca/filterfw/native/core/gl_env.cpp
@@ -159,9 +159,9 @@
     return false;
   }
 
-  // Create dummy surface using a SurfaceTexture
-  surfaceTexture_ = new SurfaceTexture(0);
-  window_ = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >(
+  // Create dummy surface using a GLConsumer
+  surfaceTexture_ = new GLConsumer(0);
+  window_ = new SurfaceTextureClient(static_cast<sp<IGraphicBufferProducer> >(
           surfaceTexture_->getBufferQueue()));
 
   surfaces_[0] = SurfaceWindowPair(eglCreateWindowSurface(display(), config, window_.get(), NULL), NULL);
diff --git a/media/mca/filterfw/native/core/gl_env.h b/media/mca/filterfw/native/core/gl_env.h
index b61785f..3c87195 100644
--- a/media/mca/filterfw/native/core/gl_env.h
+++ b/media/mca/filterfw/native/core/gl_env.h
@@ -27,7 +27,7 @@
 #include <GLES2/gl2.h>
 #include <EGL/egl.h>
 
-#include <gui/ISurfaceTexture.h>
+#include <gui/IGraphicBufferProducer.h>
 #include <gui/SurfaceTextureClient.h>
 
 namespace android {
@@ -236,8 +236,8 @@
     // Dummy surface for context
     sp<ANativeWindow> window_;
 
-    // Dummy SurfaceTexture for context
-    sp<SurfaceTexture> surfaceTexture_;
+    // Dummy GLConsumer for context
+    sp<GLConsumer> surfaceTexture_;
 
     // The maximum surface id used.
     int max_surface_id_;
diff --git a/media/tests/players/invoke_mock_media_player.cpp b/media/tests/players/invoke_mock_media_player.cpp
index 1289dfa..a94fedb 100644
--- a/media/tests/players/invoke_mock_media_player.cpp
+++ b/media/tests/players/invoke_mock_media_player.cpp
@@ -26,7 +26,7 @@
 
 using android::INVALID_OPERATION;
 using android::Surface;
-using android::ISurfaceTexture;
+using android::IGraphicBufferProducer;
 using android::MediaPlayerBase;
 using android::OK;
 using android::Parcel;
@@ -69,7 +69,7 @@
 
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length) {return OK;}
     virtual status_t    setVideoSurfaceTexture(
-                                const sp<ISurfaceTexture>& surfaceTexture) {return OK;}
+                                const sp<IGraphicBufferProducer>& bufferProducer) {return OK;}
     virtual status_t    prepare() {return OK;}
     virtual status_t    prepareAsync() {return OK;}
     virtual status_t    start() {return OK;}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 2601bd0..5bf7e21 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -228,7 +228,7 @@
      * manager with lock held.  (This lock will be acquired in places
      * where the window manager is calling in with its own lock held.)
      */
-    final Object mLock = new Object();
+    private final Object mLock = new Object();
 
     Context mContext;
     IWindowManager mWindowManager;
@@ -694,9 +694,8 @@
             // Double the time it takes to take a screenshot from the keyguard
             return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
                     ViewConfiguration.getGlobalActionKeyTimeout());
-        } else {
-            return ViewConfiguration.getGlobalActionKeyTimeout();
         }
+        return ViewConfiguration.getGlobalActionKeyTimeout();
     }
 
     private void cancelPendingScreenshotChordAction() {
@@ -739,6 +738,7 @@
     };
 
     private final Runnable mScreenshotRunnable = new Runnable() {
+        @Override
         public void run() {
             takeScreenshot();
         }
@@ -845,6 +845,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public void init(Context context, IWindowManager windowManager,
             WindowManagerFuncs windowManagerFuncs) {
         mContext = context;
@@ -947,6 +948,7 @@
         }
     }
 
+    @Override
     public void setInitialDisplaySize(Display display, int width, int height, int density) {
         mDisplay = display;
 
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 8c5ff04..4cfe5d5 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1193,8 +1193,11 @@
                         log("startUsingNetworkFeature reconnecting to " + networkType + ": " +
                                 feature);
                     }
-                    network.reconnect();
-                    return PhoneConstants.APN_REQUEST_STARTED;
+                    if (network.reconnect()) {
+                        return PhoneConstants.APN_REQUEST_STARTED;
+                    } else {
+                        return PhoneConstants.APN_REQUEST_FAILED;
+                    }
                 } else {
                     // need to remember this unsupported request so we respond appropriately on stop
                     synchronized(this) {
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 91ac1de..81ae101 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -782,6 +782,9 @@
         if (!isSystemIme(imi)) {
             return false;
         }
+        if (imi.isAuxiliaryIme()) {
+            return false;
+        }
         if (imi.getIsDefaultResourceId() != 0) {
             try {
                 Resources res = context.createPackageContext(
@@ -805,6 +808,9 @@
         if (!isSystemIme(imi)) {
             return false;
         }
+        if (imi.isAuxiliaryIme()) {
+            return false;
+        }
         return containsSubtypeOf(imi, ENGLISH_LOCALE.getLanguage());
     }
 
@@ -2858,6 +2864,9 @@
         List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
                 .getEnabledInputMethodsAndSubtypeListLocked();
 
+        if (DEBUG) {
+            Slog.d(TAG, (enabled ? "Enable " : "Disable ") + id);
+        }
         if (enabled) {
             for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
                 if (pair.first.equals(id)) {
diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java
index 1b9742c..faa72a2 100644
--- a/services/java/com/android/server/NsdService.java
+++ b/services/java/com/android/server/NsdService.java
@@ -389,8 +389,10 @@
                         break;
                     case NsdManager.NATIVE_DAEMON_EVENT:
                         NativeEvent event = (NativeEvent) msg.obj;
-                        handleNativeEvent(event.code, event.raw,
-                                NativeDaemonEvent.unescapeArgs(event.raw));
+                        if (!handleNativeEvent(event.code, event.raw,
+                                NativeDaemonEvent.unescapeArgs(event.raw))) {
+                            result = NOT_HANDLED;
+                        }
                         break;
                     default:
                         result = NOT_HANDLED;
@@ -398,6 +400,127 @@
                 }
                 return result;
             }
+
+            private boolean handleNativeEvent(int code, String raw, String[] cooked) {
+                boolean handled = true;
+                NsdServiceInfo servInfo;
+                int id = Integer.parseInt(cooked[1]);
+                ClientInfo clientInfo = mIdToClientInfoMap.get(id);
+                if (clientInfo == null) {
+                    Slog.e(TAG, "Unique id with no client mapping: " + id);
+                    handled = false;
+                    return handled;
+                }
+
+                /* This goes in response as msg.arg2 */
+                int clientId = -1;
+                int keyId = clientInfo.mClientIds.indexOfValue(id);
+                if (keyId != -1) {
+                    clientId = clientInfo.mClientIds.keyAt(keyId);
+                }
+                switch (code) {
+                    case NativeResponseCode.SERVICE_FOUND:
+                        /* NNN uniqueId serviceName regType domain */
+                        if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
+                        servInfo = new NsdServiceInfo(cooked[2], cooked[3], null);
+                        clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
+                                clientId, servInfo);
+                        break;
+                    case NativeResponseCode.SERVICE_LOST:
+                        /* NNN uniqueId serviceName regType domain */
+                        if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
+                        servInfo = new NsdServiceInfo(cooked[2], cooked[3], null);
+                        clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
+                                clientId, servInfo);
+                        break;
+                    case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
+                        /* NNN uniqueId errorCode */
+                        if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw);
+                        clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
+                                NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+                        break;
+                    case NativeResponseCode.SERVICE_REGISTERED:
+                        /* NNN regId serviceName regType */
+                        if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
+                        servInfo = new NsdServiceInfo(cooked[2], null, null);
+                        clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
+                                id, clientId, servInfo);
+                        break;
+                    case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
+                        /* NNN regId errorCode */
+                        if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw);
+                        clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
+                               NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+                        break;
+                    case NativeResponseCode.SERVICE_UPDATED:
+                        /* NNN regId */
+                        break;
+                    case NativeResponseCode.SERVICE_UPDATE_FAILED:
+                        /* NNN regId errorCode */
+                        break;
+                    case NativeResponseCode.SERVICE_RESOLVED:
+                        /* NNN resolveId fullName hostName port txtlen txtdata */
+                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
+                        int index = cooked[2].indexOf(".");
+                        if (index == -1) {
+                            Slog.e(TAG, "Invalid service found " + raw);
+                            break;
+                        }
+                        String name = cooked[2].substring(0, index);
+                        String rest = cooked[2].substring(index);
+                        String type = rest.replace(".local.", "");
+
+                        clientInfo.mResolvedService.setServiceName(name);
+                        clientInfo.mResolvedService.setServiceType(type);
+                        clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
+
+                        stopResolveService(id);
+                        if (!getAddrInfo(id, cooked[3])) {
+                            clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
+                                    NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+                            removeRequestMap(clientId, id, clientInfo);
+                            clientInfo.mResolvedService = null;
+                        }
+                        break;
+                    case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
+                        /* NNN resolveId errorCode */
+                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
+                        stopResolveService(id);
+                        removeRequestMap(clientId, id, clientInfo);
+                        clientInfo.mResolvedService = null;
+                        clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
+                                NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+                        break;
+                    case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
+                        /* NNN resolveId errorCode */
+                        stopGetAddrInfo(id);
+                        removeRequestMap(clientId, id, clientInfo);
+                        clientInfo.mResolvedService = null;
+                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
+                        clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
+                                NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+                        break;
+                    case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
+                        /* NNN resolveId hostname ttl addr */
+                        if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw);
+                        try {
+                            clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
+                            clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
+                                   0, clientId, clientInfo.mResolvedService);
+                        } catch (java.net.UnknownHostException e) {
+                            clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
+                                    NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+                        }
+                        stopGetAddrInfo(id);
+                        removeRequestMap(clientId, id, clientInfo);
+                        clientInfo.mResolvedService = null;
+                        break;
+                    default:
+                        handled = false;
+                        break;
+                }
+                return handled;
+            }
        }
     }
 
@@ -483,8 +606,8 @@
     }
 
     private class NativeEvent {
-        int code;
-        String raw;
+        final int code;
+        final String raw;
 
         NativeEvent(int code, String raw) {
             this.code = code;
@@ -506,123 +629,6 @@
         }
     }
 
-    private void handleNativeEvent(int code, String raw, String[] cooked) {
-        NsdServiceInfo servInfo;
-        int id = Integer.parseInt(cooked[1]);
-        ClientInfo clientInfo = mIdToClientInfoMap.get(id);
-        if (clientInfo == null) {
-            Slog.e(TAG, "Unique id with no client mapping: " + id);
-            return;
-        }
-
-        /* This goes in response as msg.arg2 */
-        int clientId = -1;
-        int keyId = clientInfo.mClientIds.indexOfValue(id);
-        if (keyId != -1) {
-            clientId = clientInfo.mClientIds.keyAt(keyId);
-        }
-        switch (code) {
-            case NativeResponseCode.SERVICE_FOUND:
-                /* NNN uniqueId serviceName regType domain */
-                if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
-                servInfo = new NsdServiceInfo(cooked[2], cooked[3], null);
-                clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
-                        clientId, servInfo);
-                break;
-            case NativeResponseCode.SERVICE_LOST:
-                /* NNN uniqueId serviceName regType domain */
-                if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
-                servInfo = new NsdServiceInfo(cooked[2], cooked[3], null);
-                clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
-                        clientId, servInfo);
-                break;
-            case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
-                /* NNN uniqueId errorCode */
-                if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw);
-                clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
-                        NsdManager.FAILURE_INTERNAL_ERROR, clientId);
-                break;
-            case NativeResponseCode.SERVICE_REGISTERED:
-                /* NNN regId serviceName regType */
-                if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
-                servInfo = new NsdServiceInfo(cooked[2], null, null);
-                clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
-                        id, clientId, servInfo);
-                break;
-            case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
-                /* NNN regId errorCode */
-                if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw);
-                clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
-                        NsdManager.FAILURE_INTERNAL_ERROR, clientId);
-                break;
-            case NativeResponseCode.SERVICE_UPDATED:
-                /* NNN regId */
-                break;
-            case NativeResponseCode.SERVICE_UPDATE_FAILED:
-                /* NNN regId errorCode */
-                break;
-            case NativeResponseCode.SERVICE_RESOLVED:
-                /* NNN resolveId fullName hostName port txtlen txtdata */
-                if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
-                int index = cooked[2].indexOf(".");
-                if (index == -1) {
-                    Slog.e(TAG, "Invalid service found " + raw);
-                    break;
-                }
-                String name = cooked[2].substring(0, index);
-                String rest = cooked[2].substring(index);
-                String type = rest.replace(".local.", "");
-
-                clientInfo.mResolvedService.setServiceName(name);
-                clientInfo.mResolvedService.setServiceType(type);
-                clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
-
-                stopResolveService(id);
-                if (!getAddrInfo(id, cooked[3])) {
-                    clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
-                            NsdManager.FAILURE_INTERNAL_ERROR, clientId);
-                    mIdToClientInfoMap.remove(id);
-                    clientInfo.mResolvedService = null;
-                }
-                break;
-            case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
-                /* NNN resolveId errorCode */
-                if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
-                stopResolveService(id);
-                mIdToClientInfoMap.remove(id);
-                clientInfo.mResolvedService = null;
-                clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
-                        NsdManager.FAILURE_INTERNAL_ERROR, clientId);
-                break;
-            case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
-                /* NNN resolveId errorCode */
-                stopGetAddrInfo(id);
-                mIdToClientInfoMap.remove(id);
-                clientInfo.mResolvedService = null;
-                if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
-                clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
-                        NsdManager.FAILURE_INTERNAL_ERROR, clientId);
-                break;
-            case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
-                /* NNN resolveId hostname ttl addr */
-                if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw);
-                try {
-                    clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
-                    clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
-                            0, clientId, clientInfo.mResolvedService);
-                } catch (java.net.UnknownHostException e) {
-                    clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
-                            NsdManager.FAILURE_INTERNAL_ERROR, clientId);
-                }
-                stopGetAddrInfo(id);
-                mIdToClientInfoMap.remove(id);
-                clientInfo.mResolvedService = null;
-                break;
-            default:
-                break;
-        }
-    }
-
     private boolean startMDnsDaemon() {
         if (DBG) Slog.d(TAG, "startMDnsDaemon");
         try {
@@ -801,8 +807,8 @@
     private class ClientInfo {
 
         private static final int MAX_LIMIT = 10;
-        private AsyncChannel mChannel;
-        private Messenger mMessenger;
+        private final AsyncChannel mChannel;
+        private final Messenger mMessenger;
         /* Remembers a resolved service until getaddrinfo completes */
         private NsdServiceInfo mResolvedService;
 
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index b007bc8..0e01e4c 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -45,6 +45,7 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -280,6 +281,13 @@
      */
     boolean mDismissKeyguardOnNextActivity = false;
 
+    /**
+     * Save the most recent screenshot for reuse. This keeps Recents from taking two identical
+     * screenshots, one for the Recents thumbnail and one for the pauseActivity thumbnail.
+     */
+    private ActivityRecord mLastScreenshotActivity = null;
+    private Bitmap mLastScreenshotBitmap = null;
+
     int mThumbnailWidth = -1;
     int mThumbnailHeight = -1;
 
@@ -931,8 +939,16 @@
         }
 
         if (w > 0) {
-            return mService.mWindowManager.screenshotApplications(who.appToken,
-                    Display.DEFAULT_DISPLAY, w, h);
+            if (who != mLastScreenshotActivity || mLastScreenshotBitmap == null
+                    || mLastScreenshotBitmap.getWidth() != w
+                    || mLastScreenshotBitmap.getHeight() != h) {
+                mLastScreenshotActivity = who;
+                mLastScreenshotBitmap = mService.mWindowManager.screenshotApplications(
+                        who.appToken, Display.DEFAULT_DISPLAY, w, h);
+            }
+            if (mLastScreenshotBitmap != null) {
+                return mLastScreenshotBitmap.copy(Config.ARGB_8888, true);
+            }
         }
         return null;
     }
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index e09970e..813c9c7 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -118,6 +118,9 @@
 
     // The synchronization root for the display manager.
     // This lock guards most of the display manager's state.
+    // NOTE: This is synchronized on while holding WindowManagerService.mWindowMap so never call
+    // into WindowManagerService methods that require mWindowMap while holding this unless you are
+    // very very sure that no deadlock can occur.
     private final SyncRoot mSyncRoot = new SyncRoot();
 
     // True if in safe mode.
@@ -158,7 +161,7 @@
             new CopyOnWriteArrayList<DisplayTransactionListener>();
 
     // Set to true if all displays have been blanked by the power manager.
-    private int mAllDisplayBlankStateFromPowerManager;
+    private int mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNKNOWN;
 
     // Set to true when there are pending display changes that have yet to be applied
     // to the surface flinger state.
@@ -541,9 +544,8 @@
             synchronized (mSyncRoot) {
                 if (mWifiDisplayAdapter != null) {
                     return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
-                } else {
-                    return new WifiDisplayStatus();
                 }
+                return new WifiDisplayStatus();
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -812,11 +814,9 @@
             Slog.w(TAG, "Missing logical display to use for physical display device: "
                     + device.getDisplayDeviceInfoLocked());
             return;
-        } else {
-            boolean isBlanked = (mAllDisplayBlankStateFromPowerManager
-                    == DISPLAY_BLANK_STATE_BLANKED);
-            display.configureDisplayInTransactionLocked(device, isBlanked);
         }
+        boolean isBlanked = (mAllDisplayBlankStateFromPowerManager == DISPLAY_BLANK_STATE_BLANKED);
+        display.configureDisplayInTransactionLocked(device, isBlanked);
 
         // Update the viewports if needed.
         DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index b09390c..cbd2a0f 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -52,7 +52,6 @@
 import static android.net.NetworkTemplate.MATCH_WIFI;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
 import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.net.wifi.WifiInfo.removeDoubleQuotes;
 import static android.net.wifi.WifiManager.CHANGE_REASON_ADDED;
 import static android.net.wifi.WifiManager.CHANGE_REASON_REMOVED;
 import static android.net.wifi.WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION;
@@ -551,8 +550,7 @@
                 final WifiConfiguration config = intent.getParcelableExtra(
                         EXTRA_WIFI_CONFIGURATION);
                 if (config.SSID != null) {
-                    final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(
-                            removeDoubleQuotes(config.SSID));
+                    final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(config.SSID);
                     synchronized (mRulesLock) {
                         if (mNetworkPolicy.containsKey(template)) {
                             mNetworkPolicy.remove(template);
@@ -581,8 +579,7 @@
             final WifiInfo info = intent.getParcelableExtra(EXTRA_WIFI_INFO);
             final boolean meteredHint = info.getMeteredHint();
 
-            final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(
-                    removeDoubleQuotes(info.getSSID()));
+            final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(info.getSSID());
             synchronized (mRulesLock) {
                 NetworkPolicy policy = mNetworkPolicy.get(template);
                 if (policy == null && meteredHint) {
diff --git a/services/java/com/android/server/search/SearchManagerService.java b/services/java/com/android/server/search/SearchManagerService.java
index 132ae79..b5d81d1 100644
--- a/services/java/com/android/server/search/SearchManagerService.java
+++ b/services/java/com/android/server/search/SearchManagerService.java
@@ -240,28 +240,8 @@
     @Override
     public ComponentName getAssistIntent(int userHandle) {
         try {
-            if (userHandle != UserHandle.getCallingUserId()) {
-                // Requesting a different user, make sure that they have the permission
-                if (ActivityManager.checkComponentPermission(
-                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                        Binder.getCallingUid(), -1, true)
-                        == PackageManager.PERMISSION_GRANTED) {
-                    // Translate to the current user id, if caller wasn't aware
-                    if (userHandle == UserHandle.USER_CURRENT) {
-                        long identity = Binder.clearCallingIdentity();
-                        userHandle = ActivityManagerNative.getDefault().getCurrentUser().id;
-                        Binder.restoreCallingIdentity(identity);
-                    }
-                } else {
-                    String msg = "Permission Denial: "
-                            + "Request to getAssistIntent for " + userHandle
-                            + " but is calling from user " + UserHandle.getCallingUserId()
-                            + "; this requires "
-                            + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-                    Slog.w(TAG, msg);
-                    return null;
-                }
-            }
+            userHandle = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                    Binder.getCallingUid(), userHandle, true, false, "getAssistIntent", null);
             IPackageManager pm = AppGlobals.getPackageManager();
             Intent assistIntent = new Intent(Intent.ACTION_ASSIST);
             ResolveInfo info =
diff --git a/services/java/com/android/server/wm/AppTransition.java b/services/java/com/android/server/wm/AppTransition.java
index 92fd68b..7736c93 100644
--- a/services/java/com/android/server/wm/AppTransition.java
+++ b/services/java/com/android/server/wm/AppTransition.java
@@ -30,7 +30,6 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationSet;
 import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.view.animation.ScaleAnimation;
 
@@ -50,9 +49,14 @@
 // made visible or hidden at the next transition.
 public class AppTransition implements Dump {
     private static final String TAG = "AppTransition";
-    private static final float THUMBNAIL_ANIMATION_DECELERATE_FACTOR = 1.5f;
-    private static final boolean DEBUG_APP_TRANSITIONS = WindowManagerService.DEBUG_APP_TRANSITIONS;
-    private static final boolean DEBUG_ANIM = WindowManagerService.DEBUG_APP_TRANSITIONS;
+    private static final boolean DEBUG_APP_TRANSITIONS =
+            WindowManagerService.DEBUG_APP_TRANSITIONS;
+    private static final boolean DEBUG_ANIM = WindowManagerService.DEBUG_ANIM;
+
+    /** Fraction of animation at which the recents thumbnail becomes completely transparent */
+    static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.25f;
+
+    static final long DEFAULT_APP_TRANSITION_DURATION = 250;
 
     final Context mContext;
     final Handler mH;
@@ -75,15 +79,26 @@
     boolean mAppTransitionTimeout = false;
 
     final int mConfigShortAnimTime;
-    final Interpolator mInterpolator;
+    private final Interpolator mDecelerateInterpolator;
+    private final Interpolator mThumbnailFadeoutInterpolator;
 
     AppTransition(Context context, Handler h) {
         mContext = context;
         mH = h;
         mConfigShortAnimTime = context.getResources().getInteger(
                 com.android.internal.R.integer.config_shortAnimTime);
-        mInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.decelerate_quad);
+        mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.decelerate_cubic);
+        mThumbnailFadeoutInterpolator = new Interpolator() {
+            @Override
+            public float getInterpolation(float input) {
+                // Linear response for first fraction, then complete after that.
+                if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {
+                    return input / RECENTS_THUMBNAIL_FADEOUT_FRACTION;
+                }
+                return 1.0f;
+            }
+        };
     }
 
     boolean isTransitionSet() {
@@ -99,7 +114,7 @@
     }
 
     int getAppTransition() {
-        return mNextAppTransition; 
+        return mNextAppTransition;
      }
 
     void setAppTransition(int transit) {
@@ -229,24 +244,6 @@
         return null;
     }
 
-    private Animation createExitAnimationLocked(int transit, int duration) {
-        if (transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN ||
-                transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE) {
-            // If we are on top of the wallpaper, we need an animation that
-            // correctly handles the wallpaper staying static behind all of
-            // the animated elements.  To do this, will just have the existing
-            // element fade out.
-            Animation a = new AlphaAnimation(1, 0);
-            a.setDetachWallpaper(true);
-            a.setDuration(duration);
-            return a;
-        }
-        // For normal animations, the exiting element just holds in place.
-        Animation a = new AlphaAnimation(1, 1);
-        a.setDuration(duration);
-        return a;
-    }
-
     /**
      * Compute the pivot point for an animation that is scaling from a small
      * rect on screen to a larger rect.  The pivot point varies depending on
@@ -268,20 +265,6 @@
     private Animation createScaleUpAnimationLocked(int transit, boolean enter,
                                                    int appWidth, int appHeight) {
         Animation a = null;
-        // Pick the desired duration.  If this is an inter-activity transition,
-        // it  is the standard duration for that.  Otherwise we use the longer
-        // task transition duration.
-        int duration;
-        switch (transit) {
-            case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
-            case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
-                duration = mContext.getResources().getInteger(
-                        com.android.internal.R.integer.config_shortAnimTime);
-                break;
-            default:
-                duration = 300;
-                break;
-        }
         if (enter) {
             // Entering app zooms out from the center of the initial rect.
             float scaleW = mNextAppTransitionStartWidth / (float) appWidth;
@@ -289,22 +272,45 @@
             Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
                     computePivot(mNextAppTransitionStartX, scaleW),
                     computePivot(mNextAppTransitionStartY, scaleH));
-            scale.setDuration(duration);
-            AnimationSet set = new AnimationSet(true);
+            scale.setInterpolator(mDecelerateInterpolator);
+
             Animation alpha = new AlphaAnimation(0, 1);
-            scale.setDuration(duration);
+            alpha.setInterpolator(mThumbnailFadeoutInterpolator);
+
+            AnimationSet set = new AnimationSet(false);
             set.addAnimation(scale);
-            alpha.setDuration(duration);
             set.addAnimation(alpha);
             set.setDetachWallpaper(true);
             a = set;
+        } else  if (transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN ||
+                    transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE) {
+            // If we are on top of the wallpaper, we need an animation that
+            // correctly handles the wallpaper staying static behind all of
+            // the animated elements.  To do this, will just have the existing
+            // element fade out.
+            a = new AlphaAnimation(1, 0);
+            a.setDetachWallpaper(true);
         } else {
-            a = createExitAnimationLocked(transit, duration);
+            // For normal animations, the exiting element just holds in place.
+            a = new AlphaAnimation(1, 1);
         }
+
+        // Pick the desired duration.  If this is an inter-activity transition,
+        // it  is the standard duration for that.  Otherwise we use the longer
+        // task transition duration.
+        final long duration;
+        switch (transit) {
+            case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
+            case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
+                duration = mConfigShortAnimTime;
+                break;
+            default:
+                duration = DEFAULT_APP_TRANSITION_DURATION;
+                break;
+        }
+        a.setDuration(duration);
         a.setFillAfter(true);
-        final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext,
-                com.android.internal.R.interpolator.decelerate_cubic);
-        a.setInterpolator(interpolator);
+        a.setInterpolator(mDecelerateInterpolator);
         a.initialize(appWidth, appHeight, appWidth, appHeight);
         return a;
     }
@@ -316,75 +322,43 @@
         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
         final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
-        // Pick the desired duration.  If this is an inter-activity transition,
-        // it  is the standard duration for that.  Otherwise we use the longer
-        // task transition duration.
-        int duration;
-        switch (transit) {
-            case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
-            case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
-                duration = mConfigShortAnimTime;
-                break;
-            default:
-                duration = 250;
-                break;
-        }
         if (thumb) {
             // Animation for zooming thumbnail from its initial size to
             // filling the screen.
             if (mNextAppTransitionScaleUp) {
                 float scaleW = appWidth / thumbWidth;
                 float scaleH = appHeight / thumbHeight;
-
                 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
                         computePivot(mNextAppTransitionStartX, 1 / scaleW),
                         computePivot(mNextAppTransitionStartY, 1 / scaleH));
-                AnimationSet set = new AnimationSet(true);
+                scale.setInterpolator(mDecelerateInterpolator);
+
                 Animation alpha = new AlphaAnimation(1, 0);
-                scale.setDuration(duration);
-                scale.setInterpolator(
-                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
+                alpha.setInterpolator(mThumbnailFadeoutInterpolator);
+
+                // This AnimationSet uses the Interpolators assigned above.
+                AnimationSet set = new AnimationSet(false);
                 set.addAnimation(scale);
-                alpha.setDuration(duration);
                 set.addAnimation(alpha);
-                set.setFillBefore(true);
                 a = set;
             } else {
                 float scaleW = appWidth / thumbWidth;
                 float scaleH = appHeight / thumbHeight;
-
-                Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
+                a = new ScaleAnimation(scaleW, 1, scaleH, 1,
                         computePivot(mNextAppTransitionStartX, 1 / scaleW),
                         computePivot(mNextAppTransitionStartY, 1 / scaleH));
-                AnimationSet set = new AnimationSet(true);
-                Animation alpha = new AlphaAnimation(1, 1);
-                scale.setDuration(duration);
-                scale.setInterpolator(
-                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
-                set.addAnimation(scale);
-                alpha.setDuration(duration);
-                set.addAnimation(alpha);
-                set.setFillBefore(true);
-
-                a = set;
             }
         } else if (enter) {
             // Entering app zooms out from the center of the thumbnail.
             if (mNextAppTransitionScaleUp) {
                 float scaleW = thumbWidth / appWidth;
                 float scaleH = thumbHeight / appHeight;
-                Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
+                a = new ScaleAnimation(scaleW, 1, scaleH, 1,
                         computePivot(mNextAppTransitionStartX, scaleW),
                         computePivot(mNextAppTransitionStartY, scaleH));
-                scale.setDuration(duration);
-                scale.setInterpolator(
-                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
-                scale.setFillBefore(true);
-                a = scale;
             } else {
                 // noop animation
                 a = new AlphaAnimation(1, 1);
-                a.setDuration(duration);
             }
         } else {
             // Exiting app
@@ -398,31 +372,39 @@
                     // noop animation
                     a = new AlphaAnimation(1, 1);
                 }
-                a.setDuration(duration);
             } else {
                 float scaleW = thumbWidth / appWidth;
                 float scaleH = thumbHeight / appHeight;
                 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
                         computePivot(mNextAppTransitionStartX, scaleW),
                         computePivot(mNextAppTransitionStartY, scaleH));
-                scale.setDuration(duration);
-                scale.setInterpolator(
-                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
-                scale.setFillBefore(true);
-                AnimationSet set = new AnimationSet(true);
+
                 Animation alpha = new AlphaAnimation(1, 0);
+
+                AnimationSet set = new AnimationSet(true);
                 set.addAnimation(scale);
-                alpha.setDuration(duration);
-                alpha.setInterpolator(new DecelerateInterpolator(
-                        THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
                 set.addAnimation(alpha);
-                set.setFillBefore(true);
                 set.setZAdjustment(Animation.ZORDER_TOP);
                 a = set;
             }
         }
+
+        // Pick the desired duration.  If this is an inter-activity transition,
+        // it  is the standard duration for that.  Otherwise we use the longer
+        // task transition duration.
+        final long duration;
+        switch (transit) {
+            case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
+            case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
+                duration = mConfigShortAnimTime;
+                break;
+            default:
+                duration = DEFAULT_APP_TRANSITION_DURATION;
+                break;
+        }
+        a.setDuration(duration);
         a.setFillAfter(true);
-        a.setInterpolator(mInterpolator);
+        a.setInterpolator(mDecelerateInterpolator);
         a.initialize(appWidth, appHeight, appWidth, appHeight);
         return a;
     }
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java
index 34513a1..ad68307 100644
--- a/services/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/java/com/android/server/wm/AppWindowAnimator.java
@@ -58,9 +58,9 @@
     }
 
     public void setAnimation(Animation anim, int width, int height) {
-        if (WindowManagerService.localLOGV) Slog.v(
-            TAG, "Setting animation in " + mAppToken + ": " + anim
-                    + " wxh=" + width + "x" + height);
+        if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting animation in " + mAppToken
+                + ": " + anim + " wxh=" + width + "x" + height
+                + " isVisible=" + mAppToken.isVisible());
         animation = anim;
         animating = false;
         if (!anim.isInitialized()) {
@@ -82,16 +82,17 @@
         }
         // Start out animation gone if window is gone, or visible if window is visible.
         transformation.clear();
-        transformation.setAlpha(mAppToken.reportedVisible ? 1 : 0);
+        transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
         hasTransformation = true;
     }
 
     public void setDummyAnimation() {
-        if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting dummy animation in " + mAppToken);
+        if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting dummy animation in " + mAppToken
+                + " isVisible=" + mAppToken.isVisible());
         animation = sDummyAnimation;
         hasTransformation = true;
         transformation.clear();
-        transformation.setAlpha(mAppToken.reportedVisible ? 1 : 0);
+        transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
     }
 
     public void clearAnimation() {
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 275c9bf..adad09d 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -223,6 +223,22 @@
         return null;
     }
 
+    boolean isVisible() {
+        final int N = allAppWindows.size();
+        // TODO: Consider using allDrawn instead of a single window.
+        for (int i=0; i<N; i++) {
+            WindowState win = allAppWindows.get(i);
+            if (!win.mAppFreezing
+                    && (win.mViewVisibility == View.VISIBLE ||
+                        (win.mWinAnimator.isAnimating() &&
+                                !service.mAppTransition.isTransitionSet()))
+                    && !win.mDestroying && win.isDrawnLw()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     void dump(PrintWriter pw, String prefix) {
         super.dump(pw, prefix);
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index cfcf841..71a61c6 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -267,8 +267,7 @@
     private void setSnapshotTransformInTransaction(Matrix matrix, float alpha) {
         if (mSurface != null) {
             matrix.getValues(mTmpFloats);
-            mSurface.setPosition(mTmpFloats[Matrix.MTRANS_X],
-                    mTmpFloats[Matrix.MTRANS_Y]);
+            mSurface.setPosition(mTmpFloats[Matrix.MTRANS_X], mTmpFloats[Matrix.MTRANS_Y]);
             mSurface.setMatrix(
                     mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
                     mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 1640cac..c67a465 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -476,7 +476,7 @@
     // This is held as long as we have the screen frozen, to give us time to
     // perform a rotation animation when turning off shows the lock screen which
     // changes the orientation.
-    PowerManager.WakeLock mScreenFrozenLock;
+    private PowerManager.WakeLock mScreenFrozenLock;
 
     final AppTransition mAppTransition;
     boolean mStartingIconInTransition = false;
@@ -762,8 +762,7 @@
         mPowerManager = pm;
         mPowerManager.setPolicy(mPolicy);
         PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                "SCREEN_FROZEN");
+        mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN");
         mScreenFrozenLock.setReferenceCounted(false);
 
         mAppTransition = new AppTransition(context, mH);
@@ -2248,8 +2247,6 @@
             // Don't do layout here, the window must call
             // relayout to be displayed, so we'll do it there.
 
-            //dump();
-
             if (focusChanged) {
                 finishUpdateFocusedWindowAfterAssignLayersLocked(false /*updateInputWindows*/);
             }
@@ -2352,9 +2349,7 @@
         removeWindowInnerLocked(session, win);
         // Removing a visible window will effect the computed orientation
         // So just update orientation if needed.
-        if (wasVisible && computeForcedAppOrientationLocked()
-                != mForcedAppOrientation
-                && updateOrientationFromAppTokensLocked(false)) {
+        if (wasVisible && updateOrientationFromAppTokensLocked(false)) {
             mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
         }
         updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
@@ -3461,11 +3456,9 @@
 
         if (updateOrientationFromAppTokensLocked(false)) {
             if (freezeThisOneIfNeeded != null) {
-                AppWindowToken atoken = findAppWindowToken(
-                        freezeThisOneIfNeeded);
+                AppWindowToken atoken = findAppWindowToken(freezeThisOneIfNeeded);
                 if (atoken != null) {
-                    startAppFreezingScreenLocked(atoken,
-                            ActivityInfo.CONFIG_ORIENTATION);
+                    startAppFreezingScreenLocked(atoken, ActivityInfo.CONFIG_ORIENTATION);
                 }
             }
             config = computeNewConfigurationLocked();
@@ -3507,7 +3500,10 @@
     boolean updateOrientationFromAppTokensLocked(boolean inTransaction) {
         long ident = Binder.clearCallingIdentity();
         try {
-            int req = computeForcedAppOrientationLocked();
+            int req = getOrientationFromWindowsLocked();
+            if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
+                req = getOrientationFromAppTokensLocked();
+            }
 
             if (req != mForcedAppOrientation) {
                 mForcedAppOrientation = req;
@@ -3526,14 +3522,6 @@
         }
     }
 
-    int computeForcedAppOrientationLocked() {
-        int req = getOrientationFromWindowsLocked();
-        if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
-            req = getOrientationFromAppTokensLocked();
-        }
-        return req;
-    }
-
     @Override
     public void setNewConfiguration(Configuration config) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -4488,8 +4476,7 @@
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG,
                     "Start moving token " + wtoken + " initially at "
                     + oldIndex);
-            if (oldIndex > index && mAppTransition.isTransitionSet()
-                    && !mAppTransition.isRunning()) {
+            if (oldIndex > index && mAppTransition.isTransitionSet()) {
                 // animation towards back has not started, copy old list for duration of animation.
                 mAnimatingAppTokens.clear();
                 mAnimatingAppTokens.addAll(mAppTokens);
@@ -4503,7 +4490,7 @@
             if (DEBUG_REORDER) Slog.v(TAG, "Moved " + token + " to " + index + ":");
             else if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "Moved " + token + " to " + index);
             if (DEBUG_REORDER) dumpAppTokensLocked();
-            if (!mAppTransition.isTransitionSet() && !mAppTransition.isRunning()) {
+            if (!mAppTransition.isTransitionSet()) {
                 // Not animating, bring animating app list in line with mAppTokens.
                 mAnimatingAppTokens.clear();
                 mAnimatingAppTokens.addAll(mAppTokens);
@@ -4557,40 +4544,6 @@
         }
     }
 
-    private void moveAppWindowsLocked(AppWindowToken wtoken, int tokenPos,
-            boolean updateFocusAndLayout) {
-        // First remove all of the windows from the list.
-        tmpRemoveAppWindowsLocked(wtoken);
-
-        // And now add them back at the correct place.
-        DisplayContentsIterator iterator = new DisplayContentsIterator();
-        while (iterator.hasNext()) {
-            final DisplayContent displayContent = iterator.next();
-            final WindowList windows = displayContent.getWindowList();
-            final int pos = findWindowOffsetLocked(windows, tokenPos);
-            final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken);
-            if (pos != newPos) {
-                displayContent.layoutNeeded = true;
-            }
-
-            if (updateFocusAndLayout && !updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
-                    false /*updateInputWindows*/)) {
-                assignLayersLocked(windows);
-            }
-        }
-
-        if (updateFocusAndLayout) {
-            mInputMonitor.setUpdateInputWindowsNeededLw();
-
-            // Note that the above updateFocusedWindowLocked conditional used to sit here.
-
-            if (!mInLayout) {
-                performLayoutAndPlaceSurfacesLocked();
-            }
-            mInputMonitor.updateInputWindowsLw(false /*force*/);
-        }
-    }
-
     private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) {
         // First remove all of the windows from the list.
         final int N = tokens.size();
@@ -4635,6 +4588,7 @@
         //dump();
     }
 
+    @Override
     public void moveAppTokensToTop(List<IBinder> tokens) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "moveAppTokensToTop()")) {
@@ -4657,11 +4611,9 @@
                 }
             }
 
-            if (!mAppTransition.isRunning()) {
-                mAnimatingAppTokens.clear();
-                mAnimatingAppTokens.addAll(mAppTokens);
-                moveAppWindowsLocked(tokens, mAppTokens.size());
-            }
+            mAnimatingAppTokens.clear();
+            mAnimatingAppTokens.addAll(mAppTokens);
+            moveAppWindowsLocked(tokens, mAppTokens.size());
         }
         Binder.restoreCallingIdentity(origId);
     }
@@ -4676,7 +4628,7 @@
         final long origId = Binder.clearCallingIdentity();
         synchronized(mWindowMap) {
             final int N = tokens.size();
-            if (N > 0 && !mAppTransition.isRunning()) {
+            if (N > 0) {
                 // animating towards back, hang onto old list for duration of animation.
                 mAnimatingAppTokens.clear();
                 mAnimatingAppTokens.addAll(mAppTokens);
@@ -4696,11 +4648,9 @@
                 }
             }
 
-            if (!mAppTransition.isRunning()) {
-                mAnimatingAppTokens.clear();
-                mAnimatingAppTokens.addAll(mAppTokens);
-                moveAppWindowsLocked(tokens, 0);
-            }
+            mAnimatingAppTokens.clear();
+            mAnimatingAppTokens.addAll(mAppTokens);
+            moveAppWindowsLocked(tokens, 0);
         }
         Binder.restoreCallingIdentity(origId);
     }
@@ -4776,12 +4726,14 @@
     /**
      * @see android.app.KeyguardManager#exitKeyguardSecurely
      */
+    @Override
     public void exitKeyguardSecurely(final IOnKeyguardExitResult callback) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
             != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires DISABLE_KEYGUARD permission");
         }
         mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() {
+            @Override
             public void onKeyguardExitResult(boolean success) {
                 try {
                     callback.onKeyguardExitResult(success);
@@ -4792,18 +4744,22 @@
         });
     }
 
+    @Override
     public boolean inKeyguardRestrictedInputMode() {
         return mPolicy.inKeyguardRestrictedKeyInputMode();
     }
 
+    @Override
     public boolean isKeyguardLocked() {
         return mPolicy.isKeyguardLocked();
     }
 
+    @Override
     public boolean isKeyguardSecure() {
         return mPolicy.isKeyguardSecure();
     }
 
+    @Override
     public void dismissKeyguard() {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -4814,6 +4770,7 @@
         }
     }
 
+    @Override
     public void closeSystemDialogs(String reason) {
         synchronized(mWindowMap) {
             final AllWindowsIterator iterator = new AllWindowsIterator();
@@ -4835,6 +4792,7 @@
         return Math.abs(scale);
     }
 
+    @Override
     public void setAnimationScale(int which, float scale) {
         if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
                 "setAnimationScale()")) {
@@ -5568,8 +5526,7 @@
 
         mWindowsFreezingScreen = true;
         mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
-        mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT,
-                WINDOW_FREEZE_TIMEOUT_DURATION);
+        mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
         mWaitingForConfig = true;
         getDefaultDisplayContentLocked().layoutNeeded = true;
         startFreezingDisplayLocked(inTransaction, 0, 0);
@@ -5642,13 +5599,16 @@
         return true;
     }
 
+    @Override
     public int getRotation() {
         return mRotation;
     }
 
+    @Override
     public int watchRotation(IRotationWatcher watcher) {
         final IBinder watcherBinder = watcher.asBinder();
         IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
+            @Override
             public void binderDied() {
                 synchronized (mWindowMap) {
                     for (int i=0; i<mRotationWatchers.size(); i++) {
@@ -7984,7 +7944,6 @@
                 final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
                 appAnimator.clearThumbnail();
-                wtoken.reportedVisible = false;
                 wtoken.inPendingTransaction = false;
                 appAnimator.animation = null;
                 setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
@@ -8380,7 +8339,10 @@
                     if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
                         displayContent.pendingLayoutChanges);
 
-                    if ((adjustWallpaperWindowsLocked() & ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
+                    if ((displayContent.pendingLayoutChanges &
+                            WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
+                            (adjustWallpaperWindowsLocked() &
+                                    ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
                         assignLayersLocked(windows);
                         displayContent.layoutNeeded = true;
                     }
@@ -8902,6 +8864,7 @@
         }
     }
 
+    @Override
     public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
         if (token != null && callback != null) {
             synchronized (mWindowMap) {
@@ -9372,7 +9335,7 @@
         mInputMonitor.thawInputDispatchingLw();
 
         boolean configChanged;
-        
+
         // While the display is frozen we don't re-compute the orientation
         // to avoid inconsistent states.  However, something interesting
         // could have actually changed during that time so re-evaluate it
@@ -9425,9 +9388,10 @@
 
         File file = new File("/system/etc/setup.conf");
         FileInputStream in = null;
+        DataInputStream ind = null;
         try {
             in = new FileInputStream(file);
-            DataInputStream ind = new DataInputStream(in);
+            ind = new DataInputStream(in);
             String line = ind.readLine();
             if (line != null) {
                 String[] toks = line.split("%");
@@ -9439,7 +9403,12 @@
         } catch (FileNotFoundException e) {
         } catch (IOException e) {
         } finally {
-            if (in != null) {
+            if (ind != null) {
+                try {
+                    ind.close();
+                } catch (IOException e) {
+                }
+            } else if (in != null) {
                 try {
                     in.close();
                 } catch (IOException e) {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index e0dad01b..5fd42c2 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -215,36 +215,44 @@
     int mXOffset;
     int mYOffset;
 
-    // This is set after IWindowSession.relayout() has been called at
-    // least once for the window.  It allows us to detect the situation
-    // where we don't yet have a surface, but should have one soon, so
-    // we can give the window focus before waiting for the relayout.
+    /**
+     * This is set after IWindowSession.relayout() has been called at
+     * least once for the window.  It allows us to detect the situation
+     * where we don't yet have a surface, but should have one soon, so
+     * we can give the window focus before waiting for the relayout.
+     */
     boolean mRelayoutCalled;
 
-    // If the application has called relayout() with changes that can
-    // impact its window's size, we need to perform a layout pass on it
-    // even if it is not currently visible for layout.  This is set
-    // when in that case until the layout is done.
+    /**
+     * If the application has called relayout() with changes that can
+     * impact its window's size, we need to perform a layout pass on it
+     * even if it is not currently visible for layout.  This is set
+     * when in that case until the layout is done.
+     */
     boolean mLayoutNeeded;
 
-    // Currently running an exit animation?
+    /** Currently running an exit animation? */
     boolean mExiting;
 
-    // Currently on the mDestroySurface list?
+    /** Currently on the mDestroySurface list? */
     boolean mDestroying;
 
-    // Completely remove from window manager after exit animation?
+    /** Completely remove from window manager after exit animation? */
     boolean mRemoveOnExit;
 
-    // Set when the orientation is changing and this window has not yet
-    // been updated for the new orientation.
+    /**
+     * Set when the orientation is changing and this window has not yet
+     * been updated for the new orientation.
+     */
     boolean mOrientationChanging;
 
-    // Is this window now (or just being) removed?
+    /** Is this window now (or just being) removed? */
     boolean mRemoved;
 
-    // Temp for keeping track of windows that have been removed when
-    // rebuilding window list.
+    /**
+     * Temp for keeping track of windows that have been removed when
+     * rebuilding window list.
+     */
     boolean mRebuilding;
 
     // Input channel and input window handle used by the input dispatcher.
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 9acdd49..5b7cb99 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -1223,7 +1223,7 @@
         if (mIsWallpaper && !mWin.mWallpaperVisible) {
             // Wallpaper is no longer visible and there is no wp target => hide it.
             hide();
-        } else if (w.mAttachedHidden || !w.isReadyForDisplay()) {
+        } else if (w.mAttachedHidden || !w.isOnScreen()) {
             hide();
             mAnimator.hideWallpapersLocked(w);
 
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
index abe2e83..b5df38d 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
@@ -111,15 +111,11 @@
         mRS = RenderScript.create(act);
         mRS.setMessageHandler(new MessageProcessor(act));
         mMessageScript = new ScriptC_msg(mRS);
-        mInPixelsAllocation = Allocation.createFromBitmap(mRS, b,
-                                                          Allocation.MipmapControl.MIPMAP_NONE,
-                                                          Allocation.USAGE_SCRIPT);
-        mInPixelsAllocation2 = Allocation.createFromBitmap(mRS, b2,
-                                                          Allocation.MipmapControl.MIPMAP_NONE,
-                                                          Allocation.USAGE_SCRIPT);
-        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, outb,
-                                                           Allocation.MipmapControl.MIPMAP_NONE,
-                                                           Allocation.USAGE_SCRIPT);
+
+        mInPixelsAllocation = Allocation.createFromBitmap(mRS, b);
+        mInPixelsAllocation2 = Allocation.createFromBitmap(mRS, b2);
+        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, outb);
+
         createTest(act.getResources());
     }