Merge "Added a hovered state for drawables."
diff --git a/api/current.xml b/api/current.xml
index de7d0dd..df2c756 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -31505,6 +31505,25 @@
 <parameter name="exit" type="int">
 </parameter>
 </method>
+<method name="setCustomAnimations"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enter" type="int">
+</parameter>
+<parameter name="exit" type="int">
+</parameter>
+<parameter name="popEnter" type="int">
+</parameter>
+<parameter name="popExit" type="int">
+</parameter>
+</method>
 <method name="setTransition"
  return="android.app.FragmentTransaction"
  abstract="true"
@@ -86741,6 +86760,17 @@
 <parameter name="texName" type="int">
 </parameter>
 </constructor>
+<method name="getTimestamp"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getTransformMatrix"
  return="void"
  abstract="false"
@@ -93397,6 +93427,17 @@
  visibility="public"
 >
 </field>
+<field name="TYPE_AMBIENT_TEMPERATURE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="13"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TYPE_GRAVITY"
  type="int"
  transient="false"
@@ -93503,7 +93544,7 @@
  value="7"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 894e196..93983a6 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -1786,22 +1786,6 @@
         }
     }
 
-    private String getMetaValue(String key) {
-        synchronized (mCacheLock) {
-            final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
-            Cursor c = db.query(TABLE_META,
-                    new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
-            try {
-                if (c.moveToNext()) {
-                    return c.getString(0);
-                }
-                return null;
-            } finally {
-                c.close();
-            }
-        }
-    }
-
     public IBinder onBind(Intent intent) {
         return asBinder();
     }
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 1d217f0..850f56a 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -43,7 +43,7 @@
             if (op.removed != null) numRemoved += op.removed.size();
             op = op.next;
         }
-        mOps = new int[bse.mNumOp*5 + numRemoved];
+        mOps = new int[bse.mNumOp*7 + numRemoved];
 
         if (!bse.mAddToBackStack) {
             throw new IllegalStateException("Not on back stack");
@@ -56,6 +56,8 @@
             mOps[pos++] = op.fragment.mIndex;
             mOps[pos++] = op.enterAnim;
             mOps[pos++] = op.exitAnim;
+            mOps[pos++] = op.popEnterAnim;
+            mOps[pos++] = op.popExitAnim;
             if (op.removed != null) {
                 final int N = op.removed.size();
                 mOps[pos++] = N;
@@ -101,6 +103,8 @@
             op.fragment = f;
             op.enterAnim = mOps[pos++];
             op.exitAnim = mOps[pos++];
+            op.popEnterAnim = mOps[pos++];
+            op.popExitAnim = mOps[pos++];
             final int N = mOps[pos++];
             if (N > 0) {
                 op.removed = new ArrayList<Fragment>(N);
@@ -177,6 +181,8 @@
         Fragment fragment;
         int enterAnim;
         int exitAnim;
+        int popEnterAnim;
+        int popExitAnim;
         ArrayList<Fragment> removed;
     }
 
@@ -185,6 +191,8 @@
     int mNumOp;
     int mEnterAnim;
     int mExitAnim;
+    int mPopEnterAnim;
+    int mPopExitAnim;
     int mTransition;
     int mTransitionStyle;
     boolean mAddToBackStack;
@@ -241,6 +249,11 @@
                     writer.print(prefix); writer.print("enterAnim="); writer.print(op.enterAnim);
                             writer.print(" exitAnim="); writer.println(op.exitAnim);
                 }
+                if (op.popEnterAnim != 0 || op.popExitAnim != 0) {
+                    writer.print(prefix);
+                            writer.print("popEnterAnim="); writer.print(op.popEnterAnim);
+                            writer.print(" popExitAnim="); writer.println(op.popExitAnim);
+                }
                 if (op.removed != null && op.removed.size() > 0) {
                     for (int i=0; i<op.removed.size(); i++) {
                         writer.print(innerPrefix);
@@ -299,6 +312,8 @@
         }
         op.enterAnim = mEnterAnim;
         op.exitAnim = mExitAnim;
+        op.popEnterAnim = mPopEnterAnim;
+        op.popExitAnim = mPopExitAnim;
         mNumOp++;
     }
 
@@ -402,8 +417,15 @@
     }
 
     public FragmentTransaction setCustomAnimations(int enter, int exit) {
+        return setCustomAnimations(enter, exit, 0, 0);
+    }
+
+    public FragmentTransaction setCustomAnimations(int enter, int exit,
+            int popEnter, int popExit) {
         mEnterAnim = enter;
         mExitAnim = exit;
+        mPopEnterAnim = popEnter;
+        mPopExitAnim = popExit;
         return this;
     }
 
@@ -593,6 +615,7 @@
             switch (op.cmd) {
                 case OP_ADD: {
                     Fragment f = op.fragment;
+                    f.mNextAnim = op.popExitAnim;
                     f.mImmediateActivity = null;
                     mManager.removeFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition),
@@ -600,6 +623,7 @@
                 } break;
                 case OP_REPLACE: {
                     Fragment f = op.fragment;
+                    f.mNextAnim = op.popExitAnim;
                     f.mImmediateActivity = null;
                     mManager.removeFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition),
@@ -607,6 +631,7 @@
                     if (op.removed != null) {
                         for (int i=0; i<op.removed.size(); i++) {
                             Fragment old = op.removed.get(i);
+                            old.mNextAnim = op.popEnterAnim;
                             f.mImmediateActivity = mManager.mActivity;
                             mManager.addFragment(old, false);
                         }
@@ -614,16 +639,19 @@
                 } break;
                 case OP_REMOVE: {
                     Fragment f = op.fragment;
+                    f.mNextAnim = op.popEnterAnim;
                     f.mImmediateActivity = mManager.mActivity;
                     mManager.addFragment(f, false);
                 } break;
                 case OP_HIDE: {
                     Fragment f = op.fragment;
+                    f.mNextAnim = op.popEnterAnim;
                     mManager.showFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
                 } break;
                 case OP_SHOW: {
                     Fragment f = op.fragment;
+                    f.mNextAnim = op.popExitAnim;
                     mManager.hideFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
                 } break;
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 0cc774d..68600b3 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -116,10 +116,20 @@
 
     /**
      * Set specific animation resources to run for the fragments that are
-     * entering and exiting in this transaction.
+     * entering and exiting in this transaction. These animations will not be
+     * played when popping the back stack.
      */
     public abstract FragmentTransaction setCustomAnimations(int enter, int exit);
-    
+
+    /**
+     * Set specific animation resources to run for the fragments that are
+     * entering and exiting in this transaction. The <code>popEnter</code>
+     * and <code>popExit</code> animations will be played for enter/exit
+     * operations specifically when popping the back stack.
+     */
+    public abstract FragmentTransaction setCustomAnimations(int enter, int exit,
+            int popEnter, int popExit);
+
     /**
      * Select a standard transition animation for this transaction.  May be
      * one of {@link #TRANSIT_NONE}, {@link #TRANSIT_FRAGMENT_OPEN},
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index fc07478..80bed0d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1442,7 +1442,7 @@
      * {@link Intent#resolveActivity} finds an activity if a class has not
      * been explicitly specified.
      *
-     * <p><em>Note: if using an implicit Intent (without an explicit ComponentName
+     * <p><em>Note:</em> if using an implicit Intent (without an explicit ComponentName
      * specified), be sure to consider whether to set the {@link #MATCH_DEFAULT_ONLY}
      * only flag.  You need to do so to resolve the activity in the same way
      * that {@link android.content.Context#startActivity(Intent)} and
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index ed2b205..e525c95 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -374,6 +374,12 @@
      * The preview surface texture may not otherwise change while preview is
      * running.
      *
+     * The timestamps provided by {@link SurfaceTexture#getTimestamp()} for a
+     * SurfaceTexture set as the preview texture have an unspecified zero point,
+     * and cannot be directly compared between different cameras or different
+     * instances of the same camera, or across multiple runs of the same
+     * program.
+     *
      * @param surfaceTexture the {@link SurfaceTexture} to which the preview
      *     images are to be sent or null to remove the current preview surface
      *     texture
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index f2b907b..a4ba3bd 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -66,7 +66,14 @@
     /** A constant describing a pressure sensor type */
     public static final int TYPE_PRESSURE = 6;
 
-    /** A constant describing a temperature sensor type */
+    /**
+     * A constant describing a temperature sensor type
+     *
+     * @deprecated use
+     *             {@link android.hardware.Sensor#TYPE_AMBIENT_TEMPERATURE
+     *             Sensor.TYPE_AMBIENT_TEMPERATURE} instead.
+     */
+    @Deprecated
     public static final int TYPE_TEMPERATURE = 7;
 
     /**
@@ -97,6 +104,9 @@
      */
     public static final int TYPE_ROTATION_VECTOR = 11;
 
+    /** A constant describing an ambient temperature sensor type */
+    public static final int TYPE_AMBIENT_TEMPERATURE = 13;
+
     /** 
      * A constant describing all sensor types.
      */
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 78d7991..91f0098 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -305,6 +305,14 @@
      * positive in the counter-clockwise direction).
      * </p>
      * 
+     * <h4>{@link android.hardware.Sensor#TYPE_AMBIENT_TEMPERATURE Sensor.TYPE_AMBIENT_TEMPERATURE}:
+     * </h4>
+     *
+     * <ul>
+     * <p>
+     * values[0]: ambient (room) temperature in degree Celsius.
+     * </ul>
+     *
      * @see SensorEvent
      * @see GeomagneticField
      */
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index f8f8a29..3bf64b2 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -17,18 +17,12 @@
 package android.net;
 
 import android.os.SystemProperties;
-import android.util.Config;
 import android.util.Log;
 
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.Socket;
-import java.security.GeneralSecurityException;
 import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 
 import javax.net.SocketFactory;
@@ -40,7 +34,6 @@
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
 import org.apache.harmony.xnet.provider.jsse.OpenSSLContextImpl;
@@ -128,7 +121,7 @@
      *
      * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
      *         for none.  The socket timeout is reset to 0 after the handshake.
-     * @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
+     * @param cache The {@link SSLSessionCache} to use, or null for no cache.
      * @return a new SSLSocketFactory with the specified parameters
      */
     public static SSLSocketFactory getDefault(int handshakeTimeoutMillis, SSLSessionCache cache) {
@@ -144,7 +137,7 @@
      *
      * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
      *         for none.  The socket timeout is reset to 0 after the handshake.
-     * @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
+     * @param cache The {@link SSLSessionCache} to use, or null for no cache.
      * @return an insecure SSLSocketFactory with the specified parameters
      */
     public static SSLSocketFactory getInsecure(int handshakeTimeoutMillis, SSLSessionCache cache) {
@@ -157,12 +150,11 @@
      *
      * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
      *         for none.  The socket timeout is reset to 0 after the handshake.
-     * @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
+     * @param cache The {@link SSLSessionCache} to use, or null for no cache.
      * @return a new SocketFactory with the specified parameters
      */
     public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(
-            int handshakeTimeoutMillis,
-            SSLSessionCache cache) {
+            int handshakeTimeoutMillis, SSLSessionCache cache) {
         return new org.apache.http.conn.ssl.SSLSocketFactory(
                 new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true));
     }
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 8621de3..b8c5c2a 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -983,6 +983,13 @@
         if (b.getConfig() == Bitmap.Config.ALPHA_8) {
             return setupModifiers(paint);
         }
+
+        final ColorFilter filter = paint.getColorFilter();
+        if (filter != null) {
+            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
+            return MODIFIER_COLOR_FILTER;
+        }
+
         return MODIFIER_NONE;
     }
 
@@ -1016,7 +1023,7 @@
             nSetupColorFilter(mRenderer, filter.nativeColorFilter);
             return MODIFIER_COLOR_FILTER;
         }
-        return MODIFIER_NONE;        
+        return MODIFIER_NONE;
     }
 
     private static native void nSetupShader(int renderer, int shader);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 8584bf2..28541fe 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -20,7 +20,7 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Rect;
-import android.os.SystemClock;
+import android.os.*;
 import android.util.EventLog;
 import android.util.Log;
 
@@ -256,6 +256,7 @@
 
     @SuppressWarnings({"deprecation"})
     static abstract class GlRenderer extends HardwareRenderer {
+        // These values are not exposed in our EGL APIs
         private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
         private static final int EGL_SURFACE_TYPE = 0x3033;
         private static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
@@ -290,7 +291,7 @@
         GlRenderer(int glVersion, boolean translucent) {
             mGlVersion = glVersion;
             mTranslucent = translucent;
-            final String dirtyProperty = System.getProperty(RENDER_DIRTY_REGIONS_PROPERTY, "true");
+            final String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
             //noinspection PointlessBooleanExpression,ConstantConditions
             mDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
         }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c0eb030..96cddfa 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7359,8 +7359,16 @@
             mPrivateFlags &= ~DRAWN;
             mPrivateFlags |= INVALIDATED;
             mPrivateFlags &= ~DRAWING_CACHE_VALID;
-            if (mParent != null && mAttachInfo != null && mAttachInfo.mHardwareAccelerated) {
-                mParent.invalidateChild(this, null);
+            if (mParent != null && mAttachInfo != null) {
+                if (mAttachInfo.mHardwareAccelerated) {
+                    mParent.invalidateChild(this, null);
+                } else {
+                    final Rect r = mAttachInfo.mTmpInvalRect;
+                    r.set(0, 0, mRight - mLeft, mBottom - mTop);
+                    // Don't call invalidate -- we don't want to internally scroll
+                    // our own bounds
+                    mParent.invalidateChild(this, r);
+                }
             }
         }
     }
@@ -7466,8 +7474,9 @@
      */
     public boolean post(Runnable action) {
         Handler handler;
-        if (mAttachInfo != null) {
-            handler = mAttachInfo.mHandler;
+        AttachInfo attachInfo = mAttachInfo;
+        if (attachInfo != null) {
+            handler = attachInfo.mHandler;
         } else {
             // Assume that post will succeed later
             ViewRoot.getRunQueue().post(action);
@@ -7495,8 +7504,9 @@
      */
     public boolean postDelayed(Runnable action, long delayMillis) {
         Handler handler;
-        if (mAttachInfo != null) {
-            handler = mAttachInfo.mHandler;
+        AttachInfo attachInfo = mAttachInfo;
+        if (attachInfo != null) {
+            handler = attachInfo.mHandler;
         } else {
             // Assume that post will succeed later
             ViewRoot.getRunQueue().postDelayed(action, delayMillis);
@@ -7518,8 +7528,9 @@
      */
     public boolean removeCallbacks(Runnable action) {
         Handler handler;
-        if (mAttachInfo != null) {
-            handler = mAttachInfo.mHandler;
+        AttachInfo attachInfo = mAttachInfo;
+        if (attachInfo != null) {
+            handler = attachInfo.mHandler;
         } else {
             // Assume that post will succeed later
             ViewRoot.getRunQueue().removeCallbacks(action);
@@ -7566,11 +7577,12 @@
     public void postInvalidateDelayed(long delayMilliseconds) {
         // We try only with the AttachInfo because there's no point in invalidating
         // if we are not attached to our window
-        if (mAttachInfo != null) {
+        AttachInfo attachInfo = mAttachInfo;
+        if (attachInfo != null) {
             Message msg = Message.obtain();
             msg.what = AttachInfo.INVALIDATE_MSG;
             msg.obj = this;
-            mAttachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
+            attachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
         }
     }
 
@@ -7590,7 +7602,8 @@
 
         // We try only with the AttachInfo because there's no point in invalidating
         // if we are not attached to our window
-        if (mAttachInfo != null) {
+        AttachInfo attachInfo = mAttachInfo;
+        if (attachInfo != null) {
             final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.acquire();
             info.target = this;
             info.left = left;
@@ -7601,7 +7614,7 @@
             final Message msg = Message.obtain();
             msg.what = AttachInfo.INVALIDATE_RECT_MSG;
             msg.obj = info;
-            mAttachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
+            attachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
         }
     }
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 377f083..058b826 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2087,7 +2087,7 @@
     public void setPadding(int left, int top, int right, int bottom) {
         super.setPadding(left, top, right, bottom);
 
-        if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingRight) != 0) {
+        if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
             mGroupFlags |= FLAG_PADDING_NOT_NULL;
         } else {
             mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index c86c9a5..3c386b4 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -502,6 +502,11 @@
                 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
 
         if (hardwareAccelerated) {
+            if (!HardwareRenderer.isAvailable()) {
+                mAttachInfo.mHardwareAccelerationRequested = true;
+                return;
+            }
+
             // Only enable hardware acceleration if we are not in the system process
             // The window manager creates ViewRoots to display animated preview windows
             // of launching apps and we don't want those to be hardware accelerated
@@ -524,8 +529,6 @@
                 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
                 mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
                         = mAttachInfo.mHardwareRenderer != null;
-            } else if (HardwareRenderer.isAvailable()) {
-                mAttachInfo.mHardwareAccelerationRequested = true;
             }
         }
     }
diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java
index 0510f8b..9636513 100644
--- a/core/java/android/webkit/HTML5VideoFullScreen.java
+++ b/core/java/android/webkit/HTML5VideoFullScreen.java
@@ -153,7 +153,7 @@
         // So in full screen, we reset the MediaPlayer
         mPlayer.reset();
         setMediaController(new MediaController(mProxy.getContext()));
-
+        mPlayer.setScreenOnWhilePlaying(true);
         prepareDataAndDisplayMode(mProxy);
     }
 
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 094566f..acd7eab 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -109,7 +109,7 @@
                     boolean foundInTree = nativeSendSurfaceTexture(surfTexture,
                             layer, currentVideoLayerId, textureName,
                             playerState);
-                    if (playerState == HTML5VideoView.STATE_PREPARED
+                    if (playerState >= HTML5VideoView.STATE_PREPARED
                             && !foundInTree) {
                         mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
                         mHTML5VideoView.deleteSurfaceTexture();
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index b712fdb..11b594c 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -25,13 +25,13 @@
 
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.app.ActionBar;
 import android.app.Activity;
 import android.app.Dialog;
-import android.app.Fragment;
 import android.app.FragmentTransaction;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
@@ -44,7 +44,6 @@
 import android.view.View;
 import android.view.Window;
 import android.view.animation.DecelerateInterpolator;
-import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.SpinnerAdapter;
 
@@ -59,6 +58,7 @@
  * which is normally hidden.
  */
 public class ActionBarImpl extends ActionBar {
+    private static final String TAG = "ActionBarImpl";
     private static final int NORMAL_VIEW = 0;
     private static final int CONTEXT_VIEW = 1;
 
@@ -92,60 +92,34 @@
 
     final Handler mHandler = new Handler();
 
-    private Animator mCurrentAnim;
+    private Animator mCurrentShowAnim;
+    private Animator mCurrentModeAnim;
     private boolean mShowHideAnimationEnabled;
+    boolean mWasHiddenBeforeMode;
 
     private static final TimeInterpolator sFadeOutInterpolator = new DecelerateInterpolator();
 
     final AnimatorListener[] mAfterAnimation = new AnimatorListener[] {
-            new AnimatorListener() { // NORMAL_VIEW
-                @Override
-                public void onAnimationStart(Animator animation) {
-                }
-
+            new AnimatorListenerAdapter() { // NORMAL_VIEW
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     if (mLowerContextView != null) {
                         mLowerContextView.removeAllViews();
                     }
-                    mCurrentAnim = null;
+                    mCurrentModeAnim = null;
                     hideAllExcept(NORMAL_VIEW);
                 }
-
-                @Override
-                public void onAnimationCancel(Animator animation) {
-                }
-
-                @Override
-                public void onAnimationRepeat(Animator animation) {
-                }
             },
-            new AnimatorListener() { // CONTEXT_VIEW
-                @Override
-                public void onAnimationStart(Animator animation) {
-                }
-
+            new AnimatorListenerAdapter() { // CONTEXT_VIEW
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    mCurrentAnim = null;
+                    mCurrentModeAnim = null;
                     hideAllExcept(CONTEXT_VIEW);
                 }
-
-                @Override
-                public void onAnimationCancel(Animator animation) {
-                }
-
-                @Override
-                public void onAnimationRepeat(Animator animation) {
-                }
             }
     };
 
-    final AnimatorListener mHideListener = new AnimatorListener() {
-        @Override
-        public void onAnimationStart(Animator animation) {
-        }
-
+    final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
             if (mContentView != null) {
@@ -153,36 +127,16 @@
             }
             mContainerView.setVisibility(View.GONE);
             mContainerView.setTransitioning(false);
-            mCurrentAnim = null;
-        }
-
-        @Override
-        public void onAnimationCancel(Animator animation) {
-        }
-
-        @Override
-        public void onAnimationRepeat(Animator animation) {
+            mCurrentShowAnim = null;
         }
     };
 
-    final AnimatorListener mShowListener = new AnimatorListener() {
-        @Override
-        public void onAnimationStart(Animator animation) {
-        }
-
+    final AnimatorListener mShowListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
-            mCurrentAnim = null;
+            mCurrentShowAnim = null;
             mContainerView.requestLayout();
         }
-
-        @Override
-        public void onAnimationCancel(Animator animation) {
-        }
-
-        @Override
-        public void onAnimationRepeat(Animator animation) {
-        }
     };
 
     public ActionBarImpl(Activity activity) {
@@ -229,8 +183,8 @@
      */
     public void setShowHideAnimationEnabled(boolean enabled) {
         mShowHideAnimationEnabled = enabled;
-        if (!enabled && mCurrentAnim != null) {
-            mCurrentAnim.end();
+        if (!enabled && mCurrentShowAnim != null) {
+            mCurrentShowAnim.end();
         }
     }
 
@@ -370,6 +324,7 @@
         mUpperContextView.killMode();
         ActionMode mode = new ActionModeImpl(callback);
         if (callback.onCreateActionMode(mode, mode.getMenu())) {
+            mWasHiddenBeforeMode = !isShowing();
             mode.invalidate();
             mUpperContextView.initForMode(mode);
             animateTo(CONTEXT_VIEW);
@@ -378,7 +333,6 @@
                 mLowerContextView.setVisibility(View.VISIBLE);
             }
             mActionMode = mode;
-            show();
             return mode;
         }
         return null;
@@ -498,10 +452,15 @@
 
     @Override
     public void show() {
-        if (mCurrentAnim != null) {
-            mCurrentAnim.end();
+        show(true);
+    }
+
+    void show(boolean markHiddenBeforeMode) {
+        if (mCurrentShowAnim != null) {
+            mCurrentShowAnim.end();
         }
         if (mContainerView.getVisibility() == View.VISIBLE) {
+            if (markHiddenBeforeMode) mWasHiddenBeforeMode = false;
             return;
         }
         mContainerView.setVisibility(View.VISIBLE);
@@ -517,17 +476,19 @@
                 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0));
             }
             anim.addListener(mShowListener);
-            mCurrentAnim = anim;
+            mCurrentShowAnim = anim;
             anim.start();
         } else {
+            mContainerView.setAlpha(1);
+            mContainerView.setTranslationY(0);
             mShowListener.onAnimationEnd(null);
         }
     }
 
     @Override
     public void hide() {
-        if (mCurrentAnim != null) {
-            mCurrentAnim.end();
+        if (mCurrentShowAnim != null) {
+            mCurrentShowAnim.end();
         }
         if (mContainerView.getVisibility() == View.GONE) {
             return;
@@ -545,7 +506,7 @@
                         -mContainerView.getHeight()));
             }
             anim.addListener(mHideListener);
-            mCurrentAnim = anim;
+            mCurrentShowAnim = anim;
             anim.start();
         } else {
             mHideListener.onAnimationEnd(null);
@@ -556,13 +517,17 @@
         return mContainerView.getVisibility() == View.VISIBLE;
     }
 
-    private long animateTo(int viewIndex) {
-        show();
+    long animateTo(int viewIndex) {
+        show(false);
+        if (mCurrentModeAnim != null) {
+            mCurrentModeAnim.end();
+        }
 
         AnimatorSet set = new AnimatorSet();
 
         final View targetChild = mContainerView.getChildAt(viewIndex);
         targetChild.setVisibility(View.VISIBLE);
+        targetChild.setAlpha(0);
         AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1));
 
         final int count = mContainerView.getChildCount();
@@ -581,7 +546,7 @@
 
         set.addListener(mAfterAnimation[viewIndex]);
 
-        mCurrentAnim = set;
+        mCurrentModeAnim = set;
         set.start();
         return set.getDuration();
     }
@@ -636,6 +601,10 @@
                 mLowerContextView.setVisibility(View.GONE);
             }
             mActionMode = null;
+
+            if (mWasHiddenBeforeMode) {
+                hide();
+            }
         }
 
         @Override
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index 3325df6..ca1aa0b 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -56,6 +56,7 @@
         mTextButton = (Button) findViewById(com.android.internal.R.id.textButton);
         mImageButton.setOnClickListener(this);
         mTextButton.setOnClickListener(this);
+        setOnClickListener(this);
     }
 
     public MenuItemImpl getItemData() {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index b4a0e4f..66d8a36 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -93,6 +93,7 @@
 	android/graphics/DrawFilter.cpp \
 	android/graphics/CreateJavaOutputStreamAdaptor.cpp \
 	android/graphics/Graphics.cpp \
+	android/graphics/HarfbuzzSkia.cpp \
 	android/graphics/Interpolator.cpp \
 	android/graphics/LayerRasterizer.cpp \
 	android/graphics/MaskFilter.cpp \
@@ -174,6 +175,7 @@
 	external/icu4c/i18n \
 	external/icu4c/common \
 	external/jpeg \
+	external/harfbuzz/src \
 	frameworks/opt/emoji
 
 LOCAL_SHARED_LIBRARIES := \
@@ -206,6 +208,7 @@
 	libjpeg \
 	libnfc_ndef \
 	libusbhost \
+	libharfbuzz \
 
 ifeq ($(USE_OPENGL_RENDERER),true)
 	LOCAL_SHARED_LIBRARIES += libhwui
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 0cdb357..b4ad9e9 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -755,6 +755,27 @@
         env->ReleaseStringChars(text, textArray);
     }
 
+    static void drawGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
+                                         jcharArray glyphs, int index, int count,
+                                         jfloat x, jfloat y, int flags, SkPaint* paint) {
+        jchar* glyphArray = env->GetCharArrayElements(glyphs, NULL);
+
+        // TODO: need to suppress this code after the GL renderer is modified for not
+        // copying the paint
+
+        // Save old text encoding
+        SkPaint::TextEncoding oldEncoding = paint->getTextEncoding();
+        // Define Glyph encoding
+        paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+        TextLayout::drawText(paint, glyphArray + index, count, flags, x, y, canvas);
+
+        // Get back old encoding
+        paint->setTextEncoding(oldEncoding);
+
+        env->ReleaseCharArrayElements(glyphs, glyphArray, JNI_ABORT);
+    }
+
     static void drawTextRun___CIIIIFFIPaint(
         JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index,
         int count, int contextIndex, int contextCount,
@@ -946,6 +967,8 @@
         (void*) SkCanvasGlue::drawText___CIIFFIPaint},
     {"native_drawText","(ILjava/lang/String;IIFFII)V",
         (void*) SkCanvasGlue::drawText__StringIIFFIPaint},
+    {"native_drawGlyphs","(I[CIIFFII)V",
+        (void*) SkCanvasGlue::drawGlyphs___CIIFFIPaint},
     {"native_drawTextRun","(I[CIIIIFFII)V",
         (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
     {"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V",
diff --git a/core/jni/android/graphics/HarfbuzzSkia.cpp b/core/jni/android/graphics/HarfbuzzSkia.cpp
new file mode 100644
index 0000000..58fb32b
--- /dev/null
+++ b/core/jni/android/graphics/HarfbuzzSkia.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ * Copyright 2011, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "HarfbuzzSkia.h"
+
+#include "SkFontHost.h"
+
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkPoint.h"
+#include "SkRect.h"
+#include "SkTypeface.h"
+
+extern "C" {
+#include "harfbuzz-shaper.h"
+}
+
+// This file implements the callbacks which Harfbuzz requires by using Skia
+// calls. See the Harfbuzz source for references about what these callbacks do.
+
+namespace android {
+
+static HB_Fixed SkiaScalarToHarfbuzzFixed(SkScalar value)
+{
+    // HB_Fixed is a 26.6 fixed point format.
+    return value * 64;
+}
+
+static void setupPaintWithFontData(SkPaint* paint, FontData* data) {
+    paint->setAntiAlias(true);
+    paint->setSubpixelText(true);
+    paint->setHinting(SkPaint::kSlight_Hinting);
+    paint->setTextSize(SkFloatToScalar(data->textSize));
+    paint->setTypeface(data->typeFace);
+    paint->setFakeBoldText(data->fakeBold);
+    paint->setTextSkewX(data->fakeItalic ? -SK_Scalar1/4 : 0);
+}
+
+static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length,
+        HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL)
+{
+    FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+    SkPaint paint;
+    setupPaintWithFontData(&paint, data);
+
+    paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+    int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t),
+            reinterpret_cast<uint16_t*>(glyphs));
+
+    // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our
+    // |glyphs| array needs to be converted.
+    for (int i = numGlyphs - 1; i >= 0; --i) {
+        uint16_t value;
+        // We use a memcpy to avoid breaking strict aliasing rules.
+        memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(value));
+        glyphs[i] = value;
+    }
+
+    *glyphsSize = numGlyphs;
+    return 1;
+}
+
+static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs,
+        HB_Fixed* advances, int flags)
+{
+    FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+    SkPaint paint;
+    setupPaintWithFontData(&paint, data);
+
+    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+    uint16_t* glyphs16 = new uint16_t[numGlyphs];
+    if (!glyphs16)
+        return;
+    for (unsigned i = 0; i < numGlyphs; ++i)
+        glyphs16[i] = glyphs[i];
+    paint.getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), reinterpret_cast<SkScalar*>(advances));
+
+    // The |advances| values which Skia outputs are SkScalars, which are floats
+    // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format.
+    // These two formats are both 32-bits long.
+    for (unsigned i = 0; i < numGlyphs; ++i) {
+        float value;
+        // We use a memcpy to avoid breaking strict aliasing rules.
+        memcpy(&value, reinterpret_cast<char*>(advances) + sizeof(float) * i, sizeof(value));
+        advances[i] = SkiaScalarToHarfbuzzFixed(value);
+    }
+    delete glyphs16;
+}
+
+static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length)
+{
+    FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+    SkPaint paint;
+    setupPaintWithFontData(&paint, data);
+
+    paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+    uint16_t* glyphs16 = new uint16_t[length];
+    int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), glyphs16);
+
+    bool result = true;
+    for (int i = 0; i < numGlyphs; ++i) {
+        if (!glyphs16[i]) {
+            result = false;
+            break;
+        }
+    }
+    delete glyphs16;
+    return result;
+}
+
+static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point,
+        HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints)
+{
+    FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+    SkPaint paint;
+    setupPaintWithFontData(&paint, data);
+
+    if (flags & HB_ShaperFlag_UseDesignMetrics)
+        // This is requesting pre-hinted positions. We can't support this.
+        return HB_Err_Invalid_Argument;
+
+    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+    uint16_t glyph16 = glyph;
+    SkPath path;
+    paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path);
+    uint32_t numPoints = path.getPoints(0, 0);
+    if (point >= numPoints)
+        return HB_Err_Invalid_SubTable;
+    SkPoint* points = reinterpret_cast<SkPoint*>(malloc(sizeof(SkPoint) * (point + 1)));
+    if (!points)
+        return HB_Err_Invalid_SubTable;
+    // Skia does let us get a single point from the path.
+    path.getPoints(points, point + 1);
+    *xPos = SkiaScalarToHarfbuzzFixed(points[point].fX);
+    *yPos = SkiaScalarToHarfbuzzFixed(points[point].fY);
+    *resultingNumPoints = numPoints;
+    delete points;
+
+    return HB_Err_Ok;
+}
+
+static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics)
+{
+    FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+    SkPaint paint;
+    setupPaintWithFontData(&paint, data);
+
+    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+    uint16_t glyph16 = glyph;
+    SkScalar width;
+    SkRect bounds;
+    paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
+
+    metrics->x = SkiaScalarToHarfbuzzFixed(bounds.fLeft);
+    metrics->y = SkiaScalarToHarfbuzzFixed(bounds.fTop);
+    metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width());
+    metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height());
+
+    metrics->xOffset = SkiaScalarToHarfbuzzFixed(width);
+    // We can't actually get the |y| correct because Skia doesn't export
+    // the vertical advance. However, nor we do ever render vertical text at
+    // the moment so it's unimportant.
+    metrics->yOffset = 0;
+}
+
+static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric)
+{
+    FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+    SkPaint paint;
+    setupPaintWithFontData(&paint, data);
+
+    SkPaint::FontMetrics skiaMetrics;
+    paint.getFontMetrics(&skiaMetrics);
+
+    switch (metric) {
+    case HB_FontAscent:
+        return SkiaScalarToHarfbuzzFixed(-skiaMetrics.fAscent);
+    // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them.
+    default:
+        return 0;
+    }
+    return 0;
+}
+
+const HB_FontClass harfbuzzSkiaClass = {
+    stringToGlyphs,
+    glyphsToAdvances,
+    canRender,
+    getOutlinePoint,
+    getGlyphMetrics,
+    getFontMetric,
+};
+
+HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len)
+{
+    FontData* data = reinterpret_cast<FontData*>(voidface);
+    SkTypeface* typeface = data->typeFace;
+
+    const size_t tableSize = SkFontHost::GetTableSize(typeface->uniqueID(), tag);
+    if (!tableSize)
+        return HB_Err_Invalid_Argument;
+    // If Harfbuzz specified a NULL buffer then it's asking for the size of the table.
+    if (!buffer) {
+        *len = tableSize;
+        return HB_Err_Ok;
+    }
+
+    if (*len < tableSize)
+        return HB_Err_Invalid_Argument;
+    SkFontHost::GetTableData(typeface->uniqueID(), tag, 0, tableSize, buffer);
+    return HB_Err_Ok;
+}
+
+}  // namespace android
diff --git a/core/jni/android/graphics/HarfbuzzSkia.h b/core/jni/android/graphics/HarfbuzzSkia.h
new file mode 100644
index 0000000..d057d76
--- /dev/null
+++ b/core/jni/android/graphics/HarfbuzzSkia.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ * Copyright 2011, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HarfbuzzSkia_h
+#define HarfbuzzSkia_h
+
+#include "SkTypeface.h"
+
+extern "C" {
+#include "harfbuzz-shaper.h"
+}
+
+namespace android {
+    typedef struct {
+        SkTypeface* typeFace;
+        float textSize;
+        bool fakeBold;
+        bool fakeItalic;
+    } FontData;
+
+    HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len);
+    extern const HB_FontClass harfbuzzSkiaClass;
+}  // namespace android
+
+#endif
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index e62b034..5c3497f 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -393,13 +393,40 @@
         return count;
     }
  
-    static int getTextWidths__StringII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text, int start, int end, jfloatArray widths) {
+    static int getTextWidths__StringII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text,
+            int start, int end, jfloatArray widths) {
         const jchar* textArray = env->GetStringChars(text, NULL);
         int count = dotextwidths(env, paint, textArray + start, end - start, widths);
         env->ReleaseStringChars(text, textArray);
         return count;
     }
 
+    static int doTextGlyphs(JNIEnv* env, SkPaint* paint, const jchar* text, jint start, jint count,
+            jint contextCount, jint flags, jcharArray glyphs) {
+        jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL);
+        HB_ShaperItem shaperItem;
+        HB_FontRec font;
+        FontData fontData;
+        RunAdvanceDescription::shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, text,
+                start, count, contextCount, flags);
+
+        int glyphCount = shaperItem.num_glyphs;
+        for (int i = 0; i < glyphCount; i++) {
+            glyphsArray[i] = (jchar) shaperItem.glyphs[i];
+        }
+        return glyphCount;
+    }
+
+    static int getTextGlyphs__StringIIIII_C(JNIEnv* env, jobject clazz, SkPaint* paint,
+            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
+            jcharArray glyphs) {
+        const jchar* textArray = env->GetStringChars(text, NULL);
+        int count = doTextGlyphs(env, paint, textArray + contextStart, start - contextStart,
+                end - start, contextEnd - contextStart, flags, glyphs);
+        env->ReleaseStringChars(text, textArray);
+        return count;
+    }
+
     static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text,
                                     jint start, jint count, jint contextCount, jint flags,
                                     jfloatArray advances, jint advancesIndex) {
@@ -725,6 +752,8 @@
         SkPaintGlue::getTextRunAdvances___CIIIII_FI},
     {"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FI)F",
         (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI},
+    {"native_getTextGlyphs","(ILjava/lang/String;IIIII[C)I",
+        (void*) SkPaintGlue::getTextGlyphs__StringIIIII_C},
     {"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
     {"native_getTextRunCursor", "(ILjava/lang/String;IIIII)I",
         (void*) SkPaintGlue::getTextRunCursor__String},
diff --git a/core/jni/android/graphics/RtlProperties.h b/core/jni/android/graphics/RtlProperties.h
index 6d8ba91..2c68fa3 100644
--- a/core/jni/android/graphics/RtlProperties.h
+++ b/core/jni/android/graphics/RtlProperties.h
@@ -45,5 +45,7 @@
     return kRtlDebugDisabled;
 }
 
+#define RTL_USE_HARFBUZZ 1
+
 } // namespace android
 #endif // ANDROID_RTL_PROPERTIES_H
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 7888769..a7265be 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -47,8 +47,16 @@
     if (mDebugEnabled) {
         LOGD("TextLayoutCache start time: %lld", mCacheStartTime);
     }
-
     mInitialized = true;
+
+    if (mDebugEnabled) {
+#if RTL_USE_HARFBUZZ
+        LOGD("TextLayoutCache is using HARFBUZZ");
+#else
+        LOGD("TextLayoutCache is using ICU");
+#endif
+    }
+
     if (mDebugEnabled) {
         LOGD("TextLayoutCache initialization is done");
     }
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 9d55918..e962a86 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -30,6 +30,8 @@
 
 #include "unicode/ubidi.h"
 #include "unicode/ushape.h"
+#include "HarfbuzzSkia.h"
+#include "harfbuzz-shaper.h"
 
 #include <android_runtime/AndroidRuntime.h>
 
@@ -52,8 +54,14 @@
 // Define the interval in number of cache hits between two statistics dump
 #define DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL 100
 
+// Define if we want to have Advances debug values
+#define DEBUG_ADVANCES 0
+
 namespace android {
 
+// Harfbuzz uses 26.6 fixed point values for pixel offsets
+#define HB_FIXED_TO_FLOAT(v) (((float) v) * (1.0 / 64))
+
 /**
  * TextLayoutCacheKey is the Cache key
  */
@@ -149,8 +157,18 @@
         advances = new float[count];
         this->count = count;
 
-        computeAdvances(paint, chars, start, count, contextCount, dirFlags,
+#if RTL_USE_HARFBUZZ
+        computeAdvancesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags,
                 advances, &totalAdvance);
+#else
+        computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags,
+                advances, &totalAdvance);
+#endif
+#if DEBUG_ADVANCES
+        LOGD("Advances - count=%d - countextCount=%d - totalAdvance=%f - "
+                "adv[0]=%f adv[1]=%f adv[2]=%f adv[3]=%f", count, contextCount, totalAdvance,
+                advances[0], advances[1], advances[2], advances[3]);
+#endif
     }
 
     void copyResult(jfloat* outAdvances, jfloat* outTotalAdvance) {
@@ -165,8 +183,108 @@
         return sizeof(RunAdvanceDescription) + sizeof(jfloat) * count;
     }
 
-    static void computeAdvances(SkPaint* paint, const UChar* chars, size_t start, size_t count,
-            size_t contextCount, int dirFlags, jfloat* outAdvances, jfloat* outTotalAdvance) {
+    static void setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData,
+            SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount,
+            int dirFlags) {
+        bool isRTL = dirFlags & 0x1;
+
+        font->klass = &harfbuzzSkiaClass;
+        font->userData = 0;
+        // The values which harfbuzzSkiaClass returns are already scaled to
+        // pixel units, so we just set all these to one to disable further
+        // scaling.
+        font->x_ppem = 1;
+        font->y_ppem = 1;
+        font->x_scale = 1;
+        font->y_scale = 1;
+
+        memset(shaperItem, 0, sizeof(*shaperItem));
+        shaperItem->font = font;
+        shaperItem->face = HB_NewFace(shaperItem->font, harfbuzzSkiaGetTable);
+
+        // We cannot know, ahead of time, how many glyphs a given script run
+        // will produce. We take a guess that script runs will not produce more
+        // than twice as many glyphs as there are code points plus a bit of
+        // padding and fallback if we find that we are wrong.
+        createGlyphArrays(shaperItem, (contextCount + 2) * 2);
+
+        // Free memory for clusters if needed and recreate the clusters array
+        if (shaperItem->log_clusters) {
+            delete shaperItem->log_clusters;
+        }
+        shaperItem->log_clusters = new unsigned short[contextCount];
+
+        shaperItem->item.pos = start;
+        shaperItem->item.length = count;
+        shaperItem->item.bidiLevel = isRTL;
+        shaperItem->item.script = isRTL ? HB_Script_Arabic : HB_Script_Common;
+
+        shaperItem->string = chars;
+        shaperItem->stringLength = contextCount;
+
+        fontData->textSize = paint->getTextSize();
+        fontData->fakeBold = paint->isFakeBoldText();
+        fontData->fakeItalic = (paint->getTextSkewX() > 0);
+        fontData->typeFace = paint->getTypeface();
+
+        shaperItem->font->userData = fontData;
+    }
+
+    static void shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData,
+            SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount,
+            int dirFlags) {
+        // Setup Harfbuzz Shaper
+        setupShaperItem(shaperItem, font, fontData, paint, chars, start, count,
+                contextCount, dirFlags);
+
+        // Shape
+        resetGlyphArrays(shaperItem);
+        while (!HB_ShapeItem(shaperItem)) {
+            // We overflowed our arrays. Resize and retry.
+            // HB_ShapeItem fills in shaperItem.num_glyphs with the needed size.
+            deleteGlyphArrays(shaperItem);
+            createGlyphArrays(shaperItem, shaperItem->num_glyphs << 1);
+            resetGlyphArrays(shaperItem);
+        }
+    }
+
+    static void computeAdvancesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start,
+            size_t count, size_t contextCount, int dirFlags,
+            jfloat* outAdvances, jfloat* outTotalAdvance) {
+
+        bool isRTL = dirFlags & 0x1;
+
+        HB_ShaperItem shaperItem;
+        HB_FontRec font;
+        FontData fontData;
+        shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, chars, start, count,
+                contextCount, dirFlags);
+
+#if DEBUG_ADVANCES
+        LOGD("HARFBUZZ -- num_glypth=%d", shaperItem.num_glyphs);
+#endif
+
+        jfloat totalAdvance = 0;
+        for (size_t i = 0; i < count; i++) {
+            // Be careful: we need to use roundf() for doing the same way as Skia is doing
+            totalAdvance += outAdvances[i] = roundf(HB_FIXED_TO_FLOAT(shaperItem.advances[i]));
+
+#if DEBUG_ADVANCES
+            LOGD("hb-adv = %d - rebased = %f - total = %f", shaperItem.advances[i], outAdvances[i],
+                    totalAdvance);
+#endif
+        }
+
+        deleteGlyphArrays(&shaperItem);
+        HB_FreeFace(shaperItem.face);
+
+        *outTotalAdvance = totalAdvance;
+    }
+
+    static void computeAdvancesWithICU(SkPaint* paint, const UChar* chars, size_t start,
+            size_t count, size_t contextCount, int dirFlags,
+            jfloat* outAdvances, jfloat* outTotalAdvance) {
+
         SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
         jchar* buffer = tempBuffer.get();
 
@@ -199,6 +317,9 @@
 
         jfloat totalAdvance = 0;
         if (widths < count) {
+#if DEBUG_ADVANCES
+        LOGD("ICU -- count=%d", widths);
+#endif
             // Skia operates on code points, not code units, so surrogate pairs return only
             // one value. Expand the result so we have one value per UTF-16 code unit.
 
@@ -213,10 +334,19 @@
                         text[p-1] < UNICODE_FIRST_LOW_SURROGATE) {
                     outAdvances[p++] = 0;
                 }
+#if DEBUG_ADVANCES
+                LOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
+#endif
             }
         } else {
+#if DEBUG_ADVANCES
+        LOGD("ICU -- count=%d", count);
+#endif
             for (size_t i = 0; i < count; i++) {
                 totalAdvance += outAdvances[i] = SkScalarToFloat(scalarArray[i]);
+#if DEBUG_ADVANCES
+                LOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
+#endif
             }
         }
         *outTotalAdvance = totalAdvance;
@@ -228,6 +358,32 @@
     size_t count;
 
     uint32_t elapsedTime;
+
+    static void deleteGlyphArrays(HB_ShaperItem* shaperItem) {
+        delete[] shaperItem->glyphs;
+        delete[] shaperItem->attributes;
+        delete[] shaperItem->advances;
+        delete[] shaperItem->offsets;
+    }
+
+    static void createGlyphArrays(HB_ShaperItem* shaperItem, int size) {
+        shaperItem->glyphs = new HB_Glyph[size];
+        shaperItem->attributes = new HB_GlyphAttributes[size];
+        shaperItem->advances = new HB_Fixed[size];
+        shaperItem->offsets = new HB_FixedPoint[size];
+        shaperItem->num_glyphs = size;
+    }
+
+    static void resetGlyphArrays(HB_ShaperItem* shaperItem) {
+        int size = shaperItem->num_glyphs;
+        // All the types here don't have pointers. It is safe to reset to
+        // zero unless Harfbuzz breaks the compatibility in the future.
+        memset(shaperItem->glyphs, 0, size * sizeof(shaperItem->glyphs[0]));
+        memset(shaperItem->attributes, 0, size * sizeof(shaperItem->attributes[0]));
+        memset(shaperItem->advances, 0, size * sizeof(shaperItem->advances[0]));
+        memset(shaperItem->offsets, 0, size * sizeof(shaperItem->offsets[0]));
+    }
+
 }; // RunAdvanceDescription
 
 
diff --git a/core/res/res/layout/action_menu_item_layout.xml b/core/res/res/layout/action_menu_item_layout.xml
index 15dfea3..4a73368 100644
--- a/core/res/res/layout/action_menu_item_layout.xml
+++ b/core/res/res/layout/action_menu_item_layout.xml
@@ -24,7 +24,8 @@
     android:paddingLeft="12dip"
     android:paddingRight="12dip"
     android:minWidth="64dip"
-    android:minHeight="?attr/actionBarSize">
+    android:minHeight="?attr/actionBarSize"
+    android:focusable="true">
     <ImageButton android:id="@+id/imageButton"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
@@ -34,7 +35,8 @@
                  android:paddingRight="4dip"
                  android:minHeight="56dip"
                  android:scaleType="center"
-                 android:background="@null" />
+                 android:background="@null"
+                 android:focusable="false" />
     <Button android:id="@+id/textButton"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -45,5 +47,6 @@
             android:textColor="?attr/actionMenuTextColor"
             android:background="@null"
             android:paddingLeft="4dip"
-            android:paddingRight="4dip" />
+            android:paddingRight="4dip"
+            android:focusable="false" />
 </com.android.internal.view.menu.ActionMenuItemView>
diff --git a/core/res/res/layout/tab_indicator_holo.xml b/core/res/res/layout/tab_indicator_holo.xml
index d37476b..60c80e9 100644
--- a/core/res/res/layout/tab_indicator_holo.xml
+++ b/core/res/res/layout/tab_indicator_holo.xml
@@ -15,32 +15,24 @@
 -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="56dip"
-    android:layout_weight="0"
-    android:layout_marginLeft="0dip"
-    android:layout_marginRight="0dip"
+    android:layout_width="0dp"
+    android:layout_height="58dp"
+    android:layout_weight="1"
+    android:layout_marginLeft="-3dip"
+    android:layout_marginRight="-3dip"
+    android:paddingBottom="8dp"
     android:background="@android:drawable/tab_indicator_holo">
 
-    <View android:id="@+id/tab_indicator_left_spacer"
-        android:layout_width="16dip"
-        android:layout_height="0dip" />
-
     <ImageView android:id="@+id/icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_centerVertical="true"
-        android:visibility="gone"
-        android:layout_toRightOf="@id/tab_indicator_left_spacer"
-        android:paddingRight="8dip" />
+        android:layout_centerHorizontal="true" />
 
     <TextView android:id="@+id/title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_centerVertical="true"
-        android:layout_toRightOf="@id/icon"
-        android:paddingLeft="0dip"
-        android:paddingRight="16dip"
+        android:layout_alignParentBottom="true"
+        android:layout_centerHorizontal="true"
         style="?android:attr/tabWidgetStyle" />
-
+    
 </RelativeLayout>
diff --git a/core/res/res/layout/tab_indicator_holo_large.xml b/core/res/res/layout/tab_indicator_holo_large.xml
new file mode 100644
index 0000000..bdd8d11
--- /dev/null
+++ b/core/res/res/layout/tab_indicator_holo_large.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="56dip"
+    android:layout_weight="0"
+    android:layout_marginLeft="0dip"
+    android:layout_marginRight="0dip"
+    android:background="@android:drawable/tab_indicator_holo">
+
+    <View android:id="@+id/tab_indicator_left_spacer"
+        android:layout_width="16dip"
+        android:layout_height="0dip" />
+
+    <ImageView android:id="@+id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:visibility="gone"
+        android:layout_toRightOf="@id/tab_indicator_left_spacer"
+        android:paddingRight="8dip" />
+
+    <TextView android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:layout_toRightOf="@id/icon"
+        android:paddingLeft="0dip"
+        android:paddingRight="16dip"
+        style="?android:attr/tabWidgetStyle" />
+
+</RelativeLayout>
diff --git a/core/res/res/values-xlarge/styles.xml b/core/res/res/values-xlarge/styles.xml
index dd78920..a39d9d6 100644
--- a/core/res/res/values-xlarge/styles.xml
+++ b/core/res/res/values-xlarge/styles.xml
@@ -36,6 +36,22 @@
         <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
 
+    <style name="TextAppearance.Holo.Widget.TabWidget">
+        <item name="android:textSize">18sp</item>
+        <item name="android:textStyle">normal</item>
+        <item name="android:textColor">@android:color/tab_indicator_text</item>
+    </style>
+    
+    <style name="Widget.Holo.TabWidget" parent="Widget.TabWidget">
+        <item name="android:textAppearance">@style/TextAppearance.Holo.Widget.TabWidget</item>
+        <item name="android:tabStripLeft">@null</item>
+        <item name="android:tabStripRight">@null</item>
+        <item name="android:tabStripEnabled">false</item>
+        <item name="android:divider">@null</item>
+        <item name="android:gravity">left|center_vertical</item>
+        <item name="android:tabLayout">@android:layout/tab_indicator_holo_large</item>
+    </style>
+    
     <style name="PreferencePanel">
         <item name="android:layout_marginLeft">@dimen/preference_screen_side_margin</item>
         <item name="android:layout_marginRight">@dimen/preference_screen_side_margin</item>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 08f5410..f7d3c3f 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1214,8 +1214,10 @@
         <item name="android:textColor">?textColorPrimary</item>
     </style>
 
+    <!-- This style is for smaller screens; values-xlarge defines a version
+         for larger screens. -->
     <style name="TextAppearance.Holo.Widget.TabWidget">
-        <item name="android:textSize">18sp</item>
+        <item name="android:textSize">14sp</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textColor">@android:color/tab_indicator_text</item>
     </style>
@@ -1664,6 +1666,9 @@
         <item name="android:button">@android:drawable/btn_star_holo_dark</item>
     </style>
 
+    <!-- The holo style for smaller screens actually uses the non-holo layout,
+         which is more compact.  values-xlarge defines an alternative version
+         for the real holo look on a large screen. -->
     <style name="Widget.Holo.TabWidget" parent="Widget.TabWidget">
         <item name="android:textAppearance">@style/TextAppearance.Holo.Widget.TabWidget</item>
         <item name="android:tabStripLeft">@null</item>
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
index 5dedd4a..7f13791 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
@@ -60,6 +60,7 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        mTestUtils.disable(adapter);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("enable iteration " + (i + 1) + " of " + iterations);
@@ -78,7 +79,9 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
+        mTestUtils.undiscoverable(adapter);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("discoverable iteration " + (i + 1) + " of " + iterations);
@@ -99,7 +102,9 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
+        mTestUtils.stopScan(adapter);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("scan iteration " + (i + 1) + " of " + iterations);
@@ -116,7 +121,9 @@
     public void testEnablePan() {
         int iterations = BluetoothTestRunner.sEnablePanIterations;
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
+        mTestUtils.disablePan(adapter);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("testEnablePan iteration " + (i + 1) + " of "
@@ -141,13 +148,15 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPairAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
+        mTestUtils.unpair(adapter, device);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("pair iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                    BluetoothTestRunner.sPairPin);
+            mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                    BluetoothTestRunner.sDevicePairPin);
             mTestUtils.unpair(adapter, device);
         }
         mTestUtils.disable(adapter);
@@ -162,13 +171,15 @@
     public void testAcceptPair() {
         int iterations = BluetoothTestRunner.sPairIterations;
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPairAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
+        mTestUtils.unpair(adapter, device);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("acceptPair iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                    BluetoothTestRunner.sPairPin);
+            mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                    BluetoothTestRunner.sDevicePairPin);
             mTestUtils.unpair(adapter, device);
         }
         mTestUtils.disable(adapter);
@@ -187,15 +198,20 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sA2dpAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                BluetoothTestRunner.sPairPin);
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                BluetoothTestRunner.sDevicePairPin);
+        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP, null);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("connectA2dp iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.connectProfile(adapter, device, BluetoothProfile.A2DP);
-            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP);
+            mTestUtils.connectProfile(adapter, device, BluetoothProfile.A2DP,
+                    String.format("connectA2dp(device=%s)", device));
+            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP,
+                    String.format("disconnectA2dp(device=%s)", device));
         }
 
         mTestUtils.unpair(adapter, device);
@@ -215,15 +231,20 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sHeadsetAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                BluetoothTestRunner.sPairPin);
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                BluetoothTestRunner.sDevicePairPin);
+        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET, null);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("connectHeadset iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET);
-            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET);
+            mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET,
+                    String.format("connectHeadset(device=%s)", device));
+            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET,
+                    String.format("disconnectHeadset(device=%s)", device));
         }
 
         mTestUtils.unpair(adapter, device);
@@ -243,15 +264,20 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sInputAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                BluetoothTestRunner.sPairPin);
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                BluetoothTestRunner.sDevicePairPin);
+        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE, null);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("connectInput iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.connectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE);
-            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE);
+            mTestUtils.connectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE,
+                    String.format("connectInput(device=%s)", device));
+            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE,
+                    String.format("disconnectInput(device=%s)", device));
         }
 
         mTestUtils.unpair(adapter, device);
@@ -271,10 +297,12 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPanAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                BluetoothTestRunner.sPairPin);
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                BluetoothTestRunner.sDevicePairPin);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("connectPan iteration " + (i + 1) + " of " + iterations);
@@ -299,11 +327,14 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPanAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
+        mTestUtils.disablePan(adapter);
         mTestUtils.enablePan(adapter);
-        mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                BluetoothTestRunner.sPairPin);
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                BluetoothTestRunner.sDevicePairPin);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("incomingPanConnection iteration " + (i + 1) + " of "
@@ -330,11 +361,15 @@
         }
 
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sHeadsetAddress);
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.disable(adapter);
         mTestUtils.enable(adapter);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
-                BluetoothTestRunner.sPairPin);
-        mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET);
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+                BluetoothTestRunner.sDevicePairPin);
+        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET, null);
+        mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET, null);
+        mTestUtils.stopSco(adapter, device);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("startStopSco iteration " + (i + 1) + " of " + iterations);
@@ -342,7 +377,7 @@
             mTestUtils.stopSco(adapter, device);
         }
 
-        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET);
+        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET, null);
         mTestUtils.unpair(adapter, device);
         mTestUtils.disable(adapter);
     }
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
index 1febc5c..64d2c12 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
@@ -65,14 +65,9 @@
     public static int sConnectPanIterations = 100;
     public static int sStartStopScoIterations = 100;
 
-    public static String sPairAddress = "";
-    public static String sHeadsetAddress = "";
-    public static String sA2dpAddress = "";
-    public static String sInputAddress = "";
-    public static String sPanAddress = "";
-
-    public static byte[] sPairPin = {'1', '2', '3', '4'};
-    public static int sPairPasskey = 123456;
+    public static String sDeviceAddress = "";
+    public static byte[] sDevicePairPin = {'1', '2', '3', '4'};
+    public static int sDevicePairPasskey = 123456;
 
     @Override
     public TestSuite getAllTests() {
@@ -177,40 +172,24 @@
                 // Invalid argument, fall back to default value
             }
         }
-        val = arguments.getString("pair_address");
+
+        val = arguments.getString("device_address");
         if (val != null) {
-            sPairAddress = val;
+            sDeviceAddress = val;
         }
 
-        val = arguments.getString("headset_address");
+        val = arguments.getString("device_pair_pin");
         if (val != null) {
-            sHeadsetAddress = val;
+            byte[] pin = BluetoothDevice.convertPinToBytes(val);
+            if (pin != null) {
+                sDevicePairPin = pin;
+            }
         }
 
-        val = arguments.getString("a2dp_address");
-        if (val != null) {
-            sA2dpAddress = val;
-        }
-
-        val = arguments.getString("input_address");
-        if (val != null) {
-            sInputAddress = val;
-        }
-
-        val = arguments.getString("pan_address");
-        if (val != null) {
-            sPanAddress = val;
-        }
-
-        val = arguments.getString("pair_pin");
-        if (val != null) {
-            sPairPin = BluetoothDevice.convertPinToBytes(val);
-        }
-
-        val = arguments.getString("pair_passkey");
+        val = arguments.getString("device_pair_passkey");
         if (val != null) {
             try {
-                sPairPasskey = Integer.parseInt(val);
+                sDevicePairPasskey = Integer.parseInt(val);
             } catch (NumberFormatException e) {
                 // Invalid argument, fall back to default value
             }
@@ -225,13 +204,9 @@
         Log.i(TAG, String.format("connect_input_iterations=%d", sConnectInputIterations));
         Log.i(TAG, String.format("connect_pan_iterations=%d", sConnectPanIterations));
         Log.i(TAG, String.format("start_stop_sco_iterations=%d", sStartStopScoIterations));
-        Log.i(TAG, String.format("pair_address=%s", sPairAddress));
-        Log.i(TAG, String.format("a2dp_address=%s", sA2dpAddress));
-        Log.i(TAG, String.format("headset_address=%s", sHeadsetAddress));
-        Log.i(TAG, String.format("input_address=%s", sInputAddress));
-        Log.i(TAG, String.format("pan_address=%s", sPanAddress));
-        Log.i(TAG, String.format("pair_pin=%s", new String(sPairPin)));
-        Log.i(TAG, String.format("pair_passkey=%d", sPairPasskey));
+        Log.i(TAG, String.format("device_address=%s", sDeviceAddress));
+        Log.i(TAG, String.format("device_pair_pin=%s", new String(sDevicePairPin)));
+        Log.i(TAG, String.format("device_pair_passkey=%d", sDevicePairPasskey));
 
         // Call onCreate last since we want to set the static variables first.
         super.onCreate(arguments);
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
index 1741119..f1dd8fe 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
@@ -37,44 +37,21 @@
 
 public class BluetoothTestUtils extends Assert {
 
-    /**
-     * Timeout for enable/disable in ms.
-     */
+    /** Timeout for enable/disable in ms. */
     private static final int ENABLE_DISABLE_TIMEOUT = 20000;
-
-    /**
-     * Timeout for discoverable/undiscoverable in ms.
-     */
+    /** Timeout for discoverable/undiscoverable in ms. */
     private static final int DISCOVERABLE_UNDISCOVERABLE_TIMEOUT = 5000;
-
-    /**
-     * Timeout for starting/stopping a scan in ms.
-     */
+    /** Timeout for starting/stopping a scan in ms. */
     private static final int START_STOP_SCAN_TIMEOUT = 5000;
-
-    /**
-     * Timeout for pair/unpair in ms.
-     */
+    /** Timeout for pair/unpair in ms. */
     private static final int PAIR_UNPAIR_TIMEOUT = 20000;
-
-    /**
-     * Timeout for connecting/disconnecting a profile in ms.
-     */
+    /** Timeout for connecting/disconnecting a profile in ms. */
     private static final int CONNECT_DISCONNECT_PROFILE_TIMEOUT = 20000;
-
-    /**
-     * Timeout to connect a profile proxy in ms.
-     */
-    private static final int CONNECT_PROXY_TIMEOUT = 5000;
-
-    /**
-     * Timeout to start or stop a SCO channel in ms.
-     */
+    /** Timeout to start or stop a SCO channel in ms. */
     private static final int START_STOP_SCO_TIMEOUT = 10000;
-
-    /**
-     * Time between polls in ms.
-     */
+    /** Timeout to connect a profile proxy in ms. */
+    private static final int CONNECT_PROXY_TIMEOUT = 5000;
+    /** Time between polls in ms. */
     private static final int POLL_TIME = 100;
 
     private abstract class FlagReceiver extends BroadcastReceiver {
@@ -249,6 +226,9 @@
                 case BluetoothProfile.INPUT_DEVICE:
                     mConnectionAction = BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED;
                     break;
+                case BluetoothProfile.PAN:
+                    mConnectionAction = BluetoothPan.ACTION_CONNECTION_STATE_CHANGED;
+                    break;
                 default:
                     mConnectionAction = null;
             }
@@ -281,47 +261,22 @@
         }
     }
 
-    private class ConnectPanReceiver extends FlagReceiver {
-        private static final int STATE_DISCONNECTED_FLAG = 1;
-        private static final int STATE_CONNECTING_FLAG = 1 << 1;
-        private static final int STATE_CONNECTED_FLAG = 1 << 2;
-        private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
-
-        private BluetoothDevice mDevice;
+    private class ConnectPanReceiver extends ConnectProfileReceiver {
         private int mRole;
 
         public ConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags) {
-            super (expectedFlags);
+            super(device, BluetoothProfile.PAN, expectedFlags);
 
-            mDevice = device;
             mRole = role;
         }
 
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))
-                    || mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
+            if (mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
                 return;
             }
 
-            if (BluetoothPan.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
-                int state = intent.getIntExtra(BluetoothPan.EXTRA_STATE, -1);
-                assertNotSame(-1, state);
-                switch (state) {
-                    case BluetoothPan.STATE_DISCONNECTED:
-                        setFiredFlag(STATE_DISCONNECTED_FLAG);
-                        break;
-                    case BluetoothPan.STATE_CONNECTING:
-                        setFiredFlag(STATE_CONNECTING_FLAG);
-                        break;
-                    case BluetoothPan.STATE_CONNECTED:
-                        setFiredFlag(STATE_CONNECTED_FLAG);
-                        break;
-                    case BluetoothPan.STATE_DISCONNECTING:
-                        setFiredFlag(STATE_DISCONNECTING_FLAG);
-                        break;
-                }
-            }
+            super.onReceive(context, intent);
         }
     }
 
@@ -353,6 +308,7 @@
 
     private BluetoothProfile.ServiceListener mServiceListener =
             new BluetoothProfile.ServiceListener() {
+        @Override
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
             synchronized (this) {
                 switch (profile) {
@@ -372,6 +328,7 @@
             }
         }
 
+        @Override
         public void onServiceDisconnected(int profile) {
             synchronized (this) {
                 switch (profile) {
@@ -399,10 +356,10 @@
     private String mOutputFile;
 
     private Context mContext;
-    private BluetoothA2dp mA2dp;
-    private BluetoothHeadset mHeadset;
-    private BluetoothInputDevice mInput;
-    private BluetoothPan mPan;
+    private BluetoothA2dp mA2dp = null;
+    private BluetoothHeadset mHeadset = null;
+    private BluetoothInputDevice mInput = null;
+    private BluetoothPan mPan = null;
 
     /**
      * Creates a utility instance for testing Bluetooth.
@@ -818,10 +775,15 @@
             byte[] pin, boolean shouldPair) {
         int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG;
         long start = -1;
-        String methodName = shouldPair ? "pair()" : "acceptPair()";
+        String methodName;
+        if (shouldPair) {
+            methodName = String.format("pair(device=%s)", device);
+        } else {
+            methodName = String.format("acceptPair(device=%s)", device);
+        }
 
         if (!adapter.isEnabled()) {
-            fail(methodName + " bluetooth not enabled");
+            fail(String.format("%s bluetooth not enabled", methodName));
         }
 
         PairReceiver receiver = getPairReceiver(device, passkey, pin, mask);
@@ -843,8 +805,7 @@
                 return;
             default:
                 removeReceiver(receiver);
-                fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
-                        state));
+                fail(String.format("%s invalid state: state=%d", methodName, state));
         }
 
         long s = System.currentTimeMillis();
@@ -854,10 +815,10 @@
                 assertTrue(adapter.getBondedDevices().contains(device));
                 long finish = receiver.getCompletedTime();
                 if (start != -1 && finish != -1) {
-                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
-                            (finish - start), device));
+                    writeOutput(String.format("%s completed in %d ms", methodName,
+                            (finish - start)));
                 } else {
-                    writeOutput(String.format("%s completed: device=%s", methodName, device));
+                    writeOutput(String.format("%s completed", methodName));
                 }
                 removeReceiver(receiver);
                 return;
@@ -867,9 +828,8 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
-                + "flags=0x%x (expected 0x%x)", methodName, device, state,
-                BluetoothDevice.BOND_BONDED, firedFlags, mask));
+        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
+                methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask));
     }
 
     /**
@@ -882,9 +842,10 @@
     public void unpair(BluetoothAdapter adapter, BluetoothDevice device) {
         int mask = PairReceiver.STATE_NONE_FLAG;
         long start = -1;
+        String methodName = String.format("unpair(device=%s)", device);
 
         if (!adapter.isEnabled()) {
-            fail("unpair() bluetooth not enabled");
+            fail(String.format("%s bluetooth not enabled", methodName));
         }
 
         PairReceiver receiver = getPairReceiver(device, 0, null, mask);
@@ -906,7 +867,7 @@
                 break;
             default:
                 removeReceiver(receiver);
-                fail(String.format("unpair() invalid state: device=%s, state=%d", device, state));
+                fail(String.format("%s invalid state: state=%d", methodName, state));
         }
 
         long s = System.currentTimeMillis();
@@ -916,10 +877,10 @@
                 assertFalse(adapter.getBondedDevices().contains(device));
                 long finish = receiver.getCompletedTime();
                 if (start != -1 && finish != -1) {
-                    writeOutput(String.format("unpair() completed in %d ms: device=%s",
-                            (finish - start), device));
+                    writeOutput(String.format("%s completed in %d ms", methodName,
+                            (finish - start)));
                 } else {
-                    writeOutput(String.format("unpair() completed: device=%s", device));
+                    writeOutput(String.format("%s completed", methodName));
                 }
                 removeReceiver(receiver);
                 return;
@@ -928,9 +889,8 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("unpair() timeout: device=%s, state=%d (expected %d), "
-                + "flags=0x%x (expected 0x%x)", device, state, BluetoothDevice.BOND_BONDED,
-                firedFlags, mask));
+        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
+                methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask));
     }
 
     /**
@@ -939,29 +899,30 @@
      *
      * @param adapter The BT adapter.
      * @param device The remote device.
-     * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP} or
-     *        {@link BluetoothProfile#HEADSET}.
+     * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP},
+     * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#INPUT_DEVICE}.
+     * @param methodName The method name to printed in the logs.  If null, will be
+     * "connectProfile(profile=&lt;profile&gt;, device=&lt;device&gt;)"
      */
-    public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile) {
+    public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile,
+            String methodName) {
+        if (methodName == null) {
+            methodName = String.format("connectProfile(profile=%d, device=%s)", profile, device);
+        }
         int mask = (ConnectProfileReceiver.STATE_CONNECTING_FLAG
                 | ConnectProfileReceiver.STATE_CONNECTED_FLAG);
         long start = -1;
 
         if (!adapter.isEnabled()) {
-            fail(String.format("connectProfile() bluetooth not enabled: device=%s, profile=%d",
-                    device, profile));
+            fail(String.format("%s bluetooth not enabled", methodName));
         }
 
         if (!adapter.getBondedDevices().contains(device)) {
-            fail(String.format("connectProfile() device not paired: device=%s, profile=%d",
-                    device, profile));
+            fail(String.format("%s device not paired", methodName));
         }
 
         BluetoothProfile proxy = connectProxy(adapter, profile);
-        if (proxy == null) {
-            fail(String.format("connectProfile() unknown profile: device=%s, profile=%d",
-                    device, profile));
-        }
+        assertNotNull(proxy);
 
         ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask);
 
@@ -980,8 +941,7 @@
                 break;
             default:
                 removeReceiver(receiver);
-                fail(String.format("connectProfile() invalid state: device=%s, profile=%d, "
-                        + "state=%d", device, profile, state));
+                fail(String.format("%s invalid state: state=%d", methodName, state));
         }
 
         long s = System.currentTimeMillis();
@@ -991,11 +951,10 @@
                     && (receiver.getFiredFlags() & mask) == mask) {
                 long finish = receiver.getCompletedTime();
                 if (start != -1 && finish != -1) {
-                    writeOutput(String.format("connectProfile() completed in %d ms: "
-                            + "device=%s, profile=%d", (finish - start), device, profile));
+                    writeOutput(String.format("%s completed in %d ms", methodName,
+                            (finish - start)));
                 } else {
-                    writeOutput(String.format("connectProfile() completed: device=%s, "
-                            + "profile=%d", device, profile));
+                    writeOutput(String.format("%s completed", methodName));
                 }
                 removeReceiver(receiver);
                 return;
@@ -1005,9 +964,8 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("connectProfile() timeout: device=%s, profile=%s, "
-                + "state=%d (expected %d), flags=0x%x (expected 0x%x)", device, profile, state,
-                BluetoothProfile.STATE_CONNECTED, firedFlags, mask));
+        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
+                methodName, state, BluetoothProfile.STATE_CONNECTED, firedFlags, mask));
     }
 
     /**
@@ -1016,29 +974,30 @@
      *
      * @param adapter The BT adapter.
      * @param device The remote device.
-     * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP} or
-     *        {@link BluetoothProfile#HEADSET}.
+     * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP},
+     * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#INPUT_DEVICE}.
+     * @param methodName The method name to printed in the logs.  If null, will be
+     * "connectProfile(profile=&lt;profile&gt;, device=&lt;device&gt;)"
      */
-    public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile) {
+    public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile,
+            String methodName) {
+        if (methodName == null) {
+            methodName = String.format("disconnectProfile(profile=%d, device=%s)", profile, device);
+        }
         int mask = (ConnectProfileReceiver.STATE_DISCONNECTING_FLAG
                 | ConnectProfileReceiver.STATE_DISCONNECTED_FLAG);
         long start = -1;
 
         if (!adapter.isEnabled()) {
-            fail(String.format("disconnectProfile() bluetooth not enabled: device=%s, profile=%d",
-                    device, profile));
+            fail(String.format("%s bluetooth not enabled", methodName));
         }
 
         if (!adapter.getBondedDevices().contains(device)) {
-            fail(String.format("disconnectProfile() device not paired: device=%s, profile=%d",
-                    device, profile));
+            fail(String.format("%s device not paired", methodName));
         }
 
         BluetoothProfile proxy = connectProxy(adapter, profile);
-        if (proxy == null) {
-            fail(String.format("disconnectProfile() unknown profile: device=%s, profile=%d",
-                    device, profile));
-        }
+        assertNotNull(proxy);
 
         ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask);
 
@@ -1057,8 +1016,7 @@
                 break;
             default:
                 removeReceiver(receiver);
-                fail(String.format("disconnectProfile() invalid state: device=%s, profile=%d, "
-                        + "state=%d", device, profile, state));
+                fail(String.format("%s invalid state: state=%d", methodName, state));
         }
 
         long s = System.currentTimeMillis();
@@ -1068,11 +1026,10 @@
                     && (receiver.getFiredFlags() & mask) == mask) {
                 long finish = receiver.getCompletedTime();
                 if (start != -1 && finish != -1) {
-                    writeOutput(String.format("disconnectProfile() completed in %d ms: "
-                            + "device=%s, profile=%d", (finish - start), device, profile));
+                    writeOutput(String.format("%s completed in %d ms", methodName,
+                            (finish - start)));
                 } else {
-                    writeOutput(String.format("disconnectProfile() completed: device=%s, "
-                            + "profile=%d", device, profile));
+                    writeOutput(String.format("%s completed", methodName));
                 }
                 removeReceiver(receiver);
                 return;
@@ -1082,9 +1039,8 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("disconnectProfile() timeout: device=%s, profile=%s, "
-                + "state=%d (expected %d), flags=0x%x (expected 0x%x)", device, profile, state,
-                BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask));
+        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
+                methodName, state, BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask));
     }
 
     /**
@@ -1125,25 +1081,25 @@
         String methodName;
 
         if (connect) {
-            methodName = "connectPan()";
-            mask = (ConnectPanReceiver.STATE_CONNECTED_FLAG |
-                    ConnectPanReceiver.STATE_CONNECTING_FLAG);
+            methodName = String.format("connectPan(device=%s)", device);
+            mask = (ConnectProfileReceiver.STATE_CONNECTED_FLAG |
+                    ConnectProfileReceiver.STATE_CONNECTING_FLAG);
             role = BluetoothPan.LOCAL_PANU_ROLE;
         } else {
-            methodName = "incomingPanConnection()";
-            mask = ConnectPanReceiver.STATE_CONNECTED_FLAG;
+            methodName = String.format("incomingPanConnection(device=%s)", device);
+            mask = ConnectProfileReceiver.STATE_CONNECTED_FLAG;
             role = BluetoothPan.LOCAL_NAP_ROLE;
         }
 
         if (!adapter.isEnabled()) {
-            fail(String.format("%s bluetooth not enabled: device=%s", methodName, device));
+            fail(String.format("%s bluetooth not enabled", methodName));
         }
 
         if (!adapter.getBondedDevices().contains(device)) {
-            fail(String.format("%s device not paired: device=%s", methodName, device));
+            fail(String.format("%s device not paired", methodName));
         }
 
-        if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
+        mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
         assertNotNull(mPan);
         ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
 
@@ -1165,8 +1121,7 @@
                 break;
             default:
                 removeReceiver(receiver);
-                fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
-                        state));
+                fail(String.format("%s invalid state: state=%d", methodName, state));
         }
 
         long s = System.currentTimeMillis();
@@ -1176,10 +1131,10 @@
                     && (receiver.getFiredFlags() & mask) == mask) {
                 long finish = receiver.getCompletedTime();
                 if (start != -1 && finish != -1) {
-                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
-                            (finish - start), device));
+                    writeOutput(String.format("%s completed in %d ms", methodName,
+                            (finish - start)));
                 } else {
-                    writeOutput(String.format("%s completed: device=%s", methodName, device));
+                    writeOutput(String.format("%s completed", methodName));
                 }
                 removeReceiver(receiver);
                 return;
@@ -1189,9 +1144,8 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
-                + "flags=0x%x (expected 0x%s)", methodName, device, state,
-                BluetoothPan.STATE_CONNECTED, firedFlags, mask));
+        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
+                methodName, state, BluetoothPan.STATE_CONNECTED, firedFlags, mask));
     }
 
     /**
@@ -1232,25 +1186,25 @@
         String methodName;
 
         if (disconnect) {
-            methodName = "disconnectPan()";
-            mask = (ConnectPanReceiver.STATE_DISCONNECTED_FLAG |
-                    ConnectPanReceiver.STATE_DISCONNECTING_FLAG);
+            methodName = String.format("disconnectPan(device=%s)", device);
+            mask = (ConnectProfileReceiver.STATE_DISCONNECTED_FLAG |
+                    ConnectProfileReceiver.STATE_DISCONNECTING_FLAG);
             role = BluetoothPan.LOCAL_PANU_ROLE;
         } else {
-            methodName = "incomingPanDisconnection()";
-            mask = ConnectPanReceiver.STATE_DISCONNECTED_FLAG;
+            methodName = String.format("incomingPanDisconnection(device=%s)", device);
+            mask = ConnectProfileReceiver.STATE_DISCONNECTED_FLAG;
             role = BluetoothPan.LOCAL_NAP_ROLE;
         }
 
         if (!adapter.isEnabled()) {
-            fail(String.format("%s bluetooth not enabled: device=%s", methodName, device));
+            fail(String.format("%s bluetooth not enabled", methodName));
         }
 
         if (!adapter.getBondedDevices().contains(device)) {
-            fail(String.format("%s device not paired: device=%s", methodName, device));
+            fail(String.format("%s device not paired", methodName));
         }
 
-        if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
+        mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
         assertNotNull(mPan);
         ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
 
@@ -1271,8 +1225,7 @@
                 break;
             default:
                 removeReceiver(receiver);
-                fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
-                        state));
+                fail(String.format("%s invalid state: state=%d", methodName, state));
         }
 
         long s = System.currentTimeMillis();
@@ -1282,10 +1235,10 @@
                     && (receiver.getFiredFlags() & mask) == mask) {
                 long finish = receiver.getCompletedTime();
                 if (start != -1 && finish != -1) {
-                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
-                            (finish - start), device));
+                    writeOutput(String.format("%s completed in %d ms", methodName,
+                            (finish - start)));
                 } else {
-                    writeOutput(String.format("%s completed: device=%s", methodName, device));
+                    writeOutput(String.format("%s completed", methodName));
                 }
                 removeReceiver(receiver);
                 return;
@@ -1295,9 +1248,8 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
-                + "flags=0x%x (expected 0x%s)", methodName, device, state,
-                BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
+        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
+                methodName, state, BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
     }
 
     /**
@@ -1335,29 +1287,26 @@
         String methodName;
 
         if (isStart) {
-            methodName = "startSco()";
+            methodName = String.format("startSco(device=%s)", device);
             mask = StartStopScoReceiver.STATE_CONNECTED_FLAG;
         } else {
-            methodName = "stopSco()";
+            methodName = String.format("stopSco(device=%s)", device);
             mask = StartStopScoReceiver.STATE_DISCONNECTED_FLAG;
         }
 
         if (!adapter.isEnabled()) {
-            fail(String.format("%s bluetooth not enabled: device=%s, start=%b", methodName, device,
-                    isStart));
+            fail(String.format("%s bluetooth not enabled", methodName));
         }
 
         if (!adapter.getBondedDevices().contains(device)) {
-            fail(String.format("%s device not paired: device=%s, start=%b", methodName, device,
-                    isStart));
+            fail(String.format("%s device not paired", methodName));
         }
 
         AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
         assertNotNull(manager);
 
         if (!manager.isBluetoothScoAvailableOffCall()) {
-            fail(String.format("%s device does not support SCO: device=%s, start=%b", methodName,
-                    device, isStart));
+            fail(String.format("%s device does not support SCO", methodName));
         }
 
         boolean isScoOn = manager.isBluetoothScoOn();
@@ -1376,8 +1325,7 @@
         long s = System.currentTimeMillis();
         while (System.currentTimeMillis() - s < START_STOP_SCO_TIMEOUT) {
             isScoOn = manager.isBluetoothScoOn();
-            if ((isStart == isScoOn) &&
-                    (receiver.getFiredFlags() & mask) == mask) {
+            if (isStart == isScoOn && (receiver.getFiredFlags() & mask) == mask) {
                 long finish = receiver.getCompletedTime();
                 if (start != -1 && finish != -1) {
                     writeOutput(String.format("%s completed in %d ms", methodName,
@@ -1393,7 +1341,7 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("%s timeout: start=%b (expected %b), flags=0x%x (expected 0x%x)",
+        fail(String.format("%s timeout: on=%b (expected %b), flags=0x%x (expected 0x%x)",
                 methodName, isScoOn, isStart, firedFlags, mask));
     }
 
@@ -1478,6 +1426,30 @@
     }
 
     private BluetoothProfile connectProxy(BluetoothAdapter adapter, int profile) {
+        switch (profile) {
+            case BluetoothProfile.A2DP:
+                if (mA2dp != null) {
+                    return mA2dp;
+                }
+                break;
+            case BluetoothProfile.HEADSET:
+                if (mHeadset != null) {
+                    return mHeadset;
+                }
+                break;
+            case BluetoothProfile.INPUT_DEVICE:
+                if (mInput != null) {
+                    return mInput;
+                }
+                break;
+            case BluetoothProfile.PAN:
+                if (mPan != null) {
+                    return mPan;
+                }
+                break;
+            default:
+                return null;
+        }
         adapter.getProfileProxy(mContext, mServiceListener, profile);
         long s = System.currentTimeMillis();
         switch (profile) {
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index fa588cb..46763c2 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -364,7 +364,7 @@
       <li class="toggle-list">
         <div><a href="<?cs var:toroot?>guide/market/billing/index.html">
             <span class="en">In-app Billing</span></a>
-          <span class="new">new!</span>
+          <span class="new">updated</span>
         </div>
         <ul>
           <li><a href="<?cs var:toroot?>guide/market/billing/billing_about.html">
@@ -698,6 +698,9 @@
       </li>
       </ul>
       <ul>
+      <li><a href="<?cs var:toroot ?>guide/practices/design/accessibility.html">
+            <span class="en">Designing for Accessibility</span>
+          </a> <span class="new">new!</span></li>
       <li><a href="<?cs var:toroot ?>guide/practices/design/performance.html">
             <span class="en">Designing for Performance</span>
           </a></li>
diff --git a/docs/html/guide/market/billing/billing_about.jd b/docs/html/guide/market/billing/billing_about.jd
index dac9738..ed45c19 100755
--- a/docs/html/guide/market/billing/billing_about.jd
+++ b/docs/html/guide/market/billing/billing_about.jd
@@ -3,12 +3,6 @@
 parent.link=index.html
 @jd:body
 
-<style type="text/css">
-  #jd-content {
-    background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
-  }
-</style>
-
 <div id="qv-wrapper">
 <div id="qv">
   <h2>In this document</h2>
@@ -31,15 +25,9 @@
 </div>
 </div>
 
-<div class="special" style="margin-right:345px">
-  <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
-</div>
+<p>The in-app billing release has now entered the testing phase. During this phase we are providing <a href="{@docRoot}guide/market/billing/index.html">documentation</a> and a <a href="{@docRoot}guide/market/billing/billing_integrate.html#billing-download">sample application</a> that shows you how to implement in-app billing. You can use these resources to start designing and testing your in-app billing implementations.</p>
 
-<p>This documentation gives you an early look at the Android Market In-app Billing service. We are providing this documentation to help you get started designing your in-app billing implementation. </p>
-
-<p>In addition to this documentation, we are providing a <a href="{@docRoot}guide/market/billing/billing_integrate.html#billing-download">sample application</a> that shows you how to implement in-app billing. Although you can compile the sample application, load it on a device, and run it, you cannot use it to make purchases at this time. In-app billing relies on version 2.3.0 (and higher) of the Android Market application, which may not be available yet.</p>
-
-<p>In the coming weeks we plan to launch the testing phase of the in-app billing release. Following the testing phase we will launch in-app billing to the general public (see table 1 for a summary of upcoming launch milestones).
+<p>Following the testing phase we will launch in-app billing to the general public (see table 1 for a summary launch milestones).
 
 <p class="table-caption"><strong>Table 1.</strong> Summary of launch milestones for in-app billing.</p>
 
@@ -47,29 +35,56 @@
 
 <tr>
 <th>Release Phase</th>
-<th>Android Market Application</th>
+<th>Status</th>
 <th>Description</th>
 </tr>
 <tr>
   <td>Early Development</td>
-  <td>Version 2.3.0 not available</td>
-  <td>Provides an early look at documentation and sample application.</td>
+  <td>Completed</td>
+  <td>Provided an early look at the documentation and the sample application.</td>
 </tr>
 <tr>
   <td>Test Development</td>
-  <td>Version 2.3.0 available to developers and users</td>
-  <td>In-app billing service allows static testing with reserved product IDs. You cannot publish applications that use in-app billing.</td>
+  <td>In process</td>
+  <td>You can perform static testing with reserved product IDs and end-to-end testing with real product IDs. You cannot publish applications that use in-app billing.</td>
 </tr>
 <tr>
   <td>Final Release</td>
-  <td>Version 2.3.0 available to developers and users</td>
-  <td>In-app billing service allows end-to-end testing of in-app billing. You can publish applications that use in-app billing.</td>
+  <td>Coming soon</td>
+  <td>You can perform static testing with reserved product IDs and end-to-end testing with real product IDs. You can publish applications that use in-app billing.</td>
 </tr>
 
 </table>
 
-<p>During the testing phase we will release version 2.3.0 of the Android Market application. This will allow you to test your in-app billing implementation using the <a href="{@docRoot}guide/market/billing/billing_testing.html#billing-testing-static">reserved product IDs and test responses</a>. However, you will not be able to test end-to-end in-app purchases during the testing phase, and you will not be able to publish an application that uses in in-app billing. </p>
+<p>During the testing phase we are releasing version 2.3.4 of the Android Market application and version 5.0.12 of the MyApps application. To support in-app billing, devices running Android 3.0 must have version 5.0.12 (or higher) of the MyApps application. Devices running all other versions of Android must have version 2.3.4 (or higher) of the Android Market application. Table 2 summarizes these requirements.</p>
 
-<p>After the testing phase is complete, we will release in-app billing to the general public. This will enable you to perform end-to-end tests of your in-app billing implementation using your actual in-app products. You will also be able to publish applications that use in-app billing.</p>
+<p class="table-caption"><strong>Table 2.</strong> Summary of in-app billing requirements.</p>
 
-<p>This documentation may change in the coming weeks as we move from the preview phase to the testing phase of this beta release. Be sure to check this documentation frequently for updates.</p>
\ No newline at end of file
+<table>
+
+<tr>
+<th>If your device is running this...</th>
+<th>In-app billing requires this</th>
+</tr>
+<tr>
+  <td>Android 1.6</td>
+  <td>Android Market 2.3.4 (or higher)</td>
+</tr>
+<tr>
+  <td>Android 2.x</td>
+  <td>Android Market 2.3.4 (or higher)</td>
+</tr>
+<tr>
+  <td>Android 3.0</td>
+  <td>MyApps 5.0.12 (or higher)</td>
+</tr>
+
+</table>
+
+<p class="note"><strong>Note:</strong> To learn how to check the version of the Android Market application, see <a href="http://market.android.com/support/bin/answer.py?answer=190860">Updating Android Market</a>. To learn about other requirements for in-app billing, see <a href="{@docRoot}guide/market/billing/billing_overview.html#billing-limitations">Requirements and Limitations.</a></p>
+
+<p>You can test your in-app billing implementation two ways during the testing phase: you can use the <a href="{@docRoot}guide/market/billing/billing_testing.html#billing-testing-static">reserved product IDs</a> to test static responses or you can use <a href="{@docRoot}guide/market/billing/billing_testing.html#billing-testing-real">your own product IDs</a> to test end-to-end in-app purchases. To perform end-to-end testing you need to upload your application as a draft application and add products to the application's product list.</p>
+
+<p>During the testing phase, you cannot publish applications that use in-app billing; you can only upload the applications as draft applications. After the testing phase is complete, we will launch in-app billing to the general public and you will be able to publish applications that use in-app billing.</p>
+
+<p>This documentation may change as we move from the testing phase to the final release. Be sure to check this documentation frequently for updates.</p>
diff --git a/docs/html/guide/market/billing/billing_admin.jd b/docs/html/guide/market/billing/billing_admin.jd
index cd8f960..16a2a36 100755
--- a/docs/html/guide/market/billing/billing_admin.jd
+++ b/docs/html/guide/market/billing/billing_admin.jd
@@ -3,12 +3,6 @@
 parent.link=index.html
 @jd:body
 
-<style type="text/css">
-  #jd-content {
-    background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
-  }
-</style>
-
 <div id="qv-wrapper">
 <div id="qv">
   <h2>In this document</h2>
@@ -35,25 +29,32 @@
 </div>
 
 <div class="special" style="margin-right:345px">
-  <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
+  <p>During the testing phase of the in-app billing release you cannot publish applications that implement in-app billing. You can only upload in-app billing applications as draft applications. For more information, see <a href="{@docRoot}guide/market/billing/billing_about.html">About this Release</a></p>
 </div>
 
 <p>In-app billing frees you from processing financial transactions, but you still need to perform a few administrative tasks, including setting up and maintaining your product list on the publisher site, registering test accounts, and handling refunds when necessary.</p>
 
-<p>You must have an Android Market publisher account to set up a product list and register test accounts. And you must have a Google Checkout merchant account to issue refunds to your users. If you already have a publisher account on Android Market, you can use your existing account. You do not need to register for a new account to support in-app billing. If you do not have a publisher account, you can register as an Android Market developer and set up a publisher account at the Android Market <a href="http://market.android.com/publish">publisher site</a>. If you do not have a Google Checkout merchant account, you can register for one at the <a href="http://checkout.google.com">Google Checkout site</a>.</p>
+<p>You must have an Android Market publisher account to register test accounts. And you must have a Google Checkout Merchant account to create a product list and issue refunds to your users. If you already have a publisher account on Android Market, you can use your existing account. You do not need to register for a new account to support in-app billing. If you do not have a publisher account, you can register as an Android Market developer and set up a publisher account at the Android Market <a href="http://market.android.com/publish">publisher site</a>. If you do not have a Google Checkout Merchant account, you can register for one at the <a href="http://checkout.google.com">Google Checkout site</a>.</p>
 
 <h2 id="billing-list-setup">Creating a Product List</h2>
 
 <p>The Android Market publisher site provides a product list for each of your published applications. You can sell an item using the in-app billing feature only if the item is listed on an application's product list. Each application has its own product list; you cannot sell items that are listed in another application's product list.</p>
 
-<p>A product list contains information about the items you are selling, such as a product id, product description, and price (see figure 1). The product list stores only metadata about the items you are selling in your application. It does not store any digital content. You are responsible for storing and delivering the digital content that you sell in your applications.</p>
+<p>You can access an application's product list by clicking the <strong>In-App Products</strong> link that appears under each of the applications that are listed for your publisher account (see figure 1). The <strong>In-App Products</strong> link appears only if you have a Google Checkout Merchant account and an application's manifest includes the <code>com.android.vending.BILLING</code> permission.</p>
 
-<div style="margin-bottom:2em;">
-<img src="{@docRoot}images/billing_product_list.png" style="text-align:left;margin-bottom:0;" />
-<div style="margin:0 2em;padding:0"><strong>Figure 1.</strong> An application's product list.</div>
-</div>
+<img src="{@docRoot}images/billing_product_list_entry.png" height="540" id="figure1" />
+<p class="img-caption">
+  <strong>Figure 1.</strong> You can access an application's product list by clicking the <strong>In-App Products</strong> link.
+</p>
 
-<p>You can create a product list for a published application or a draft application that's been uploaded and saved to the Android Market site. However, the application's manifest must include the com.android.vending.BILLING permission. If an application's manifest does not include this permission, you will be able to edit existing items in the product list but you will not be able to add new items to the list. For more information, see <a href="#billing-permission">Modifying your application's AndroidManifest.xml file</a>.</p>
+<p>A product list contains information about the items you are selling, such as a product id, product description, and price (see figure 2). The product list stores only metadata about the items you are selling in your application. It does not store any digital content. You are responsible for storing and delivering the digital content that you sell in your applications.</p>
+
+<img src="{@docRoot}images/billing_product_list.png" height="742" id="figure2" />
+<p class="img-caption">
+  <strong>Figure 2.</strong> An application's product list.
+</p>
+
+<p>You can create a product list for a published application or a draft application that's been uploaded and saved to the Android Market site. However, you must have a Google Checkout Merchant account and the application's manifest must include the <code>com.android.vending.BILLING</code> permission. If an application's manifest does not include this permission, you will be able to edit existing items in the product list but you will not be able to add new items to the list. For more information, see <a href="#billing-permission">Modifying your application's AndroidManifest.xml file</a>.</p>
 
 <p>To create a product list for an application, follow these steps:</p>
 
@@ -61,13 +62,13 @@
   <li><a href="http://market.android.com/publish">Log in</a> to your publisher account.</li>
   <li>In the <strong>All Android Market listings</strong> panel, under the application name, click <strong>In-app Products</strong>.</li>
   <li>On the In-app Products List page, click <strong>Add in-app product</strong>.</li>
-  <li>On the Create New In-app Product page (see figure 2), provide details about the item you are selling and then click <strong>Save</strong>.</li>
+  <li>On the Create New In-app Product page (see figure 3), provide details about the item you are selling and then click <strong>Save</strong>.</li>
 </ol>
 
-<div style="margin-bottom:2em;">
-<img src="{@docRoot}images/billing_list_form.png" style="text-align:left;margin-bottom:0;" />
-<div style="margin:0 2em;padding:0"><strong>Figure 2.</strong> The Create New In-app Product page lets you add items to an application's product list.</div>
-</div>
+<img src="{@docRoot}images/billing_list_form.png" height="854" id="figure3" />
+<p class="img-caption">
+  f<strong>Figure 3.</strong> The Create New In-app Product page lets you add items to an application's product list.
+</p>
 
 <p>You must enter the following information for each item in a product list:</p>
 <ul>
@@ -79,23 +80,26 @@
     <p>The purchase type can be "managed per user account" or "unmanaged." You can specify an item's purchase type only through the publisher site and you can never change an item's purchase type once you specify it. For more information, see <a href="#billing_purchase_type">Choosing a purchase type</a> later in this document.</p>
   </li>
   <li><strong>Publishing State</strong>
-    <p>An item's publishing state can be "published" or "unpublished." However, to be visible to a user during checkout, an item's publishing state must be set to "published" and the item's application must be published on Android Market. (Note: This is not true for test accounts: that is, an item is visible to a trusted tester if the application is not published and the item is published. See <a href="{@docRoot}guide/market/billing/billing_testing.html#billing-testing-real">Testing In-app Billing</a> for more information.)</p>
+    <p>An item's publishing state can be "published" or "unpublished." However, to be visible to a user during checkout, an item's publishing state must be set to "published" and the item's application must be published on Android Market.</p>
+    <p class="note"><strong>Note:</strong> This is not true for test accounts. An item is visible to a test account if the application is not published and the item is published. See <a href="{@docRoot}guide/market/billing/billing_testing.html#billing-testing-real">Testing In-app Billing</a> for more information.</p>
   </li>
   <li><strong>Language</strong>
     <p>A product list inherits its language from the parent application.</p>
   </li>
   <li><strong>Title</strong>
-    <p>The title is a short descriptor for the item. For example, "sleeping potion." Titles must be unique across an application's namespace. Every item must have a title. The title is visible to users during checkout.</p>
+    <p>The title is a short descriptor for the item. For example, "Sleeping potion." Titles must be unique across an application's namespace. Every item must have a title. The title is visible to users during checkout. For optimum appearance, titles should be no longer than 25 characters; however, titles can be up to 55 characters in length.</p>
   </li>
   <li><strong>Description</strong>
-    <p>The description is a long descriptor for the item. For example, "Instantly puts creatures to sleep. Does not work on angry elves." Every item must have a description. The description is visible to users during checkout.</p>
+    <p>The description is a long descriptor for the item. For example, "Instantly puts creatures to sleep. Does not work on angry elves." Every item must have a description. The description is visible to users during checkout. Descriptions can be up to 80 characters in length.</p>
   </li>
   <li><strong>Price</strong>
-    <p>Every item must have a price greater than zero; you cannot sell free items.</p>
+    <p>Every item must have a price greater than zero; you cannot set a price of "0" (free).</p>
   </li>
 </ul>
 
-<p class="note"><strong>Note</strong>: Be sure to plan your product ID namespace. You cannot reuse or modify product IDs after you save them.</p> 
+<p>For more information about product IDs and product lists, see <a href="http://market.android.com/support/bin/answer.py?answer=1072599">Creating In-App Product IDs</a>. For more information about pricing, see <a href="http://market.android.com/support/bin/answer.py?answer=1153485">In-App Billing Pricing</a>.</p>
+
+<p class="note"><strong>Note</strong>: Be sure to plan your product ID namespace. You cannot reuse or modify product IDs after you save them.</p>
 
 <h3 id="billing-purchase-type">Choosing a Purchase Type</h3>
 
@@ -113,7 +117,7 @@
 
 <h2 id="billing-refunds">Handling Refunds</h2>
 
-<p>The in-app billing feature does not allow users to send a refund request to Android Market. Refunds for purchases that were made with the in-app billing feature must be directed to you (the application developer). You can then process the refund through your Google Checkout merchant account. When you do this, Android Market receives a refund notification from Google Checkout, and Android Market sends a refund message to your application. Your application can handle this message the same way it handles the response from an application-initiated <code>REQUEST_PURCHASE</code> message so that ultimately your application receives a purchase state change message that includes information about the item that's been refunded.</p>
+<p>The in-app billing feature does not allow users to send a refund request to Android Market. Refunds for purchases that were made with the in-app billing feature must be directed to you (the application developer). You can then process the refund through your Google Checkout Merchant account. When you do this, Android Market receives a refund notification from Google Checkout, and Android Market sends a refund message to your application. For more information, see <a href="{@docRoot}guide/market/billing/billing_overview.html#billing-action-notify">Handling IN_APP_NOTIFY messages</a> and <a href="http://www.google.com/support/androidmarket/bin/answer.py?answer=1153485">In-app Billing Pricing</a>.</p>
 
 <h2 id="billing-testing-setup">Setting Up Test Accounts</h2>
 
@@ -134,16 +138,15 @@
 <ol>
   <li><a href="http://market.android.com/publish">Log in</a> to your publisher account.</li>
   <li>On the upper left part of the page, under your name, click <strong>Edit profile</strong>.</li>
-  <li>On the Edit Profile page, scroll down to the Licensing &amp; In-app Billing panel (see figure 3).</li>
+  <li>On the Edit Profile page, scroll down to the Licensing &amp; In-app Billing panel (see figure 4).</li>
   <li>In Test Accounts, add the email addresses for the test accounts you want to register, separating each account with a comma.</li>
   <li>Click <strong>Save</strong> to save your profile changes.</li>
 </ol>
 
-<div style="margin-bottom:2em;">
-<img src="{@docRoot}images/billing_public_key.png" style="text-align:left;margin-bottom:0;" />
-<div style="margin:0 2em;padding:0"><strong>Figure 3.</strong> The Licensing and In-app Billing
-panel of your account's Edit Profile page lets you register test accounts.</div>
-</div>
+<img src="{@docRoot}images/billing_public_key.png" height="510" id="figure4" />
+<p class="img-caption">
+  <strong>Figure 4.</strong> The Licensing and In-app Billing panel of your account's Edit Profile page lets you register test accounts.
+</p>
 
 <h2 id="billing-support">Where to Get Support</h2>
 
diff --git a/docs/html/guide/market/billing/billing_best_practices.jd b/docs/html/guide/market/billing/billing_best_practices.jd
index 4743e88..a505de4 100755
--- a/docs/html/guide/market/billing/billing_best_practices.jd
+++ b/docs/html/guide/market/billing/billing_best_practices.jd
@@ -3,12 +3,6 @@
 parent.link=index.html
 @jd:body
 
-<style type="text/css">
-  #jd-content {
-    background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
-  }
-</style>
-
 <div id="qv-wrapper">
 <div id="qv">
   <h2>In this document</h2>
@@ -31,9 +25,10 @@
 </div>
 
 <div class="special" style="margin-right:345px">
-  <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
+  <p>During the testing phase of the in-app billing release you cannot publish applications that implement in-app billing. You can only upload in-app billing applications as draft applications. For more information, see <a href="{@docRoot}guide/market/billing/billing_about.html">About this Release</a></p>
 </div>
-<p>As you design your in-app billing implementation, be sure to follow the security and design guidelines that are discussed in this document. These guidelines are recommended best practices for anyone who is using the Android Market In-app Billing service and can be incorporated into any in-app billing implementation.</p>
+
+<p>As you design your in-app billing implementation, be sure to follow the security and design guidelines that are discussed in this document. These guidelines are recommended best practices for anyone who is using the Android Market in-app billing service and can be incorporated into any in-app billing implementation.</p>
 
 <h2>Security Best Practices</h2>
 
@@ -58,7 +53,7 @@
 </ul>
 <p>Using these techniques can help reduce the attack surface of your application and help minimize attacks that can compromise your in-app billing implementation.</p>
 <div class="note">
-  <p><strong>Note:</strong> If you use Proguard to obfuscate your code, you must add the following line to your Proguard configuration file:</p>    
+  <p><strong>Note:</strong> If you use Proguard to obfuscate your code, you must add the following line to your Proguard configuration file:</p>
   <p><code>-keep class com.android.vending.billing.**</code></p>
 </div>
   
diff --git a/docs/html/guide/market/billing/billing_integrate.jd b/docs/html/guide/market/billing/billing_integrate.jd
index 0cac2eb..d027686 100755
--- a/docs/html/guide/market/billing/billing_integrate.jd
+++ b/docs/html/guide/market/billing/billing_integrate.jd
@@ -3,12 +3,6 @@
 parent.link=index.html
 @jd:body
 
-<style type="text/css">
-  #jd-content {
-    background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
-  }
-</style>
-
 <div id="qv-wrapper">
 <div id="qv">
   <h2>In this document</h2>
@@ -16,7 +10,7 @@
     <li><a href="#billing-download">Downloading the Sample Application</a></li>
     <li><a href="#billing-add-aidl">Adding the AIDL file to your project</a></li>
     <li><a href="#billing-permission">Updating Your Application's Manifest</a></li>
-    <li><a href="#billing-service">Creating a Service</a></li>  
+    <li><a href="#billing-service">Creating a Service</a></li>
     <li><a href="#billing-broadcast-receiver">Creating a BroadcastReceiver</a></li>
     <li><a href="#billing-signatures">Creating a security processing component</a></li>
     <li><a href="#billing-implement">Modifying Your Application Code</a></li>
@@ -37,10 +31,10 @@
 </div>
 
 <div class="special" style="margin-right:345px">
-  <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
+  <p>During the testing phase of the in-app billing release you cannot publish applications that implement in-app billing. You can only upload in-app billing applications as draft applications. For more information, see <a href="{@docRoot}guide/market/billing/billing_about.html">About this Release</a></p>
 </div>
 
-<p>The Android Market In-app Billing service provides a straightforward, simple interface for sending in-app billing requests and managing in-app billing transactions using Android Market. This document helps you implement in-app billing by stepping through the primary implementation tasks, using the in-app billing sample application as an example.</p>
+<p>The Android Market in-app billing service provides a straightforward, simple interface for sending in-app billing requests and managing in-app billing transactions using Android Market. This document helps you implement in-app billing by stepping through the primary implementation tasks, using the in-app billing sample application as an example.</p>
 
 <p>Before you implement in-app billing in your own application, be sure that you read <a href="{@docRoot}guide/market/billing/billing_overview.html">Overview of In-app Billing</a> and <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a>. These documents provide background information that will make it easier for you to implement in-app billing.</p>
 
@@ -67,7 +61,7 @@
   <li>Creating a user interface that lets users select items for purchase.</li>
 </ul>
 
-<p>The sample application includes an application file (<code><code>Dungeons.java</code></code>), the AIDL file for the <code>MarketBillingService</code> (<code>IMarketBillingService.aidl</code>), and several classes that demonstrate in-app billing messaging. It also includes a class that demonstrates basic security tasks, such as signature verification.</p>
+<p>The sample application includes an application file (<code>Dungeons.java</code>), the AIDL file for the <code>MarketBillingService</code> (<code>IMarketBillingService.aidl</code>), and several classes that demonstrate in-app billing messaging. It also includes a class that demonstrates basic security tasks, such as signature verification.</p>
 
 <p>Table 1 lists the source files that are included with the sample application.</p>
 <p class="table-caption" id="source-files-table"><strong>Table 1.</strong>
@@ -86,7 +80,7 @@
 
 <tr>
 <td>Dungeons.java</td>
-<td>Sample application file that provides a UI for making purchases and diplaying purchase history.</td>
+<td>Sample application file that provides a UI for making purchases and displaying purchase history.</td>
 </tr>
 
 <tr>
@@ -130,19 +124,101 @@
 
 </table>
 
-<p>The in-app billing sample application is available as a downloadable component of the Android SDK. To download the sample application component, launch the Android SDK and AVD Manager and then select the "Market Billing package, revision 1" component (see figure 1), and click <strong>Install Selected</strong> to begin the download.</p>
+<p>The in-app billing sample application is available as a downloadable component of the Android SDK. To download the sample application component, launch the Android SDK and AVD Manager and then select the "Google Market Billing package" component (see figure 1), and click <strong>Install Selected</strong> to begin the download.</p>
 
 <div style="margin-bottom:2em;">
 
-<img src="{@docRoot}images/billing_package.png" style="text-align:left;margin-bottom:0;" />
-<div style="margin:0 2em;padding:0"><strong>Figure 1.</strong> The Google Market
-Billing package contains the sample application and the AIDL file. </div>
-</div>
+<img src="{@docRoot}images/billing_package.png" height="325" id="figure1" />
+<p class="img-caption">
+  <strong>Figure 1.</strong> The Google Market Billing package contains the sample application and the AIDL file.
+</p>
 
 <p>When the download is complete, the Android SDK and AVD Manager saves the component into the following directory:</p>
 
 <p><code>&lt;sdk&gt;/google-market_billing/</code></p>
 
+<p>If you want to see an end-to-end demonstration of in-app billing before you integrate in-app billing into your own application, you can build and run the sample application. Building and running the sample application involves three tasks:<p>
+
+<ul>
+  <li>Configuring and building the sample application.</li>
+  <li>Uploading the sample application to Android Market.</li>
+  <li>Setting up test accounts and running the sample application</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> Building and running the sample application is necessary only if you want to see a demonstration of in-app billing. If you do not want to run the sample application, you can skip to the next section, <a href="#billing-add-aidl">Adding the AIDL file to your project</a>.</p>
+
+<h3>Configuring and building the sample application</h3>
+
+<p>Before you can run the sample application, you need to configure it and build it by doing the following:</p>
+
+<ol>
+  <li><strong>Add your Android Market public key to the sample application code.</strong>
+    <p>This enables the application to verify the signature of the transaction information that is returned from Android Market. To add your public key to the sample application code, do the following:</p>
+    <ol>
+      <li>Log in to your Android Market <a href="http://market.android.com/publish">publisher account</a>.</li>
+      <li>On the upper left part of the page, under your name, click <strong>Edit Profile</strong>.</li>
+      <li>On the Edit Profile page, scroll down to the <strong>Licensing &amp; In-app Billing</strong> panel.</li>
+      <li>Copy your public key.</li>
+      <li>Open <code>src/com/example/dungeons/Security.java</code> in the editor of your choice.
+        <p>You can find this file in the sample application's project folder.</p>
+      </li>
+      <li>Add your public key to the following line of code:
+        <p><code>String base64EncodedPublicKey = "your public key here";</code></p>
+      </li>
+      <li>Save the file.</li>
+    </ol>
+  </li>
+  <li><strong>Change the package name of the sample application.</strong>
+    <p>The current package name is <code>com.example.dungeons</code>. Android Market does not let you upload applications with package names that contain <code>com.example</code>, so you must change the package name to something else.</p>
+  </li>
+  <li><strong>Build the sample application in release mode and sign it.</strong>
+    <p>To learn how to build and sign applications, see <a href="{@docRoot}guide/developing/building/index.html">Building and Running</a>.</p>
+  </li>
+</ol>
+
+<h3>Uploading the sample application</h3>
+
+<p>After you build a release version of the sample application and sign it, you need to upload it as a draft to the Android Market publisher site. You also need to create a product list for the in-app items that are available for purchase in the sample application. The following instructions show you how to do this.</p>
+<ol>
+  <li><strong>Upload the release version of the sample application to Android Market.</strong>
+    <p>Do not publish the sample application; leave it as an unpublished draft application. The sample application is for demonstration purposes only and should not be made publicly available on Android Market. To learn how to upload an application to Android Market, see <a href="http://market.android.com/support/bin/answer.py?answer=113469">Uploading applications</a>.</p>
+  </li>
+  <li><strong>Create a product list for the sample application.</strong>
+    <p>The sample application lets you purchase two items: a two-handed sword (<code>sword_001</code>) and a potion (<code>potion_001</code>). We recommend that you set up your product list so that <code>sword_001</code> has a purchase type of "Managed per user account" and <code>potion_001</code> has a purchase type of "Unmanaged" so you can see how these two purchase types behave. To learn how to set up a product list, see <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-list-setup">Creating a Product List</a>.</p>
+    <p class="note"><strong>Note:</strong> You must publish the items in your product list (<code>sword_001</code> and <code>potion_001</code>) even though you are not publishing the sample application. Also, you must have a Google Checkout Merchant account to add items to the sample application's product list.</p>
+  </li>
+</ol>
+
+<h3>Running the sample application</h3>
+
+<p>You cannot run the sample application in the emulator. You must install the sample application onto a device to run it. To run the sample application, do the following:</p>
+
+<ol>
+  <li><strong>Make sure you have at least one test account registered under your Android Market publisher account.</strong>
+    <p>You cannot purchase items from yourself (Google Checkout prohibits this), so you need to create at least one test account that you can use to purchase items in the sample application. To learn how to set up a test account, see <a href="{@docRoot}guide/market/billing/billing_testing.html#billing-testing-setup">Setting up Test Accounts</a>.</p>
+  </li>
+  <li><strong>Verify that your device is running a supported version of the Android Market application or the MyApps application.</strong>
+    <p>If your device is running Android 3.0, in-app billing requires version 5.0.12 (or higher) of the MyApps application. If your device is running any other version of Android, in-app billing requires version 2.3.4 (or higher) of the Android Market application. To learn how to check the version of the Android Market application, see <a href="http://market.android.com/support/bin/answer.py?answer=190860">Updating Android Market</a>.</p>
+  </li>
+  <li><strong>Install the application onto your device.</strong>
+    <p>Even though you uploaded the application to Android Market, the application is not published, so you cannot download it from Android Market to a device. Instead, you must install the application onto your device. To learn how to install an application onto a device, see <a href="{@docRoot}guide/developing/building/building-cmdline.html#RunningOnDevice">Running on a device</a>.</p>
+ </li>
+ <li><strong>Make one of your test accounts the primary account on your device.</strong>
+    <p>The primary account on your device must be one of the <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-testing-setup">test accounts</a> that you registered on the Android Market site. If the primary account on your device is not a test account, you must do a factory reset of the device and then sign in with one of your test accounts. To perform a factory reset, do the following:</p>
+    <ol>
+      <li>Open Settings on your device.</li>
+      <li>Touch <strong>Privacy</strong>.</li>
+      <li>Touch <strong>Factory data reset</strong>.</li>
+      <li>Touch <strong>Reset phone</strong>.</li>
+      <li>After the phone resets, be sure to sign in with one of your test accounts during the device setup process.</li>
+    </ol>
+  </li>
+  <li><strong>Run the application and purchase the sword or the potion.</strong>
+    <p>When you use a test account to purchase items, the test account is billed through Google Checkout and your Google Checkout Merchant account receives a payout for the purchase. Therefore, you may want to refund purchases that are made with test accounts, otherwise the purchases will show up as actual payouts to your merchant account.</p>
+</ol>
+
+<p class="note"><strong>Note</strong>: Debug log messages are turned off by default in the sample application. You can turn them on by setting the variable <code>DEBUG</code> to <code>true</code> in the <code>Consts.java</code> file.</p>
+
 <h2 id="billing-add-aidl">Adding the AIDL file to your project</h2>
 
 <p>The sample application contains an Android Interface Definition Language (AIDL) file,  which defines the interface to the Android Market in-app billing service <code>MarketBillingService</code>). When you add this file to your project, the Android build environment creates an interface file (<code>IMarketBillingService.java</code>). You can then use this interface to make billing requests by invoking IPC method calls.</p>
@@ -159,15 +235,15 @@
   <li>Build your application.</li>
 </ol>
 
-<p>You should now find a generated interface file named <code><code>IMarketBillingService.java</code></code> in the <code>gen</code> folder of your project.</p>
+<p>You should now find a generated interface file named <code>IMarketBillingService.java</code> in the <code>gen</code> folder of your project.</p>
 
 <h2 id="billing-permission">Updating Your Application's Manifest</h2>
 
 <p>In-app billing relies on the Android Market application, which handles all communication between your application and the Android Market server. To use the Android Market application, your application must request the proper permission. You can do this by adding the <code>com.android.vending.BILLING</code> permission to your AndroidManifest.xml file. If your application does not declare the in-app billing permission, but attempts to send billing requests, Android Market will refuse the requests and respond with a <code>RESULT_DEVELOPER_ERROR</code> response code.</p>
 
-<p>In addition to the billing permission, you need to declare the {@link android.content.BroadcastReceiver} that you will use to receive asynchronous response messages (broadcast intents) from Android Market, and you need to declare the {@link android.app.Service} that you will use to bind with the <code>IMarketBillingService</code> and send messages to Android Market. You must also declare <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">intent filters</a> for the {@link android.content.BroadcastReceiver} so that the Android system knows how to handle broadcast intents that are sent from the Android Market application.</p>
+<p>In addition to the billing permission, you need to declare the {@link android.content.BroadcastReceiver} that you will use to receive asynchronous response messages (broadcast intents) from Android Market, and you need to declare the {@link android.app.Service} that you will use to bind with the <code>IMarketBillingService</code> and send messages to Android Market. You must also declare <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">intent filters</a> for the {@link android.content.BroadcastReceiver} so that the Android system knows how to handle the broadcast intents that are sent from the Android Market application.</p>
 
-<p>For example, here's how the in-app billing sample application declares the billing permission, the {@link android.content.BroadcastReceiver}, the {@link android.app.Service}, and the intent filters. In the sample application, <code>BillingReceiver</code> is the {@link android.content.BroadcastReceiver} that handles broadcast intents from the Android Market application and <code>BillingService</code> is the {@link android.app.Service} that sends requests to the Android Market application.</p>
+<p>For example, here is how the in-app billing sample application declares the billing permission, the {@link android.content.BroadcastReceiver}, the {@link android.app.Service}, and the intent filters. In the sample application, <code>BillingReceiver</code> is the {@link android.content.BroadcastReceiver} that handles broadcast intents from the Android Market application and <code>BillingService</code> is the {@link android.app.Service} that sends requests to the Android Market application.</p>
 
 <pre>
 &lt;?xml version="1.0" encoding="utf-8"?&gt;
@@ -236,7 +312,7 @@
 }
 </pre>
 
-<p>After you bind to the service, you need to create a reference to the <code>IMarketBillingService</code> interface so you can make billing requests via IPC method calls. The following code shows you how to do this using the {@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback method.</p> 
+<p>After you bind to the service, you need to create a reference to the <code>IMarketBillingService</code> interface so you can make billing requests via IPC method calls. The following code shows you how to do this using the {@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback method.</p>
 
 <pre>
 /**
@@ -265,7 +341,7 @@
   <li><code>RESTORE_TRANSACTIONS</code>&mdash;retrieves a user's transaction history for <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-purchase-type">managed purchases</a>.</li>
 </ul>
 
-<p>To make any of these billing requests, you first need to build an initial Bundle that contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The following code sample shows you how to create a helper method named <code>makeRequestBundle()</code> that does this.</p>
+<p>To make any of these billing requests, you first need to build an initial {@link android.os.Bundle} that contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The following code sample shows you how to create a helper method named <code>makeRequestBundle()</code> that does this.</p>
 
 <pre>
 protected Bundle makeRequestBundle(String method) {
@@ -296,13 +372,17 @@
 <p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The request returns a synchronous {@link android.os.Bundle} response, which contains only a single key: <code>RESPONSE_CODE</code>. The <code>RESPONSE_CODE</code> key can have the following values:</p>
 <ul>
   <li><code>RESULT_OK</code>&mdash;in-app billing is supported.</li>
-  <li><code>RESULT_BILLING_UNAVAILABLE</code>&mdash;in-app billing is not supported or the in-app billing API version you specified is not recognized.</li>
-  <li><code>RESULT_ERROR</code>&mdash;there was an error connecting with the Android Market appliction.</li>
-  <li><code>RESULT_DEVELOPER_ERROR</code>&mdash;the application is trying to make an in-app billing request but the application has not declared the com.android.vending.BILLING permission in its manifest. Can also indicate that an application is not properly signed, or that you sent a malformed request.</li>
+  <li><code>RESULT_BILLING_UNAVAILABLE</code>&mdash;in-app billing is not available because the in-app billing API version you specified is not recognized or the user is not eligible to make in-app purchases (for example, the user resides in a country that prohibits in-app purchases).</li>
+  <li><code>RESULT_ERROR</code>&mdash;there was an error connecting with the Android Market application.</li>
+  <li><code>RESULT_DEVELOPER_ERROR</code>&mdash;the application is trying to make an in-app billing request but the application has not declared the <code>com.android.vending.BILLING</code> permission in its manifest. Can also indicate that an application is not properly signed, or that you sent a malformed request.</li>
 </ul>
 
 <p>The <code>CHECK_BILLING_SUPPORTED</code> request does not trigger any asynchronous responses (broadcast intents).</p>
 
+<p>We recommend that you invoke the <code>CHECK_BILLING_SUPPORTED</code> request within a <code>RemoteException</code> block. When your code throws a <code>RemoteException</code> it indicates that the remote method call failed, which means that the Android Market application is out of date and needs to be updated. In this case, you can provide users with an error message that contains a link to the <a href="http://market.android.com/support/bin/answer.py?answer=190860">Updating Android Market</a> Help topic.</p>
+
+<p>The sample application demonstrates how you can handle this error condition (see <code>DIALOG_CANNOT_CONNECT_ID</code> in <code>Dungeons.java</code>).</p>
+
 <h4>Making a purchase request (REQUEST_PURCHASE)</h4>
 
 <p>To make a purchase request you must do the following:</p>
@@ -336,7 +416,7 @@
 
 <h5>Launching the pending intent</h5>
 
-<p>How you use the pending intent depends on which version of Android a device is running. On Android 1.6, you must use the pending intent to launch the checkout UI in its own separate task instead of your application's activity stack. On Android 2.0 and higher, you can use the pending intent to launch the checkout UI on your application's activity stack. The following code shows you how to do this. You can find this code in the PurchaseObserver.java file in the sample application.</p> 
+<p>How you use the pending intent depends on which version of Android a device is running. On Android 1.6, you must use the pending intent to launch the checkout UI in its own separate task instead of your application's activity stack. On Android 2.0 and higher, you can use the pending intent to launch the checkout UI on your application's activity stack. The following code shows you how to do this. You can find this code in the <code>PurchaseObserver.java</code> file in the sample application.</p>
 
 <pre>
 void startBuyPageActivity(PendingIntent pendingIntent, Intent intent) {
@@ -369,17 +449,17 @@
 }
 </pre>
 
-<p class="note">You must launch the pending intent from an activity context and not an application context.</p>
+<p class="caution"><strong>Important:</strong> You must launch the pending intent from an activity context and not an application context. Also, you cannot use the <code>singleTop</code> <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">launch mode</a> to launch the pending intent. If you do either of these, the Android system will not attach the pending intent to your application process. Instead, it will bring Android Market to the foreground, disrupting your application.</p>
 
 <h5>Handling broadcast intents</h5>
 
-<p>A <code>REQUEST_PURCHASE</code> request also triggers two asynchronous responses (broadcast intents). First, the Android Market application sends an <code>ACTION_RESPONSE_CODE</code> broadcast intent, which provides error information about the request. Next, if the request was successful, the Android Market application sends an <code>ACTION_NOTIFY</code> broadcast intent. This message contains a notification ID, which you can use to retrieve the transaction details for the <code>REQUEST_PURCHASE</code> request.</p>
+<p>A <code>REQUEST_PURCHASE</code> request also triggers two asynchronous responses (broadcast intents). First, the Android Market application sends a <code>RESPONSE_CODE</code> broadcast intent, which provides error information about the request. Next, if the request was successful, the Android Market application sends an <code>IN_APP_NOTIFY</code> broadcast intent. This message contains a notification ID, which you can use to retrieve the transaction details for the <code>REQUEST_PURCHASE</code> request.</p>
 
-<p>Keep in mind, the Android Market application also sends an <code>ACTION_NOTIFY</code> for refunds. For more information, see <a href="{@docRoot}guide/market/billing/billing_overview.html#billing-action-notify">Handling ACTION_NOTIFY messages</a>.</p> 
+<p>Keep in mind, the Android Market application also sends an <code>IN_APP_NOTIFY</code> for refunds. For more information, see <a href="{@docRoot}guide/market/billing/billing_overview.html#billing-action-notify">Handling IN_APP_NOTIFY messages</a>.</p>
 
 <h4>Retrieving transaction information for a purchase or refund (GET_PURCHASE_INFORMATION)</h4>
 
-<p>You retrieve transaction information in response to an <code>ACTION_NOTIFY</code> broadcast intent. The <code>ACTION_NOTIFY</code> message contains a notification ID, which you can use to retrieve transaction information.</p>
+<p>You retrieve transaction information in response to an <code>IN_APP_NOTIFY</code> broadcast intent. The <code>IN_APP_NOTIFY</code> message contains a notification ID, which you can use to retrieve transaction information.</p>
 
 <p>To retrieve transaction information for a purchase or refund you must specify five keys in the request {@link android.os.Bundle}. The following code sample shows how to set these keys and make the request. In the sample, <code>mService</code> is an instance of the <code>MarketBillingService</code> interface.</p>
 
@@ -394,11 +474,11 @@
   // Do something with this response.
 }
 </pre>
-<p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The additional keys are then added to the bundle prior to invoking the <code>sendBillingRequest()</code> method. The <code>REQUEST_NONCE</code> key contains a cryptographically secure nonce (number used once) that you must generate. The Android Market application returns this nonce with the <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent so you can verify the integrity of the transaction information. The <code>NOTIFY_IDS</code> key contains an array of notification IDs, which you received in the <code>ACTION_NOTIFY</code> broadcast intent.</p>
+<p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The additional keys are then added to the bundle prior to invoking the <code>sendBillingRequest()</code> method. The <code>REQUEST_NONCE</code> key contains a cryptographically secure nonce (number used once) that you must generate. The Android Market application returns this nonce with the <code>PURCHASE_STATE_CHANGED</code> broadcast intent so you can verify the integrity of the transaction information. The <code>NOTIFY_IDS</code> key contains an array of notification IDs, which you received in the <code>IN_APP_NOTIFY</code> broadcast intent.</p>
 
 <p>The request returns a synchronous {@link android.os.Bundle} response, which contains two keys: <code>RESPONSE_CODE</code> and <code>REQUEST_ID</code>. The <code>RESPONSE_CODE</code> key provides you with the status of the request and the <code>REQUEST_ID</code> key provides you with a unique request identifier for the request.</p>
 
-<p>A <code>GET_PURCHASE_INFORMATION</code> request also triggers two asynchronous responses (broadcast intents). First, the Android Market application sends an <code>ACTION_RESPONSE_CODE</code> broadcast intent, which provides status and error information about the request. Next, if the request was successful, the Android Market application sends an <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent. This message contains detailed transaction information. The transaction information is contained in a signed JSON string (unencrypted). The message includes the signature so you can verify the integrity of the signed string.</p>
+<p>A <code>GET_PURCHASE_INFORMATION</code> request also triggers two asynchronous responses (broadcast intents). First, the Android Market application sends a <code>RESPONSE_CODE</code> broadcast intent, which provides status and error information about the request. Next, if the request was successful, the Android Market application sends a <code>PURCHASE_STATE_CHANGED</code> broadcast intent. This message contains detailed transaction information. The transaction information is contained in a signed JSON string (unencrypted). The message includes the signature so you can verify the integrity of the signed string.</p>
 
 <h4>Acknowledging transaction information (CONFIRM_NOTIFICATIONS)</h4>
 
@@ -414,11 +494,13 @@
   // Do something with this response.
 }
 </pre>
-<p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The additional <code>NOTIFY_IDS</code> key is then added to the bundle prior to invoking the <code>sendBillingRequest()</code> method. The <code>NOTIFY_IDS</code> key contains an array of notification IDs, which you received in an <code>ACTION_NOTIFY</code> broadcast intent and also used in a <code>GET_PURCHASE_INFORMATION</code> request.</p>
+<p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The additional <code>NOTIFY_IDS</code> key is then added to the bundle prior to invoking the <code>sendBillingRequest()</code> method. The <code>NOTIFY_IDS</code> key contains an array of notification IDs, which you received in an <code>IN_APP_NOTIFY</code> broadcast intent and also used in a <code>GET_PURCHASE_INFORMATION</code> request.</p>
 
 <p>The request returns a synchronous {@link android.os.Bundle} response, which contains two keys: <code>RESPONSE_CODE</code> and <code>REQUEST_ID</code>. The <code>RESPONSE_CODE</code> key provides you with the status of the request and the <code>REQUEST_ID</code> key provides you with a unique request identifier for the request.</p>
 
-<p>A <code>CONFIRM_NOTIFICATIONS</code> request triggers a single asynchronous response&mdash;an <code>ACTION_RESPONSE_CODE</code> broadcast intent. This broadcast intent provides status and error information about the request.</p>
+<p>A <code>CONFIRM_NOTIFICATIONS</code> request triggers a single asynchronous response&mdash;a <code>RESPONSE_CODE</code> broadcast intent. This broadcast intent provides status and error information about the request.</p>
+
+<p class="note"><strong>Note:</strong> As a best practice, you should not send a <code>CONFIRM_NOTIFICATIONS</code> request for a purchased item until you have delivered the item to the user. This way, if your application crashes or something else prevents your application from delivering the product, your application will still receive an <code>IN_APP_NOTIFY</code> broadcast intent from Android Market indicating that you need to deliver the product.</p>
 
 <h4>Restoring transaction information (RESTORE_TRANSACTIONS)</h4>
 
@@ -434,29 +516,29 @@
   // Do something with this response.
 }
 </pre>
-<p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The additional <code>REQUEST_NONCE</code> key is then added to the bundle prior to invoking the <code>sendBillingRequest()</code> method. The <code>REQUEST_NONCE</code> key contains a cryptographically secure nonce (number used once) that you must generate. The Android Market application returns this nonce with the transactions information contained in the <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent so you can verify the integrity of the transaction information.</p>
+<p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the three keys that are required for all requests: <code>BILLING_REQUEST</code>, <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. The additional <code>REQUEST_NONCE</code> key is then added to the bundle prior to invoking the <code>sendBillingRequest()</code> method. The <code>REQUEST_NONCE</code> key contains a cryptographically secure nonce (number used once) that you must generate. The Android Market application returns this nonce with the transactions information contained in the <code>PURCHASE_STATE_CHANGED</code> broadcast intent so you can verify the integrity of the transaction information.</p>
 
 <p>The request returns a synchronous {@link android.os.Bundle} response, which contains two keys: <code>RESPONSE_CODE</code> and <code>REQUEST_ID</code>. The <code>RESPONSE_CODE</code> key provides you with the status of the request and the <code>REQUEST_ID</code> key provides you with a unique request identifier for the request.</p>
 
-<p>A <code>RESTORE_TRANSACTIONS</code> request also triggers two asynchronous responses (broadcast intents). First, the Android Market application sends an <code>ACTION_RESPONSE_CODE</code> broadcast intent, which provides status and error information about the request. Next, if the request was successful, the Android Market application sends an <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent. This message contains the detailed transaction information. The transaction information is contained in a signed JSON string (unencrypted). The message includes the signature so you can verify the integrity of the signed string.</p>
+<p>A <code>RESTORE_TRANSACTIONS</code> request also triggers two asynchronous responses (broadcast intents). First, the Android Market application sends a <code>RESPONSE_CODE</code> broadcast intent, which provides status and error information about the request. Next, if the request was successful, the Android Market application sends a <code>PURCHASE_STATE_CHANGED</code> broadcast intent. This message contains the detailed transaction information. The transaction information is contained in a signed JSON string (unencrypted). The message includes the signature so you can verify the integrity of the signed string.</p>
 
 
 <h3>Other service tasks</h3>
 
-<p>You may also want your {@link android.app.Service} to receive intent messages from your {@link android.content.BroadcastReceiver}. You can use these intent messages to convey the information that was sent asynchronously from the Android Market application to your {@link android.content.BroadcastReceiver}. To see an example of how you can send and receive these intent messages, see the BillingReceiver.java and BillingService.java files in the sample application. You can use these samples as a basis for your own implementation. However, if you use any of the code from the sample application, be sure you follow the guidelines in <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a>.</p>
+<p>You may also want your {@link android.app.Service} to receive intent messages from your {@link android.content.BroadcastReceiver}. You can use these intent messages to convey the information that was sent asynchronously from the Android Market application to your {@link android.content.BroadcastReceiver}. To see an example of how you can send and receive these intent messages, see the <code>BillingReceiver.java</code> and <code>BillingService.java</code> files in the sample application. You can use these samples as a basis for your own implementation. However, if you use any of the code from the sample application, be sure you follow the guidelines in <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a>.</p>
 
 <h2 id="billing-broadcast-receiver">Creating a BroadcastReceiver</h2>
 
 <p>The Android Market application uses broadcast intents to send asynchronous billing responses to your application. To receive these intent messages, you need to create a {@link android.content.BroadcastReceiver} that can handle the following intents:</p>
 
 <ul>
-  <li>ACTION_RESPONSE_CODE
+  <li>com.android.vending.billing.RESPONSE_CODE
   <p>This broadcast intent contains an Android Market response code, and is sent after you make an in-app billing request. For more information about the response codes that are sent with this response, see <a href="{@docRoot}guide/market/billing/billing_reference.html#billing-codes">Android Market Response Codes for In-app Billing</a>.</p>
   </li>
-  <li>ACTION_NOTIFY
+  <li>com.android.vending.billing.IN_APP_NOTIFY
   <p>This response indicates that a purchase has changed state, which means a purchase succeeded, was canceled, or was refunded. For more information about notification messages, see <a href="{@docRoot}guide/market/billing/billing_reference.html#billing-intents">In-app Billing Broadcast Intents</a></p>
   </li>
-  <li>ACTION_PURCHASE_STATE_CHANGED
+  <li>com.android.vending.billing.PURCHASE_STATE_CHANGED
   <p>This broadcast intent contains detailed information about one or more transactions. For more information about purchase state messages, see <a href="{@docRoot}guide/market/billing/billing_reference.html#billing-intents">In-app Billing Broadcast Intents</a></p>
   </li>
 </ul>
@@ -473,28 +555,28 @@
 <th>Description</th>
 </tr>
 <tr>
-  <td><code>ACTION_RESPONSE_CODE</code></td>
-  <td><code>INAPP_REQUEST_ID</code></td>
+  <td><code>com.android.vending.billing.RESPONSE_CODE</code></td>
+  <td><code>request_id</code></td>
   <td>A <code>long</code> representing a request ID. A request ID identifies a specific billing request and is returned by Android Market at the time a request is made.</td>
 </tr>
 <tr>
-  <td><code>ACTION_RESPONSE_CODE</code></td>
-  <td><code>INAPP_RESPONSE_CODE</code></td>
+  <td><code>com.android.vending.billing.RESPONSE_CODE</code></td>
+  <td><code>response_code</code></td>
   <td>An <code>int</code> representing the actual Android Market server response code.</td>
 </tr>
 <tr>
-  <td><code>ACTION_NOTIFY</code></td>
-  <td><code>NOTIFICATION_ID</code></td>
+  <td><code>com.android.vending.billing.IN_APP_NOTIFY</code></td>
+  <td><code>notification_id</code></td>
   <td>A <code>String</code> representing the notification ID for a given purchase state change. Android Market notifies you when there is a purchase state change and the notification includes a unique notification ID. To get the details of the purchase state change, you send the notification ID with the <code>GET_PURCHASE_INFORMATION</code> request.</td>
 </tr>
 <tr>
-  <td><code>ACTION_PURCHASE_STATE_CHANGED</code></td>
-  <td><code>INAPP_SIGNED_DATA</code></td>
+  <td><code>com.android.vending.billing.PURCHASE_STATE_CHANGED</code></td>
+  <td><code>inapp_signed_data</code></td>
   <td>A <code>String</code> representing the signed JSON string. The JSON string contains information about the billing transaction, such as order number, amount, and the item that was purchased or refunded.</td>
 </tr>
 <tr>
-  <td><code>ACTION_PURCHASE_STATE_CHANGED</code></td>
-  <td><code>INAPP_SIGNATURE</code></td>
+  <td><code>com.android.vending.billing.PURCHASE_STATE_CHANGED</code></td>
+  <td><code>inapp_signature</code></td>
   <td>A <code>String</code> representing the signature of the JSON string.</td>
 </tr>
 </table>
@@ -547,17 +629,17 @@
 }
 </pre>
 
-<p>In addition to receiving broadcast intents from the Android Market application, your {@link android.content.BroadcastReceiver} must handle the information it received in the broadcast intents. Usually, your {@link android.content.BroadcastReceiver} does this by sending the information to a local service (discussed in the next section). The BillingReceiver.java file in the sample application shows you how to do this. You can use this sample as a basis for your own {@link android.content.BroadcastReceiver}. However, if you use any of the code from the sample application, be sure you follow the guidelines that are discussed in <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design </a>.</p>
+<p>In addition to receiving broadcast intents from the Android Market application, your {@link android.content.BroadcastReceiver} must handle the information it received in the broadcast intents. Usually, your {@link android.content.BroadcastReceiver} does this by sending the information to a local service (discussed in the next section). The <code>BillingReceiver.java</code> file in the sample application shows you how to do this. You can use this sample as a basis for your own {@link android.content.BroadcastReceiver}. However, if you use any of the code from the sample application, be sure you follow the guidelines that are discussed in <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design </a>.</p>
 
 <h2 id="billing-signatures">Verifying Signatures and Nonces</h2>
 
-<p>The in-app billing service uses two mechanisms to help verify the integrity of the transaction information you receive from Android Market: nonces and signatures. A nonce (number used once) is a cryptographically secure number that your application generates and sends with every <code>GET_PURCHASE_INFORMATION</code> and <code>RESTORE_TRANSACTIONS</code> request. The nonce is returned with the <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent, enabling you to verify that any given <code>ACTION_PURCHASE_STATE_CHANGED</code> response corresponds to an actual request that you made. Every <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent also includes a signed JSON string and a signature, which you can use to verify the integrity of the response.</p>
+<p>The in-app billing service uses two mechanisms to help verify the integrity of the transaction information you receive from Android Market: nonces and signatures. A nonce (number used once) is a cryptographically secure number that your application generates and sends with every <code>GET_PURCHASE_INFORMATION</code> and <code>RESTORE_TRANSACTIONS</code> request. The nonce is returned with the <code>PURCHASE_STATE_CHANGED</code> broadcast intent, enabling you to verify that any given <code>PURCHASE_STATE_CHANGED</code> response corresponds to an actual request that you made. Every <code>PURCHASE_STATE_CHANGED</code> broadcast intent also includes a signed JSON string and a signature, which you can use to verify the integrity of the response.</p>
 
 <p>Your application must provide a way to generate, manage, and verify nonces. The following sample code shows some simple methods you can use to do this.</p>
 
 <pre>
   private static final SecureRandom RANDOM = new SecureRandom();
-  private static HashSet&lt;Long&gt; sKnownNonces = new HashSet&lt;Long&gt;();   
+  private static HashSet&lt;Long&gt; sKnownNonces = new HashSet&lt;Long&gt;();
 
   public static long generateNonce() {
     long nonce = RANDOM.nextLong();
@@ -574,7 +656,7 @@
   }
 </pre>
 
-<p>Your application must also provide a way to verify the signatures that accompany every <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent. The Security.java file in the sample application shows you how to do this. If you use this file as a basis for your own security implementation, be sure to follow the guidelines in <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a> and obfuscate your code.</p> 
+<p>Your application must also provide a way to verify the signatures that accompany every <code>PURCHASE_STATE_CHANGED</code> broadcast intent. The <code>Security.java</code> file in the sample application shows you how to do this. If you use this file as a basis for your own security implementation, be sure to follow the guidelines in <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a> and obfuscate your code.</p>
 
 <p>You will need to use your Android Market public key to perform the signature verification. The following procedure shows you how to retrieve Base64-encoded public key from the Android Market publisher site.</p>
 
@@ -582,17 +664,17 @@
   <li>Log in to your <a href="http://market.android.com/publish">publisher account</a>.</li>
   <li>On the upper left part of the page, under your name, click <strong>Edit profile</strong>.</li>
   <li>On the Edit Profile page, scroll down to the Licensing &amp; In-app Billing panel (see figure 2).</li>
-  <li>Copy your public key to the clipboard.</li>
+  <li>Copy your public key.</li>
 </ol>
 
 <p class="caution"><strong>Important</strong>: To keep your public key safe from malicious users and hackers, do not embed your public key as an entire literal string. Instead, construct the string at runtime from pieces or use bit manipulation (for example, XOR with some other string) to hide the actual key. The key itself is not secret information, but you do not want to make it easy for a hacker or malicious user to replace the public key with another key.</p>
 
 <div style="margin-bottom:2em;">
 
-<img src="{@docRoot}images/billing_public_key.png" style="text-align:left;margin-bottom:0;" />
-<div style="margin:0 2em;padding:0"><strong>Figure 2.</strong> The Licensing and In-app Billing
-panel of your account's Edit Profile page lets you see your public key.</div>
-</div>
+<img src="{@docRoot}images/billing_public_key.png" height="510" id="figure2" />
+<p class="img-caption">
+  <strong>Figure 2.</strong> The Licensing and In-app Billing panel of your account's Edit Profile page lets you see your public key.
+</p>
 
 <h2 id="billing-implement">Modifying Your Application Code</h2>
 
diff --git a/docs/html/guide/market/billing/billing_overview.jd b/docs/html/guide/market/billing/billing_overview.jd
index b899b9b..36f9d53c 100755
--- a/docs/html/guide/market/billing/billing_overview.jd
+++ b/docs/html/guide/market/billing/billing_overview.jd
@@ -3,12 +3,6 @@
 parent.link=index.html
 @jd:body
 
-<style type="text/css">
-  #jd-content {
-    background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
-  }
-</style>
-
 <div id="qv-wrapper">
 <div id="qv">
   <h2>In this document</h2>
@@ -19,7 +13,7 @@
       <li><a href="#billing-request">Request messages</a></li>
       <li><a href="#billing-response">Broadcast intents</a></li>
       <li><a href="#billing-message-sequence">Messaging sequence</a></li>
-      <li><a href="#billing-action-notify">Handling ACTION_NOTIFY messages</a></li>
+      <li><a href="#billing-action-notify">Handling IN_APP_NOTIFY messages</a></li>
     </ol>
     <li><a href="#billing-security">Security Controls</a></li>
     <li><a href="#billing-limitations">Requirements and Limitations</a></li>
@@ -40,10 +34,10 @@
 </div>
 
 <div class="special" style="margin-right:345px">
-  <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
+  <p>During the testing phase of the in-app billing release you cannot publish applications that implement in-app billing. You can only upload in-app billing applications as draft applications. For more information, see <a href="{@docRoot}guide/market/billing/billing_about.html">About this Release</a></p>
 </div>
 
-<p>The Android Market In-app Billing service is an Android Market feature that provides checkout processing for in-app purchases. To use the service, your application sends a billing request to the service for a specific in-app product. The service then handles all of the checkout details for the transaction, including requesting and validating the form of payment and processing the financial transaction. When the checkout process is complete, the service sends your application the purchase details, such as the order number, the order date and time, and the price paid. At no point does your application have to handle any financial transactions; that role is provided by the in-app billing service.</p>
+<p>The Android Market In-app Billing service is an Android Market feature that provides checkout processing for in-app purchases. To use the service, your application sends a billing request for a specific in-app product. The service then handles all of the checkout details for the transaction, including requesting and validating the form of payment and processing the financial transaction. When the checkout process is complete, the service sends your application the purchase details, such as the order number, the order date and time, and the price paid. At no point does your application have to handle any financial transactions; that role is provided by the in-app billing service.</p>
 
 <h2 id="billing-arch">In-app Billing Architecture</h2>
 
@@ -52,8 +46,9 @@
 <p>Some in-app billing implementations may also use a private remote server to deliver content or validate transactions, but a remote server is not required to implement in-app billing. A remote server can be useful if you are selling digital content that needs to be delivered to a user's device, such as media files or photos. You might also use a remote server to store users' transaction history or perform various in-app billing security tasks, such as signature verification. Although you can handle all security-related tasks in your application, performing those tasks on a remote server is recommended because it helps make your application less vulnerable to security attacks.</p>
 
 <div class="figure" style="width:440px">
-<img src="{@docRoot}images/billing_arch.png" alt=""/>
-<p class="img-caption"><strong>Figure 1.</strong> Your application sends and receives billing messages through the Android Market application, which handles all communication with the Android Market server.</p>
+<img src="{@docRoot}images/billing_arch.png" alt="" height="582" />
+<p class="img-caption">
+  <strong>Figure 1.</strong> Your application sends and receives billing messages through the Android Market application, which handles all communication with the Android Market server.</p>
 </div>
 
 <p>A typical in-app billing implementation relies on three components:</p>
@@ -77,7 +72,7 @@
 
 <h3 id="billing-request">In-app billing requests</h3>
 
-<p>Your application sends in-app billing requests by invoking a single IPC method (<code>sendBillingRequest()</code>), which is exposed by the <code>MarketBillingService</code> interface. This interface is defined in an <a href="{@docRoot}guide/developing/tools/aidl.html">Android Interface Definition Language</a> file (<code>IMarketBillingService.aidl</code>). You can download this AIDL file with the in-app billing sample application.</p>
+<p>Your application sends in-app billing requests by invoking a single IPC method (<code>sendBillingRequest()</code>), which is exposed by the <code>MarketBillingService</code> interface. This interface is defined in an <a href="{@docRoot}guide/developing/tools/aidl.html">Android Interface Definition Language</a> file (<code>IMarketBillingService.aidl</code>). You can <a href="{@docRoot}guide/market/billing/billing_integrate.html#billing-download">download</a> this AIDL file with the in-app billing sample application.</p>
 
 <p>The <code>sendBillingRequest()</code> method has a single {@link android.os.Bundle} parameter. The Bundle that you deliver must include several key-value pairs that specify various parameters for the request, such as the type of billing request you are making, the item that is being purchased, and the application that is making the request. For more information about the Bundle keys that are sent with a request, see <a href="{@docRoot}guide/market/billing/billing_reference.html#billing-interface">In-app Billing Service Interface</a>.
 
@@ -97,7 +92,7 @@
     <p>This request acknowledges that your application received the details of a purchase state change. Android Market sends purchase state change notifications to your application until you confirm that you received them.</p>
   </li>
   <li><code>RESTORE_TRANSACTIONS</code>
-    <p>This request retrieves a user's transaction status for managed purchases (see <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-purchase-type">Choosing a Purchase Type</a> for more information). You should send this request only when you need to retrieve a user's transaction status, which is usually only when your application is reinstalled or installed for the first time on a device.</p>
+    <p>This request retrieves a user's transaction status for <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-purchase-type">managed purchases</a>. You should send this request only when you need to retrieve a user's transaction status, which is usually only when your application is reinstalled or installed for the first time on a device.</p>
   </li>
 </ul>
 
@@ -121,18 +116,18 @@
 <p>The asynchronous response messages are sent in the form of individual broadcast intents and include the following:</p>
 
 <ul>
-    <li><code>ACTION_RESPONSE_CODE</code>
+    <li><code>com.android.vending.billing.RESPONSE_CODE</code>
     <p>This response contains an Android Market server response code, and is sent after you make an in-app billing request. A server response code can indicate that a billing request was successfully sent to Android Market or it can indicate that some error occurred during a billing request. This response is <em>not</em> used to report any purchase state changes (such as refund or purchase information). For more information about the response codes that are sent with this response, see <a href="{@docRoot}guide/market/billing/billing_reference.html#billing-codes">Server Response Codes for In-app Billing</a>.</p>
   </li>
-  <li><code>ACTION_NOTIFY</code>
-    <p>This response indicates that a purchase has changed state, which means a purchase succeeded, was canceled, or was refunded. This response contains one or more notification IDs. Each notification ID corresponds to a specific server-side message, and each messages contains information about one or more transactions. After your application receives an <code>ACTION_NOTIFY</code> broadcast intent, you send a <code>GET_PURCHASE_INFORMATION</code> request with the notification IDs to retrieve message details.</p>
+  <li><code>com.android.vending.billing.IN_APP_NOTIFY</code>
+    <p>This response indicates that a purchase has changed state, which means a purchase succeeded, was canceled, or was refunded. This response contains one or more notification IDs. Each notification ID corresponds to a specific server-side message, and each messages contains information about one or more transactions. After your application receives an <code>IN_APP_NOTIFY</code> broadcast intent, you send a <code>GET_PURCHASE_INFORMATION</code> request with the notification IDs to retrieve message details.</p>
   </li>
-  <li><code>ACTION_PURCHASE_STATE_CHANGED</code>
+  <li><code>com.android.vending.billing.PURCHASE_STATE_CHANGED</code>
     <p>This response contains detailed information about one or more transactions. The transaction information is contained in a JSON string. The JSON string is signed and the signature is sent to your application along with the JSON string (unencrypted). To help ensure the security of your in-app billing messages, your application can verify the signature of this JSON string.</p>
   </li>
 </ul>
 
-<p>The JSON string that is returned with the <code>ACTION_PURCHASE_STATE_CHANGED</code> intent provides your application with the details of one or more billing transactions. An example of this JSON string is shown below:</p>
+<p>The JSON string that is returned with the <code>PURCHASE_STATE_CHANGED</code> intent provides your application with the details of one or more billing transactions. An example of this JSON string is shown below:</p>
 <pre class="no-pretty-print" style="color:black">
 { "nonce" : 1836535032137741465,
   "orders" :
@@ -146,113 +141,85 @@
 }
 </pre>
 
-<p>The fields in the JSON string are described in the following table (see table 1):</p>
-
-<p class="table-caption"><strong>Table 1.</strong> Description of JSON fields that are returned with an <code>ACTION_PURCHASE_STATE_CHANGED</code> intent.</p>
-
-<table>
-
-<tr>
-<th>Field</th>
-<th>Description</th>
-</tr>
-<tr>
-  <td>nonce</td>
-  <td>A number used once. Your application generates the nonce and sends it with the <code>GET_PURCHASE_INFORMATION</code> request. Android Market sends the nonce back as part of the JSON string so you can verify the integrity of the message.</td>
-</tr>
-<tr>
-  <td>notificationId</td>
-  <td>A unique identifier that is sent with an <code>ACTION_NOTIFY</code> broadcast intent. Each <code>notificationId</code> corresponds to a specify message that is waiting to be retrieved on the Android Market server. Your application sends back the <code>notificationId</code> with the <code>GET_PURCHASE_INFORMATION</code> message so Android Market can determine which messages you are retrieving.</td>
-</tr>
-<tr>
-  <td>orderId</td>
-  <td>A unique order identifier for the transaction. This corresponds to the Google Checkout Order ID.</td>
-</tr>
-<tr>
-  <td>packageName</td>
-  <td>The application package from which the purchase originated.</td>
-</tr>
-<tr>
-  <td>productId</td>
-  <td>The item's product identifier. Every item has a product ID, which you must specify in the application's product list on the Android Market publisher site.</td>
-</tr>
-<tr>
-  <td>purchaseTime</td>
-  <td>The time the product was purchased, in milliseconds since the epoch (Jan 1, 1970).</td>
-</tr>
-
-<tr>
-  <td>purchaseState</td>
-  <td>The enum value for the purchase state, which indicates whether the purchase was successful, canceled, or refunded.</td>
-</tr>
-<tr>
-  <td>developerPayload</td>
-  <td>A developer-specified string that is associated with an order. This field is returned in the JSON string that contains transaction information for an order. You can use this field to send information with an order. For example, you can use this field to send index keys with an order, which is useful if you are using a database to store purchase information. We recommend that you do not use this field to send data or content.</td>
-</tr>
-</table>
+<p>For more information about the fields in this JSON string, see <a href="{@docRoot}guide/market/billing/billing_reference.html#billing-intents">In-app Billing Broadcast Intents</a>.</p>
 
 <h3 id="billing-message-sequence">Messaging sequence</h3>
 
-<p>The messaging sequence for a typical purchase request is shown in Figure 2. Request types for each <code>sendBillingRequest()</code> method are shown in <strong>bold</strong>, responses are shown in standard text. For clarity, Figure 2 does not show the <code>ACTION_RESPONSE_CODE</code> broadcast intents that are sent for every request. These responses provide status information or error information and are returned after each request.</p>
+<p>The messaging sequence for a typical purchase request is shown in figure 2. Request types for each <code>sendBillingRequest()</code> method are shown in <strong>bold</strong>, broadcast intents are shown in <em>italic</em>. For clarity, figure 2 does not show the <code>RESPONSE_CODE</code> broadcast intents that are sent for every request.</p>
 
 <p>The basic message sequence for an in-app purchase request is as follows:</p>
 
 <ol>
   <li>Your application sends a purchase request (<code>REQUEST_PURCHASE</code> type), specifying a product ID and other parameters.</li>
-  <li>The Android Market application sends your application a Bundle with a <code>RESPONSE_CODE</code>, <code>PURCHASE_INTENT</code>, and <code>REQUEST_ID</code>. The <code>PURCHASE_INTENT</code> provides a {@link android.app.PendingIntent}, which your application uses to start the checkout flow for the given product ID.</li>
+  <li>The Android Market application sends your application a Bundle with the following keys: <code>RESPONSE_CODE</code>, <code>PURCHASE_INTENT</code>, and <code>REQUEST_ID</code>. The <code>PURCHASE_INTENT</code> key provides a {@link android.app.PendingIntent}, which your application uses to start the checkout UI for the given product ID.</li>
   <li>Your application launches the pending intent, which launches the checkout UI.</li>
-  <li>When the checkout flow finishes (that is, the user successfully purchases the item or cancels the purchase), Android Market sends your application a notification message (an <code>ACTION_NOTIFY</code> intent). The notification message includes a notification ID, which references the completed transaction.</li>
+  <li>When the checkout flow finishes (that is, the user successfully purchases the item or cancels the purchase), Android Market sends your application a notification message (an <code>IN_APP_NOTIFY</code> broadcast intent). The notification message includes a notification ID, which references the transaction.</li>
   <li>Your application requests the transaction information by sending a <code>GET_PURCHASE_STATE_CHANGED</code> request, specifying the notification ID for the transaction.</li>
-  <li>The Android Market application sends a Bundle with a <code>RESPONSE_CODE</code> and a  <code>REQUEST_ID</code>.
-  <li>Android Market sends the transaction information to your application in an <code>ACTION_PURCHASE_STATE_CHANGED</code> intent.</li> 
+  <li>The Android Market application sends a Bundle with a <code>RESPONSE_CODE</code> key and a  <code>REQUEST_ID</code> key.
+  <li>Android Market sends the transaction information to your application in a <code>PURCHASE_STATE_CHANGED</code> broadcast intent.</li>
   <li>Your application confirms that you received the transaction information for the given notification ID by sending a confirmation message (<code>CONFIRM_NOTIFICATIONS</code> type), specifying the notification ID for which you received transaction information.</li>
-  <li>The Android Market applications sends your application a Bundle with a <code>RESPONSE_CODE</code> and a <code>REQUEST_ID</code>.</li>
+  <li>The Android Market application sends your application a Bundle with a <code>RESPONSE_CODE</code> key and a <code>REQUEST_ID</code> key.</li>
 </ol>
 
 <p class="note"><strong>Note:</strong> You must launch the pending intent from an activity context and not an application context.</p>
 
-<div style="margin:2em 1em 1em 1em;">
-<img src="{@docRoot}images/billing_request_purchase.png" style="text-align:left;" />
-<div style="margin:.25em 1.25em;padding:0"><strong>Figure 2.</strong> Message sequence for a typical purchase request. Request types for each <code>sendBillingRequest()</code> method are shown in <strong>bold</strong> (<code>ACTION_RESPONSE_CODE</code> broadcast intents have been omitted).</div>
-</div>
+<img src="{@docRoot}images/billing_request_purchase.png" height="231" id="figure2" />
+<p class="img-caption">
+  <strong>Figure 2.</strong> Message sequence for a purchase request.
+</p>
 
-<p>The messaging sequence for a restore transaction request is shown in Figure 3. The request type for the <code>sendBillingRequest()</code> method is shown in <strong>bold</strong>, the responses are shown in standard text.</p>
+<p>The messaging sequence for a restore transaction request is shown in figure 3. Request types for each <code>sendBillingRequest()</code> method are shown in <strong>bold</strong>, broadcast intents are shown in <em>italic</em>. For clarity, figure 3 does not show the <code>RESPONSE_CODE</code> broadcast intents that are sent for every request.</p>
 
 <div class="figure" style="width:490px">
-<img src="{@docRoot}images/billing_restore_transactions.png" alt=""/>
-<p class="img-caption"><strong>Figure 3.</strong> Message sequence for a restore transactions request.</p>
+<img src="{@docRoot}images/billing_restore_transactions.png" alt="" height="168" />
+<p class="img-caption">
+  <strong>Figure 3.</strong> Message sequence for a restore transactions request.
+</p>
 </div>
 
-<p>The request triggers three responses. The first is a {@link android.os.Bundle} with a <code>RESPONSE_CODE</code> and a <code>REQUEST_ID</code>. Next, the Android Market application sends an <code>ACTION_RESPONSE_CODE</code> broadcast intent, which provides status information or error information about the request. As always, the <code>ACTION_RESPONSE_CODE</code> message references a specific request ID, so you can determine which request an <code>ACTION_RESPONSE_CODE</code> message pertains to.</p>
+<p>The request triggers three responses. The first is a {@link android.os.Bundle} with a <code>RESPONSE_CODE</code> key and a <code>REQUEST_ID</code> key. Next, the Android Market application sends a <code>RESPONSE_CODE</code> broadcast intent, which provides status information or error information about the request. As always, the <code>RESPONSE_CODE</code> message references a specific request ID, so you can determine which request a <code>RESPONSE_CODE</code> message pertains to.</p>
 
-<p>The <code>RESTORE_TRANSACTIONS</code> request type also triggers an <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent, which contains the same type of transaction information that is sent during a purchase request, although you do not need to respond to this intent with a <code>CONFIRM_NOTIFICATIONS</code> message.</p>
+<p>The <code>RESTORE_TRANSACTIONS</code> request type also triggers a <code>PURCHASE_STATE_CHANGED</code> broadcast intent, which contains the same type of transaction information that is sent during a purchase request, although you do not need to respond to this intent with a <code>CONFIRM_NOTIFICATIONS</code> message.</p>
 
-<p>The messaging sequence for checking whether in-app billing is supported is shown in Figure 4. The request type for the <code>sendBillingRequest()</code> method is shown in <strong>bold</strong>, the response is shown in regular text.</p>
+<p>The messaging sequence for checking whether in-app billing is supported is shown in figure 4. The request type for the <code>sendBillingRequest()</code> method is shown in <strong>bold</strong>.</p>
 
 <div class="figure" style="width:454px">
-<img src="{@docRoot}images/billing_check_supported.png" alt=""/>
-<p class="img-caption"><strong>Figure 4.</strong> Message sequence for checking whether in-app billing is supported.</p>
+<img src="{@docRoot}images/billing_check_supported.png" alt="" height="168" />
+<p class="img-caption">
+  <strong>Figure 4.</strong> Message sequence for checking whether in-app billing is supported.
+</p>
 </div>
 
-<p>The synchronous response for a <code>CHECK_BILLING_SUPPORTED</code> request provides a server response code.  A <code>RESULT_OK</code> response code indicates that in-app billing is supported; a <code>RESULT_BILLING_UNAVAILABLE</code> response code indicates that the Android Market application does not support in-app billing and may need to be updated. A <code>SERVER_ERROR</code> can also be returned, indicating that there was a problem with the Android Market server. The <code>RESULT_BILLING_UNAVAILABLE</code> response code can also indicate that the user is ineligible for in-app billing (for example, the user resides in a country that does not allow in-app billing).</p>
+<p>The synchronous response for a <code>CHECK_BILLING_SUPPORTED</code> request provides a Bundle with a server response code.  A <code>RESULT_OK</code> response code indicates that in-app billing is supported; a <code>RESULT_BILLING_UNAVAILABLE</code> response code indicates that in-app billing is unavailable because the in-app billing API version you specified is unrecognized or the user is not eligible to make in-app purchases (for example, the user resides in a country that does not allow in-app billing). A <code>SERVER_ERROR</code> can also be returned, indicating that there was a problem with the Android Market server.</p>
 
-<h3 id="billing-action-notify">Handling ACTION_NOTIFY messages</h3>
+<h3 id="billing-action-notify">Handling IN_APP_NOTIFY messages</h3>
 
-<p>Usually, your application receives an <code>ACTION_NOTIFY</code> intent from Android Market in response to a <code>REQUEST_PURCHASE</code> message (see figure 2). The <code>ACTION_NOTIFY</code> intent informs your application that the state of a requested purchase has changed. To retrieve the details of that state change, your application sends a <code>GET_PURCHASE_INFORMATION</code> request. Android Market responds with an <code>ACTION_PURCHASE_STATE_CHANGED</code> intent, which contains the details of the purchase state change. Your application then sends a <code>CONFIRM_NOTIFICATIONS</code> message, informing Android Market that you've received the purchase state change information.</p>
+<p>Usually, your application receives an <code>IN_APP_NOTIFY</code> broadcast intent from Android Market in response to a <code>REQUEST_PURCHASE</code> message (see figure 2). The <code>IN_APP_NOTIFY</code> broadcast intent informs your application that the state of a requested purchase has changed. To retrieve the details of that purchase, your application sends a <code>GET_PURCHASE_INFORMATION</code> request. Android Market responds with a <code>PURCHASE_STATE_CHANGED</code> broadcast intent, which contains the details of the purchase state change. Your application then sends a <code>CONFIRM_NOTIFICATIONS</code> message, informing Android Market that you've received the purchase state change information.</p>
 
-<p>When Android Market receives a <code>CONFIRM_NOTIFICATIONS</code> message for a given message, it usually stops sending <code>ACTION_NOTIFY</code> intents for that message. However, there are some cases where Android Market may send repeated <code>ACTION_NOTIFY</code> intents for a message even though your application has sent a <code>CONFIRM_NOTIFICATIONS</code> message. This can occur if a device loses network connectivity while you are sending the <code>CONFIRM_NOTIFICATIONS</code> message. In this case, Android Market might not receive your <code>CONFIRM_NOTIFICATIONS</code> message and it could send multiple <code>ACTION_NOTIFY</code> messages until it receives acknowledgement that you received the message. Therefore, your application must be able to recognize that the subsequent <code>ACTION_NOTIFY</code> messages are for a previously processed transaction. You can do this by checking the <code>orderID</code> that's contained in the JSON string because every transaction has a unique <code>orderId</code>.</p>
+<p>When Android Market receives a <code>CONFIRM_NOTIFICATIONS</code> message for a given message, it usually stops sending <code>IN_APP_NOTIFY</code> intents for that message. However, there are some cases where Android Market may send repeated <code>IN_APP_NOTIFY</code> intents for a message even though your application has sent a <code>CONFIRM_NOTIFICATIONS</code> message. This can occur if a device loses network connectivity while you are sending the <code>CONFIRM_NOTIFICATIONS</code> message. In this case, Android Market might not receive your <code>CONFIRM_NOTIFICATIONS</code> message and it could send multiple <code>IN_APP_NOTIFY</code> messages until it receives acknowledgement that you received the message. Therefore, your application must be able to recognize that the subsequent <code>IN_APP_NOTIFY</code> messages are for a previously processed transaction. You can do this by checking the <code>orderID</code> that's contained in the JSON string because every transaction has a unique <code>orderId</code>.</p>
 
-<p>Your application may also receive <code>ACTION_NOTIFY</code> intents even though your application has not sent a <code>REQUEST_PURCHASE</code> message. This can occur when a user has your application installed on two (or more) devices and the user makes an in-app purchase from one of the devices. In this case, Android Market sends an <code>ACTION_NOTIFY</code> message to the second device, informing the application that there is a purchase state change. Your application can handle this message the same way it handles the response from an application-initiated <code>REQUEST_PURCHASE</code> message, so that ultimately your application receives a purchase state change message that includes information about the item that's been purchased. This scenario applies only to items that have their <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-purchase-type">purchase type</a> set to "managed per user account."</p>
+<p>There are two cases where your application may also receive <code>IN_APP_NOTIFY</code> broadcast intents even though your application has not sent a <code>REQUEST_PURCHASE</code> message. Figure 5 shows the messaging sequence for both of these cases. Request types for each <code>sendBillingRequest()</code> method are shown in <strong>bold</strong>, broadcast intents are shown in <em>italic</em>. For clarity, figure 5 does not show the <code>RESPONSE_CODE</code> broadcast intents that are sent for every request.</p>
+
+<div class="figure" style="width:481px">
+<img src="{@docRoot}images/billing_refund.png" alt="" height="189" />
+<p class="img-caption">
+  <strong>Figure 5.</strong> Message sequence for refunds and other unsolicited IN_APP_NOTIFY messages.
+</p>
+</div>
+
+<p>In the first case, your application can receive an <code>IN_APP_NOTIFY</code> broadcast intent when a user has your application installed on two (or more) devices and the user makes an in-app purchase from one of the devices. In this case, Android Market sends an <code>IN_APP_NOTIFY</code> message to the second device, informing the application that there is a purchase state change. Your application can handle this message the same way it handles the response from an application-initiated <code>REQUEST_PURCHASE</code> message, so that ultimately your application receives a <code>PURCHASE_STATE_CHANGED</code> broadcast intent message that includes information about the item that has been purchased. This applies only to items that have their <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-purchase-type">purchase type</a> set to "managed per user account."</p>
+
+<p>In the second case, your application can receive an <code>IN_APP_NOTIFY</code> broadcast intent when Android Market receives a refund notification from Google Checkout. In this case, Android Market sends an <code>IN_APP_NOTIFY</code> message to your application. Your application can handle this message the same way it handles responses from an application-initiated <code>REQUEST_PURCHASE</code> message so that ultimately your application receives a <code>PURCHASE_STATE_CHANGED</code> message that includes information about the item that has been refunded. The refund information is included in the JSON string that accompanies the <code>PURCHASE_STATE_CHANGED</code> broadcast intent. Also, the <code>purchaseState</code> field in the JSON string is set to 2.</p>
 
 <h2 id="billing-security">Security Controls</h2>
 
-<p>To help ensure the integrity of the transaction information that is sent to your application, Android Market signs the JSON string that is contained in the <code>ACTION_PURCHASE_STATE_CHANGED</code> broadcast intent. Android Market uses the private key that is associated with your publisher account to create this signature. The publisher site generates an RSA key pair for each publisher account. You can find the public key portion of this key pair on your account's profile page. It is the same public key that is used with Android Market licensing.</p>
+<p>To help ensure the integrity of the transaction information that is sent to your application, Android Market signs the JSON string that is contained in the <code>PURCHASE_STATE_CHANGED</code> broadcast intent. Android Market uses the private key that is associated with your publisher account to create this signature. The publisher site generates an RSA key pair for each publisher account. You can find the public key portion of this key pair on your account's profile page. It is the same public key that is used with Android Market licensing.</p>
 
 <p>When Android Market signs a billing response, it includes the signed JSON string (unencrypted) and the signature. When your application receives this signed response you can use the public key portion of your RSA key pair to verify the signature. By performing signature verification you can help detect responses that have been tampered with or that have been spoofed. You can perform this signature verification step in your application; however, if your application connects to a secure remote server then we recommend that you perform the signature verification on that server.</p>
 
 <p>In-app billing also uses nonces (a random number used once) to help verify the integrity of the purchase information that's returned from Android Market. Your application must generate a nonce and send it with a <code>GET_PURCHASE_INFORMATION</code> request and a <code>RESTORE_TRANSACTIONS</code> request. When Android Market receives the request, it adds the nonce to the JSON string that contains the transaction information. The JSON string is then signed and returned to your application. When your application receives the JSON string, you need to verify the nonce as well as the signature of the JSON string.</p>
 
-<p>For more information about best practices for security and design, see <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a>.</p> 
+<p>For more information about best practices for security and design, see <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a>.</p>
 
 <h2 id="billing-limitations">In-app Billing Requirements and Limitations</h2>
 
@@ -260,10 +227,12 @@
 
 <ul>
   <li>In-app billing can be implemented only in applications that you publish through Android Market.</li>
-  <li>You must have a Google Checkout merchant account to use the in-app billing service.</li>
-  <li>An application can use in-app billing only if the current Android Market application is installed on its host device and the device is running Android 1.6 (API level 4) or higher.</li>
-  <li>A device must be running version 2.3.0 (or higher) of the Android Market application to support in-app billing.</li>
+  <li>You must have a Google Checkout Merchant account to use the in-app billing service.</li>
+  <li>If your device is running Android 3.0, in-app billing requires version 5.0.12 (or higher) of the MyApps application. If your device is running any other version of Android, in-app billing requires version 2.3.4 (or higher) of the Android Market application.</li>
+  <li>An application can use in-app billing only if the device is running Android 1.6 (API level 4) or higher.</li>
   <li>You can use in-app billing to sell only digital content. You cannot use in-app billing to sell physical goods, personal services, or anything that requires physical delivery.</li>
   <li>Android Market does not provide any form of content delivery. You are responsible for delivering the digital content that you sell in your applications.</li>
   <li>You cannot implement in-app billing on a device that never connects to the network. To complete in-app purchase requests, a device must be able to access the Android Market server over the network. </li>
 </ul>
+
+<p>For more information about in-app billing requirements, see <a href="http://market.android.com/support/bin/answer.py?answer=1153481">In-App Billing Availability and Policies</a>.</p>
diff --git a/docs/html/guide/market/billing/billing_reference.jd b/docs/html/guide/market/billing/billing_reference.jd
index 2e5c9c6..744c4d1 100755
--- a/docs/html/guide/market/billing/billing_reference.jd
+++ b/docs/html/guide/market/billing/billing_reference.jd
@@ -3,12 +3,6 @@
 parent.link=index.html
 @jd:body
 
-<style type="text/css">
-  #jd-content {
-    background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
-  }
-</style>
-
 <div id="qv-wrapper">
 <div id="qv">
   <h2>In this document</h2>
@@ -34,7 +28,7 @@
 </div>
 
 <div class="special" style="margin-right:345px">
-  <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
+  <p>During the testing phase of the in-app billing release you cannot publish applications that implement in-app billing. You can only upload in-app billing applications as draft applications. For more information, see <a href="{@docRoot}guide/market/billing/billing_about.html">About this Release</a></p>
 </div>
 
 <p>The following document provides technical reference information for the following:</p>
@@ -47,7 +41,7 @@
 
 <h2 id="billing-codes">Android Market Server Response Codes for In-app Billing</h2>
 
-<p>The following table lists all of the server response codes that are sent from Android Market to your application. Android Market sends these response codes asynchronously as <code>INAPP_RESPONSE_CODE</code> extras in the <code>ACTION_RESPONSE_CODE</code> broadcast intent. Your application must handle all of these response codes.</p>
+<p>The following table lists all of the server response codes that are sent from Android Market to your application. Android Market sends these response codes asynchronously as <code>response_code</code> extras in the <code>com.android.vending.billing.RESPONSE_CODE</code> broadcast intent. Your application must handle all of these response codes.</p>
 
 <p class="table-caption" id="response-codes-table"><strong>Table 1.</strong> Summary of response codes returned by Android Market.</p>
 
@@ -71,7 +65,7 @@
 </tr>
 <tr>
   <td><code>RESULT_BILLING_UNAVAILABLE</code></td>
-  <td>Indicates that the <code>BILLING_API_VERSION</code> that you specified is not recognized by the Android Market application and that the Android Market application may have to be updated. Can also indicate that the user is ineligible for in-app billing. For example, the user resides in a country that does not allow in-app purchases.</td>
+  <td>Indicates that in-app billing is not available because the <code>API_VERSION</code> that you specified is not recognized by the Android Market application or the user is ineligible for in-app billing (for example, the user resides in a country that prohibits in-app purchases).</td>
 </tr>
 <tr>
   <td><code>RESULT_ITEM_UNAVAILABLE</code></td>
@@ -90,8 +84,8 @@
 
 <h2 id="billing-interface">In-app Billing Service Interface</h2>
 
-<p>The following section describes the interface for the Android Market In-app Billing service. The interface is defined in the <code>IMarketBillingService.aidl</code> file, which is included with the in-app billing <a href="{@docRoot}guide/market/billing/billing_integrate.html#billing-download">sample application</a>.</p>
-<p>The interface consists of a single request method <code>sendBillingRequest()</code>. This method takes a single {@link android.os.Bundle} parameter. The Bundle parameter includes several key-value pairs, which are summarized in Table 2.</p>
+<p>The following section describes the interface for the Android Market in-app billing service. The interface is defined in the <code>IMarketBillingService.aidl</code> file, which is included with the in-app billing <a href="{@docRoot}guide/market/billing/billing_integrate.html#billing-download">sample application</a>.</p>
+<p>The interface consists of a single request method <code>sendBillingRequest()</code>. This method takes a single {@link android.os.Bundle} parameter. The Bundle parameter includes several key-value pairs, which are summarized in table 2.</p>
 
 <p class="table-caption"><strong>Table 2.</strong> Description of Bundle keys passed in a <code>sendBillingRequest()</code> request.</p>
 
@@ -106,52 +100,52 @@
 </tr>
 <tr>
   <td><code>BILLING_REQUEST</code></td>
-  <td>String</td>
+  <td><code>String</code></td>
   <td><code>CHECK_BILLING_SUPPORTED</code>, <code>REQUEST_PURCHASE</code>, <code>GET_PURCHASE_INFORMATION</code>, <code>CONFIRM_NOTIFICATIONS</code>, or <code>RESTORE_TRANSACTIONS</code></td>
   <td>Yes</td>
   <td>The type of billing request you are making with the <code>sendBillingRequest()</code> request. The possible values are discussed more below this table.</td>
 </tr>
 <tr>
-  <td><code>BILLING_API_VERSION</code></td>
-  <td>int</td>
-  <td>0 (for alpha release); 1 (for beta release)</td>
+  <td><code>API_VERSION</code></td>
+  <td><code>int</code></td>
+  <td>1</td>
   <td>Yes</td>
-  <td>The version of the in-app billing service you are using.</td>
+  <td>The version of the in-app billing service you are using. The current version is 1.</td>
 </tr>
 <tr>
   <td><code>PACKAGE_NAME</code></td>
-  <td>String</td>
+  <td><code>String</code></td>
   <td>A valid package name.</td>
   <td>Yes</td>
   <td>The name of the application that is making the request.</td>
 </tr>
 <tr>
   <td><code>ITEM_ID</code></td>
-  <td>String</td>
+  <td><code>String</code></td>
   <td>Any valid product identifier.</td>
   <td>Required for <code>REQUEST_PURCHASE</code> requests.</td>
   <td>The product ID of the item you are making a billing request for. Every in-app item that you sell using the in-app billing service must have a unique product ID, which you specify on the Android Market publisher site.</td>
 </tr>
 <tr>
   <td><code>NONCE</code></td>
-  <td>long</td>
-  <td>Any valid long value.</td>
+  <td><code>long</code></td>
+  <td>Any valid <code>long</code> value.</td>
   <td>Required for <code>GET_PURCHASE_INFORMATION</code> and <code>RESTORE_TRANSACTIONS</code> requests.</td>
-  <td>A number used once. Your application must generate and send a nonce with each <code>GET_PURCHASE_INFORMATION</code> and <code>RESTORE_TRANSACTIONS</code> request. The nonce is returned with the <code>ACTION_PURCHASE_STATE_CHANGED</code> intent, so you can use this value to verify the integrity of transaction responses form Android Market.</td>
+  <td>A number used once. Your application must generate and send a nonce with each <code>GET_PURCHASE_INFORMATION</code> and <code>RESTORE_TRANSACTIONS</code> request. The nonce is returned with the <code>PURCHASE_STATE_CHANGED</code> broadcast intent, so you can use this value to verify the integrity of transaction responses form Android Market.</td>
 </tr>
 <tr>
   <td><code>NOTIFY_IDS</code></td>
-  <td>Array of long values</td>
-  <td>Any valid array of long values</td>
+  <td>Array of <code>long</code> values</td>
+  <td>Any valid array of <code>long</code> values</td>
   <td>Required for <code>GET_PURCHASE_INFORMATION</code> and <code>CONFIRM_NOTIFICATIONS</code> requests.</td>
-  <td>An array of notification identifiers. A notification ID is sent to your application in an <code>ACTION_NOTIFY</code> intent every time a purchase changes state. You use the notification to retrieve the details of the purchase state change.</td>
+  <td>An array of notification identifiers. A notification ID is sent to your application in an <code>IN_APP_NOTIFY</code> broadcast intent every time a purchase changes state. You use the notification to retrieve the details of the purchase state change.</td>
 </tr>
 <tr>
   <td><code>DEVELOPER_PAYLOAD</code></td>
-  <td>String</td>
-  <td>Any valid String less than 256 characters long.</td>
+  <td><code>String</code></td>
+  <td>Any valid <code>String</code> less than 256 characters long.</td>
   <td>No</td>
-  <td>A developer-specified string that is associated with an order. This field is returned in the JSON string that contains transaction information for an order. You can use this field to send information with an order. For example, you can use this field to send index keys with an order, which is useful if you are using a database to store purchase information. We recommend that you do not use this field to send data or content.</td> 
+  <td>A developer-specified string that can be specified when you make a <code>REQUEST_PURCHASE</code> request. This field is returned in the JSON string that contains transaction information for an order. You can use this key to send supplemental information with an order. For example, you can use this key to send index keys with an order, which is useful if you are using a database to store purchase information. We recommend that you do not use this key to send data or content.</td>
 </tr>
 </table>
 
@@ -231,34 +225,81 @@
 
 <p>The following section describes the in-app billing broadcast intents that are sent by the Android Market application. These broadcast intents inform your application about in-app billing actions that have occurred. Your application must implement a {@link android.content.BroadcastReceiver} to receive these broadcast intents, such as the <code>BillingReceiver</code> that's shown in the in-app billing <a href="{@docRoot}guide/market/billing/billing_integrate.html#billing-download">sample application</a>.</p>
 
-<h4>ACTION_RESPONSE_CODE</h4>
+<h4>com.android.vending.billing.RESPONSE_CODE</h4>
 
-<p>This broadcast intent contains an Android Market response code, and is sent after you make an in-app billing request. A server response code can indicate that a billing request was successfully sent to Android Market or it can indicate that some error occurred during a billing request. This intent is not used to report any purchase state changes (such as refund or purchase information). For more information about the response codes that are sent with this response, see <a href="#billing-codes">Android Market Response Codes for In-app Billing</a>.</p>
+<p>This broadcast intent contains an Android Market response code, and is sent after you make an in-app billing request. A server response code can indicate that a billing request was successfully sent to Android Market or it can indicate that some error occurred during a billing request. This intent is not used to report any purchase state changes (such as refund or purchase information). For more information about the response codes that are sent with this response, see <a href="#billing-codes">Android Market Response Codes for In-app Billing</a>. The sample application assigns this broadcast intent to a constant named <code>ACTION_RESPONSE_CODE</code>.</p>
 
 <h5>Extras</h5>
 
 <ul type="none">
-  <li><code>INAPP_REQUEST_ID</code>&mdash;a long representing a request ID. A request ID identifies a specific billing request and is returned by Android Market at the time a request is made.</li>
-  <li><code>INAPP_RESPONSE_CODE</code>&mdash;an int representing the Android Market server response code.</li>
+  <li><code>request_id</code>&mdash;a <code>long</code> representing a request ID. A request ID identifies a specific billing request and is returned by Android Market at the time a request is made.</li>
+  <li><code>response_code</code>&mdash;an <code>int</code> representing the Android Market server response code.</li>
 </ul>
 
-<h4>ACTION_NOTIFY</h4>
+<h4>com.android.vending.billing.IN_APP_NOTIFY</h4>
 
-<p>This response indicates that a purchase has changed state, which means a purchase succeeded, was canceled, or was refunded. This response contains one or more notification IDs. Each notification ID corresponds to a specific server-side message, and each messages contains information about one or more transactions. After your application receives an <code>ACTION_NOTIFY</code> broadcast intent, you send a <code>GET_PURCHASE_INFORMATION</code> request with the notification IDs to retrieve the message details.</p>
+<p>This response indicates that a purchase has changed state, which means a purchase succeeded, was canceled, or was refunded. This response contains one or more notification IDs. Each notification ID corresponds to a specific server-side message, and each messages contains information about one or more transactions. After your application receives an <code>IN_APP_NOTIFY</code> broadcast intent, you send a <code>GET_PURCHASE_INFORMATION</code> request with the notification IDs to retrieve the message details. The sample application assigns this broadcast intent to a constant named <code>ACTION_NOTIFY</code>.</p>
 
 <h5>Extras</h5>
 
 <ul type="none">
-  <li><code>NOTIFICATION_ID</code>&mdash;a string representing the notification ID for a given purchase state change. Android Market notifies you when there is a purchase state change and the notification includes a unique notification ID. To get the details of the purchase state change, you send the notification ID with the <code>GET_PURCHASE_INFORMATION</code> request.</li>
+  <li><code>notification_id</code>&mdash;a <code>String</code> representing the notification ID for a given purchase state change. Android Market notifies you when there is a purchase state change and the notification includes a unique notification ID. To get the details of the purchase state change, you send the notification ID with the <code>GET_PURCHASE_INFORMATION</code> request.</li>
 </ul>
 
-<h4>ACTION_PURCHASE_STATE_CHANGED</h4>
+<h4>com.android.vending.billing.PURCHASE_STATE_CHANGED</h4>
 
-<p>This broadcast intent contains detailed information about one or more transactions. The transaction information is contained in a JSON string. The JSON string is signed and the signature is sent to your application along with the JSON string (unencrypted). To help ensure the security of your in-app billing messages, your application can verify the signature of this JSON string.</p>
+<p>This broadcast intent contains detailed information about one or more transactions. The transaction information is contained in a JSON string. The JSON string is signed and the signature is sent to your application along with the JSON string (unencrypted). To help ensure the security of your in-app billing messages, your application can verify the signature of this JSON string. The sample application assigns this broadcast intent to a constant named <code>ACTION_PURCHASE_STATE_CHANGED</code>.</p>
 
 <h5>Extras</h5>
 
 <ul type="none">
-  <li><code>INAPP_SIGNED_DATA</code>&mdash;a string representing the signed JSON string.</li>
-  <li><code>INAPP_SIGNATURE</code>&mdash;a string representing the signature.</li>
-</ul>
\ No newline at end of file
+  <li><code>inapp_signed_data</code>&mdash;a <code>String</code> representing the signed JSON string.</li>
+  <li><code>inapp_signature</code>&mdash;a <code>String</code> representing the signature.</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> Your application should map the broadcast intents and extras to constants that are unique to your application. See the <code>Consts.java</code> file in the sample application to see how this is done.</p>
+
+<p>The fields in the JSON string are described in the following table (see table 4):</p>
+
+<p class="table-caption"><strong>Table 4.</strong> Description of JSON fields that are returned with a <code>PURCHASE_STATE_CHANGED</code> intent.</p>
+
+<table>
+
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+<tr>
+  <td>nonce</td>
+  <td>A number used once. Your application generates the nonce and sends it with the <code>GET_PURCHASE_INFORMATION</code> request. Android Market sends the nonce back as part of the JSON string so you can verify the integrity of the message.</td>
+</tr>
+<tr>
+  <td>notificationId</td>
+  <td>A unique identifier that is sent with an <code>IN_APP_NOTIFY</code> broadcast intent. Each <code>notificationId</code> corresponds to a specify message that is waiting to be retrieved on the Android Market server. Your application sends back the <code>notificationId</code> with the <code>GET_PURCHASE_INFORMATION</code> message so Android Market can determine which messages you are retrieving.</td>
+</tr>
+<tr>
+  <td>orderId</td>
+  <td>A unique order identifier for the transaction. This corresponds to the Google Checkout Order ID.</td>
+</tr>
+<tr>
+  <td>packageName</td>
+  <td>The application package from which the purchase originated.</td>
+</tr>
+<tr>
+  <td>productId</td>
+  <td>The item's product identifier. Every item has a product ID, which you must specify in the application's product list on the Android Market publisher site.</td>
+</tr>
+<tr>
+  <td>purchaseTime</td>
+  <td>The time the product was purchased, in milliseconds since the epoch (Jan 1, 1970).</td>
+</tr>
+
+<tr>
+  <td>purchaseState</td>
+  <td>The purchase state of the order. Possible values are 0 (purchased), 1 (canceled), or 2 (refunded).</td>
+</tr>
+<tr>
+  <td>developerPayload</td>
+  <td>A developer-specified string that contains supplemental information about an order. You can specify a value for this field when you make a <code>REQUEST_PURCHASE</code> request.</td>
+</tr>
+</table>
diff --git a/docs/html/guide/market/billing/billing_testing.jd b/docs/html/guide/market/billing/billing_testing.jd
index 5ced9c7..c900e8b 100755
--- a/docs/html/guide/market/billing/billing_testing.jd
+++ b/docs/html/guide/market/billing/billing_testing.jd
@@ -3,12 +3,6 @@
 parent.link=index.html
 @jd:body
 
-<style type="text/css">
-  #jd-content {
-    background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
-  }
-</style>
-
 <div id="qv-wrapper">
 <div id="qv">
   <h2>In this document</h2>
@@ -33,28 +27,26 @@
 </div>
 
 <div class="special" style="margin-right:345px">
-  <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
+  <p>During the testing phase of the in-app billing release you cannot publish applications that implement in-app billing. You can only upload in-app billing applications as draft applications. For more information, see <a href="{@docRoot}guide/market/billing/billing_about.html">About this Release</a></p>
 </div>
 
 <p>The Android Market publisher site provides several tools that help you test your in-app billing implementation before it is published. You can use these tools to create test accounts and purchase special reserved items that send static billing responses to your application.</p>
 
 <p>To test in-app billing in an application you must install the application on an Android-powered device. You cannot use the Android emulator to test in-app billing.  The device you use for testing must run a standard version of the Android 1.6 or later platform (API level 4 or higher), and have the most current version of the Android Market application installed. If a device is not running the most current Android Market application, your application won't be able to send in-app billing requests to Android Market. For general information about how to set up a device for use in developing Android applications, see <a
-href="{@docRoot}guide/developing/device.html">Developing on a Device</a>.</p>
+href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a>.</p>
 
 <p>The following section shows you how to set up and use the in-app billing test tools.</p>
 
-<p class="note"><strong>Note</strong>: Debug log messages are turned off by default in the sample application. You can turn them on by setting the variable <code>DEBUG</code> to <code>true</code> in the <code>Consts.java</code> file.</p>
-
 <h2 id="billing-testing-static">Testing in-app purchases with static responses</h2>
 
-<p>We recommend that you first test your in-app billing implementation using static responses from Android Market. This enables you to verify that your application is handling the primary Android Market responses correctly and that your application is able to verify the signature correctly.</p>
+<p>We recommend that you first test your in-app billing implementation using static responses from Android Market. This enables you to verify that your application is handling the primary Android Market responses correctly and that your application is able to verify signatures correctly.</p>
 
 <p>To test your implementation with static responses, you make an in-app billing request using a special item that has a reserved product ID. Each reserved product ID returns a specific static response from Android Market. No money is transferred when you make in-app billing requests with the reserved product IDs. Also, you cannot specify the form of payment when you make a billing request with a reserved product ID. Figure 1 shows the checkout flow for the reserved item that has the product ID android.test.purchased.</p>
 
-<div style="margin:2em 1em 1em 1em;">
-<img src="{@docRoot}images/billing_test_flow.png" style="text-align:left;" />
-<div style="margin:.25em 1.25em;padding:0"><strong>Figure 1.</strong> Checkout flow for the special reserved item android.test.purchased.</div>
-</div>
+<img src="{@docRoot}images/billing_test_flow.png" height="381" id="figure1" />
+<p class="img-caption">
+  <strong>Figure 1.</strong> Checkout flow for the special reserved item android.test.purchased.
+</p>
 
 <p>You do not need to list the reserved products in your application's product list. Android Market already knows about the reserved product IDs. Also, you do not need to upload your application to the publisher site to perform static response tests with the reserved product IDs. You can simply install your application on a device, log into the device, and make billing requests using the reserved product IDs.</p>
 
@@ -68,14 +60,14 @@
     <p>When you make an in-app billing request with this product ID Android Market responds as though the purchase was canceled. This can occur when an error is encountered in the order process, such as an invalid credit card, or when you cancel a user's order before it is charged.</p>
   </li>
   <li><strong>android.test.refunded</strong>
-    <p>When you make an in-app billing request with this product ID, Android Market responds as though the purchase was refunded. Refunds cannot be initiated through the in-app billing feature. Refunds must be initiated by you (the merchant). A refund message is sent to your app by Android Market only when Android Market gets notification from Google Checkout that a refund has been made.</p>
+    <p>When you make an in-app billing request with this product ID, Android Market responds as though the purchase was refunded. Refunds cannot be initiated through the in-app billing feature. Refunds must be initiated by you (the merchant). A refund message is sent to your application by Android Market only when Android Market gets notification from Google Checkout that a refund has been made. For more information about refunds, see <a href="{@docRoot}guide/market/billing/billing_overview.html#billing-action-notify">Handling IN_APP_NOTIFY messages</a> and <a href="http://www.google.com/support/androidmarket/bin/answer.py?answer=1153485">In-app Billing Pricing</a>.</p>
   </li>
   <li><strong>android.test.item_unavailable</strong>
-    <p>When you make an in-app billing request with this product ID Android Market responds as though the item being purchased was not listed in your app's product list.</p>
+    <p>When you make an in-app billing request with this product ID, Android Market responds as though the item being purchased was not listed in your application's product list.</p>
   </li>
 </ul>
 
-<p>In some cases, the reserved items may return signed static responses, which lets you test signature verification in your application. To test signature verification with the special reserved product IDs, you may need to set up <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-testing-setup">trusted tester accounts</a> or upload your application as a unpublished draft application. The following table (Table 1) shows you the conditions under which static responses are signed.</p>
+<p>In some cases, the reserved items may return signed static responses, which lets you test signature verification in your application. To test signature verification with the special reserved product IDs, you may need to set up <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-testing-setup">test accounts</a> or upload your application as a unpublished draft application. Table 1 shows you the conditions under which static responses are signed.</p>
 
 <p class="table-caption" id="static-responses-table"><strong>Table 1.</strong>
 Conditions under which static responses are signed.</p>
@@ -119,7 +111,7 @@
 <tr>
 <td>Yes</td>
 <td>No</td>
-<td>Trusted tester</td>
+<td>Test account</td>
 <td>Signed</td>
 </tr>
 
@@ -134,6 +126,22 @@
 
 <p>To make an in-app billing request with a reserved product ID, you simply construct a normal <code>REQUEST_PURCHASE</code> request, but instead of using a real product ID from your application's product list you use one of the reserved product IDs.</p>
 
+<p>To test your application using the reserved product IDs, follow these steps:</p>
+
+<ol>
+  <li><strong>Install your application on an Android-powered device.</strong>
+    <p>You cannot use the emulator to test in-app billing; you must install your application on a device to test in-app billing.</p>
+    <p>To learn how to install an application on a device, see <a href="{@docRoot}guide/developing/building/building-cmdline.html#RunningOnDevice">Running on a device</a>.</p>
+  </li>
+  <li><strong>Sign in to your device with your developer account.</strong>
+    <p>You do not need to use a test account if you are testing only with the reserved product IDs.</p>
+  </li>
+  <li><strong>Verify that your device is running a supported version of the Android Market application or the MyApps application.</strong>
+    <p>If your device is running Android 3.0, in-app billing requires version 5.0.12 (or higher) of the MyApps application. If your device is running any other version of Android, in-app billing requires version 2.3.4 (or higher) of the Android Market application. To learn how to check the version of the Android Market application, see <a href="http://market.android.com/support/bin/answer.py?answer=190860">Updating Android Market</a>.</p>
+  </li>
+  <li><strong>Run your application and purchase the reserved product IDs.</strong></li>
+</ol>
+
 <p class="note"><strong>Note</strong>: Making in-app billing requests with the reserved product IDs overrides the usual Android Market production system. When you send an in-app billing request for a reserved product ID, the quality of service will not be comparable to the production environment.</p>
 
 <h2 id="billing-testing-real">Testing In-app Purchases Using Your Own Product IDs</h2>
@@ -146,29 +154,35 @@
 
 <p>Also, a test account can purchase an item in your product list only if the item is published. The application does not need to be published, but the item does need to be published.</p>
 
-<p>When you use a test account to purchase items, the account is billed through Google Checkout and your Google Checkout merchant account receives a payout for the purchase. Therefore, you need to refund purchases that are made with test accounts, otherwise the purchases will show up as actual payouts to your merchant account.</p>
+<p>When you use a test account to purchase items, the test account is billed through Google Checkout and your Google Checkout Merchant account receives a payout for the purchase. Therefore, you may want to refund purchases that are made with test accounts, otherwise the purchases will show up as actual payouts to your merchant account.</p>
 
 <p>To test your in-app billing implementation with actual purchases, follow these steps:</p>
 
 <ol>
-  <li>Upload your application as a draft application to the publisher site. You do not need to publish your application to perform end-to-end testing with real product IDs.</li>
-  <li>Add items to the application's product list. Make sure that you publish the items (the application can remain unpublished).
-    <p>See <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-catalog">Creating a product list</a> to learn how to do this.</p>
+  <li><strong>Upload your application as a draft application to the publisher site.</strong>
+    <p>You do not need to publish your application to perform end-to-end testing with real product IDs. To learn how to upload an application to Android Market, see <a href="http://market.android.com/support/bin/answer.py?answer=113469">Uploading applications</a>.</p>
   </li>
-  <li>Install your application on an Android-powered device.
-    <p>See <a href="{@docRoot}guide/developing/device.html">Developing on a Device</a> for more information about how to do this.</p>
+  <li><strong>Add items to the application's product list.</strong>
+    <p>Make sure that you publish the items (the application can remain unpublished). See <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-catalog">Creating a product list</a> to learn how to do this.</p>
   </li>
-  <li>Sign in to the device using one of the <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-testing-setup">trusted tester accounts</a> that you registered on the Android Market site.
-    <p>We recommend that you make the test account the primary account on the device. To sign in to a device, do the following:</p>
+  <li><strong>Install your application on an Android-powered device.</strong>
+    <p>You cannot use the emulator to test in-app billing; you must install your application on a device to test in-app billing.</p>
+    <p>To learn how to install an application on a device, see <a href="{@docRoot}guide/developing/building/building-cmdline.html#RunningOnDevice">Running on a device</a>.</p>
+  </li>
+ <li><strong>Make one of your test accounts the primary account on your device.</strong>
+    <p>To perform end-to-end testing of in-app billing, the primary account on your device must be one of the <a href="{@docRoot}guide/market/billing/billing_admin.html#billing-testing-setup">test accounts</a> that you registered on the Android Market site. If the primary account on your device is not a test account, you must do a factory reset of the device and then sign in with one of your test accounts. To perform a factory reset, do the following:</p>
     <ol>
-      <li>Open Settings &gt; Accounts &amp; sync</li>
-      <li>Select <strong>Add Account</strong> and choose to add a "Google" account.</li>
-      <li>Select <strong>Next</strong> and then <strong>Sign in</strong>.</li>
-      <li>Enter the username and password of the test account.</li>
-      <li>Select <strong>Sign in</strong>. The system signs you in to the new account.</li>
+      <li>Open Settings on your device.</li>
+      <li>Touch <strong>Privacy</strong>.</li>
+      <li>Touch <strong>Factory data reset</strong>.</li>
+      <li>Touch <strong>Reset phone</strong>.</li>
+      <li>After the phone resets, be sure to sign in with one of your test accounts during the device setup process.</li>
     </ol>
   </li>
-  <li>Make in-app purchases in your application.</li>
+  <li><strong>Verify that your device is running a supported version of the Android Market application or the MyApps application.</strong>
+    <p>If your device is running Android 3.0, in-app billing requires version 5.0.12 (or higher) of the MyApps application. If your device is running any other version of Android, in-app billing requires version 2.3.4 (or higher) of the Android Market application. To learn how to check the version of the Android Market application, see <a href="http://market.android.com/support/bin/answer.py?answer=190860">Updating Android Market</a>.</p>
+  </li>
+  <li><strong>Make in-app purchases in your application.</strong></li>
 </ol>
 
 <p class="note"><strong>Note:</strong> The only way to change the primary account on a device is to do a factory reset, making sure you log on with your primary account first.</p>
diff --git a/docs/html/guide/market/billing/index.jd b/docs/html/guide/market/billing/index.jd
index 6985179..e7f8ee3 100755
--- a/docs/html/guide/market/billing/index.jd
+++ b/docs/html/guide/market/billing/index.jd
@@ -1,12 +1,6 @@
 page.title=In-app Billing
 @jd:body
 
-<style type="text/css">
-  #jd-content {
-    background:transparent url({@docRoot}assets/images/preliminary.png) repeat scroll 0 0;
-  }
-</style>
-
 <div id="qv-wrapper">
 <div id="qv">
 
@@ -30,23 +24,23 @@
 </div>
 
 <div class="special" style="margin-right:345px">
-  <p>This documentation provides an early look at the Android Market In-app Billing service. The documentation may change without notice.</p>
+  <p>During the testing phase of the in-app billing release you cannot publish applications that implement in-app billing. You can only upload in-app billing applications as draft applications. For more information, see <a href="{@docRoot}guide/market/billing/billing_about.html">About this Release</a></p>
 </div>
 
 <p>In-app billing is an Android Market service that lets you sell digital content in your applications. You can use the service to sell a wide range of content, including downloadable content such as media files or photos, and virtual content such as game levels or potions.</p>
 
-<p>When you use the Android Market In-app Billing service to sell an item, Android Market handles all checkout details so your application never has to directly process any financial transactions. Android Market uses the same checkout service that is used for application purchases, so your users experience a consistent and familiar purchase flow (see figure 1). Also, the transaction fee for in-app purchases is the same as the transaction fee for application purchases (30%).</p>
+<p>When you use the Android Market in-app billing service to sell an item, Android Market handles all checkout details so your application never has to directly process any financial transactions. Android Market uses the same checkout service that is used for application purchases, so your users experience a consistent and familiar purchase flow (see figure 1). Also, the transaction fee for in-app purchases is the same as the transaction fee for application purchases (30%).</p>
 
-<p>Any application that you publish through Android Market can implement in-app billing. No special account or registration is required other than an Android Market publisher account and a Google Checkout merchant account. Also, because the service uses no dedicated framework APIs, you can add in-app billing to any application that uses a minimum API level of 4 or higher.</p>
+<p>Any application that you publish through Android Market can implement in-app billing. No special account or registration is required other than an Android Market publisher account and a Google Checkout Merchant account. Also, because the service uses no dedicated framework APIs, you can add in-app billing to any application that uses a minimum API level of 4 or higher.</p>
 
 <p>To help you integrate in-app billing into your application, the Android SDK provides a sample application that demonstrates a simple implementation of in-app billing. The sample application contains examples of billing-related classes you can use to implement in-app billing in your application. It also contains examples of the database, user interface, and business logic you might use to implement in-app billing.</p>
 
 <p class="caution"><strong>Important</strong>: Although the sample application is a working example of how you can implement in-app billing, we <em>strongly recommend</em> that you modify and obfuscate the sample code before you use it in a production application. For more information, see <a href="{@docRoot}guide/market/billing/billing_best_practices.html">Security and Design</a>.</p>
 
-<div style="margin:2em 1em 1em 1em;">
-<img src="{@docRoot}images/billing_checkout_flow.png" style="text-align:left;" />
-<div style="margin:.25em 1.25em;padding:0"><strong>Figure 1.</strong> Applications initiate in-app billing requests through their own UI (first screen). Android Market responds to the request by providing the checkout user interface (middle screen). When checkout is complete, the application resumes.</div>
-</div>
+<img src="{@docRoot}images/billing_checkout_flow.png" height="382" id="figure1" />
+<p class="img-caption">
+  <strong>Figure 1.</strong> Applications initiate in-app billing requests through their own UI (first screen). Android Market responds to the request by providing the checkout user interface (middle screen). When checkout is complete, the application resumes.
+</p>
 
 <p>To learn more about the in-app billing service and start integrating in-app billing into your applications, read the following documents:</p>
 
diff --git a/docs/html/guide/practices/design/accessibility.jd b/docs/html/guide/practices/design/accessibility.jd
new file mode 100644
index 0000000..a2b314e
--- /dev/null
+++ b/docs/html/guide/practices/design/accessibility.jd
@@ -0,0 +1,351 @@
+page.title=Designing for Accessibility
+@jd:body
+
+
+<div id="qv-wrapper">
+<div id="qv">
+
+  <h2>Quickview</h2>
+  <ul>
+    <li>To make your application more accessible, you should make sure your UI is navigable
+using a directional controller and your widgets provide content descriptions</li>
+    <li>If you implement a custom view, you should ensure that it delivers the appropriate
+accessibility events during user interaction</li>
+  </ul>
+
+  <h2>In this document</h2>
+  <ol>
+    <li><a href="#Navigation">Allow Navigation with a Directional Controller</a>
+      <ol>
+        <li><a href="#FocusOrder">Controlling focus order</a></li>
+        <li><a href="#ClickingDpad">Clicking with a directional controller</a></li>
+      </ol>
+    </li>
+    <li><a href="#LabelInputs">Label Your Input Widgets</a></li>
+    <li><a href="#UiBestPractices">Follow Android UI Best Practices</a></li>
+    <li><a href="#CustomViews">Send Accessibility Events from Custom View Components</a></li>
+    <li><a href="#Test">Test Your Application’s Accessibility</a></li>
+  </ol>
+
+  <h2>Key classes</h2>
+  <ol>
+    <li>{@link android.view.accessibility.AccessibilityEvent}</li>
+    <li>{@link android.view.accessibility.AccessibilityEventSource}</li>
+  </ol>
+
+  <h2>Related samples</h2>
+  <ol>
+    <li><a
+href="{@docRoot}resources/samples/AccessibilityService/index.html">Accessibility Service</a></li>
+  </ol>
+
+</div>
+</div>
+
+
+
+<p>Many Android users have disabilities that require them to interact with their Android devices in
+different ways.  These include users who have visual, physical or age-related disabilities that
+prevent them from fully using or seeing a touchscreen.</p>
+
+<p>Android provides an accessibility layer that helps these users navigate their Android-powered
+devices more easily.  Android's accessibility services provide things like text-to-speech, haptic
+feedback, and trackball/d-pad navigation that augment the user experience.</p>
+
+<p>Your application should follow the guidelines in this document to ensure that it provides a
+good experience for users with disabilities. Following these two basic rules will solve most
+access-related problems:</p>
+
+<ul>
+<li>Make all of your user interface controls accessible with a trackball or directional
+controller (d-pad).</li>
+<li>Label your {@link android.widget.ImageButton}, {@link android.widget.EditText}, and other input
+widgets using the <a href="{@docRoot}reference/android/view/View#attr_android:contentDescription"
+>{@code android:contentDescription}</a> attribute.</li>
+</ul>
+
+
+
+<h2 id="Navigation">Allow Navigation with a Directional Controller</h2>
+
+<p>Many Android devices come with some sort of directional controller, such as:</p>
+<ul>
+<li>A clickable trackball that users can move in any direction</li>
+<li>A clickable d-pad that allows users to navigate in four directions.</li>
+<li>Arrow keys and an OK button that’s equivalent to clicking a trackball or d-pad.</li>
+</ul>
+
+<p>All of these directional controllers allow users to navigate the screen without using the
+touchscreen. On some devices, a user can also navigate to the top or bottom of a list by holding
+down the <em>alt</em> key while pressing a discrete key for up or down.</p>
+
+<p>A directional controller is the primary means of navigation for users with visual or some
+physical impairments (and also for users without impairments when using devices that don't
+have a touchscreen). You should verify that all UI controls in your application are
+accessible without using the touchscreen and that clicking with the center button (or OK button) has
+the same effect as touching the controls on the touchscreen.</p>
+
+<p>A UI control (also called a "widget") is accessible using directional controls when it's
+"focusable" property is "true." This means that users can focus on the widget using the directional
+controls and then interact with it. Widgets provided by the Android APIs are focusable by default
+and visually indicate focus by changing the widget visual appearance in some way.</p>
+
+<p>Android provides several APIs that let you control whether a widget is focusable and even
+request that a widget be given focus. Such methods include:</p>
+
+<ul>
+  <li>{@link android.view.View#setFocusable setFocusable()}</li>
+  <li>{@link android.view.View#isFocusable isFocusable()}</li>
+  <li>{@link android.view.View#requestFocus requestFocus()}</li>
+</ul>
+
+<p>When working with a view that is not focusable by default, you can make it focusable from the XML
+layout file by setting the <a href="{@docRoot}reference/android/view/View#attr_android:focusable"
+>{@code android:focusable}</a> attribute to {@code "true"}.</p>
+
+
+
+<h3 id="FocusOrder">Controlling focus order</h3>
+
+<p>When the user navigates in any direction using the directional controls, focus is passed from one
+view to another, as determined by the focus ordering. The ordering of the focus movement is based on
+an algorithm that finds the nearest neighbor in a given direction. In rare cases, the default
+algorithm may not match the order that you intended for your UI. In these situations, you can
+provide explicit overrides to the ordering using the following XML attributes in the layout
+file:</p>
+
+<dl>
+ <dt><a href="{@docRoot}reference/android/view/View.html#attr_android:nextFocusDown"
+>{@code android:nextFocusDown}</a></dt>
+  <dd>Defines the next view to receive focus when the user navigates down.</dd>
+ <a><a href="{@docRoot}reference/android/view/View.html#attr_android:nextFocusLeft"
+>{@code android:nextFocusLeft}</a></dt>
+  <dd>Defines the next view to receive focus when the user navigates left.</dd>
+ <dt><a href="{@docRoot}reference/android/view/View.html#attr_android:nextFocusRight"
+>{@code android:nextFocusRight}</a></dt>
+  <dd>Defines the next view to receive focus when the user navigates right.</dd>
+ <dt><a href="{@docRoot}reference/android/view/View.html#attr_android:nextFocusUp"
+>{@code android:nextFocusUp}</a></dt>
+  <dd>Defines the next view to receive focus when the user navigates up.</dd>
+</dl>
+
+<p>For example, here is an XML layout that contains a focusable {@link android.widget.TextView}.
+While the {@link android.widget.TextView} is located to the right of the {@link
+android.widget.EditText}, it can now be reached by pressing the down arrow when focus is on the
+{@link android.widget.EditText}: </p>
+
+<pre>
+&lt;LinearLayout android:orientation="horizontal"
+              ... &gt;
+    &lt;EditText android:id="@+id/edit"
+              android:nextFocusDown=”@+id/text”
+              ... /&gt;
+    &lt;TextView android:id="@+id/text"
+              android:focusable=”true”
+              android:text="Hello, I am a focusable TextView"
+              android:nextFocusUp=”@id/edit”
+              ... /&gt;
+&lt;/LinearLayout&gt;
+</pre>
+
+<p>When modifying this ordering, be sure that the navigation works as expected in all directions
+from each widget and when navigating in reverse (to get back to where you came from).</p>
+
+<p>You can also modify the focus ordering at runtime, using methods in the {@link
+android.view.View} class, such as {@link android.view.View#setNextFocusDownId
+setNextFocusDownId()} and  {@link android.view.View#setNextFocusRightId
+setNextFocusRightId()}.</p>
+
+
+<h3 id="ClickingDpad">Clicking with a directional controller</h3>
+
+<p>On most devices, clicking a view using a directional controller sends a {@link
+android.view.KeyEvent} with {@link android.view.KeyEvent#KEYCODE_DPAD_CENTER} to the view currently
+in focus. Make sure this event has the same effect as touching the view on the touchscreen. All
+standard Android views already handle {@link android.view.KeyEvent#KEYCODE_DPAD_CENTER}
+appropriately.</p>
+
+<p>If possible, also treat the {@link android.view.KeyEvent#KEYCODE_ENTER} event the same as
+{@link android.view.KeyEvent#KEYCODE_DPAD_CENTER}.  That makes interaction much easier from a full
+keyboard.</p>
+
+
+
+
+<h2 id="LabelInputs">Label Your Input Widgets</h2>
+
+<p>Many input widgets rely on visual cues to inform the user of their meaning.  For example, a
+notepad application might use an {@link android.widget.ImageButton} with a picture of a plus sign to
+indicate that the user can add a new note.  Or, an {@link android.widget.EditText} may have
+a label near it that indicates its purpose.  When a visually impaired user accesses your
+application, these visual cues are often useless.</p>
+
+<p>To provide textual information about these widgets (as an alternative to the visual cues), you
+should use the <a href="{@docRoot}reference/android/view/View#attr_android:contentDescription"
+>{@code android:contentDescription}</a> attribute. The text you provide in this attribute
+is not visible on the screen, but if a user has enabled accessibility speech tools then the
+description in this attribute is read aloud to the user.</p>
+
+<p>You should set the <a
+href="{@docRoot}reference/android/view/View#attr_android:contentDescription" >{@code
+android:contentDescription}</a> attribute on every {@link android.widget.ImageButton}, {@link
+android.widget.EditText}, {@link android.widget.CheckBox}, and on any other input widgets that might
+benefit users with extra information.</p>
+
+<p>For example, the following {@link android.widget.ImageButton} sets the content description for
+the plus button to the {@code add_note} string resource, which might be defined in English as
+“Add note":</p>
+
+<pre>
+&lt;ImageButton
+    android:id=”@+id/add_entry_button”
+    android:src=”@drawable/plus”
+    android:contentDescription=”@string/add_note”/&gt;
+</pre>
+
+<p>This way, when using speech accessibility tools, the user hears "Add note" when focused on
+this widget.</p>
+
+
+
+<h2 id="UiBestPractices">Follow Android UI Best Practices</h2>
+
+<p>You can make it easier for users to learn how to use your application by developing a user
+interface that complies with Android's standard interaction patterns, instead of creating your own
+or using interaction patterns from another platform. This consistency is especially important for
+many disabled users, as they may have less contextual information available to try to understand
+your application’s interface.</p>
+
+<p>Specifically, you should:</p>
+
+<ul>
+<li>Use the platform's built-in widgets and layouts whenever possible, as these views provide
+accessibility support by default.</li>
+<li>Use the <a href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options Menu</a> as an
+alternative to complex touchscreen tasks.</li>
+<li>Make sure the BACK button correctly moves the user back one logical step in the <a
+href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">task's back stack</a> or the
+activity's back stack of fragments (when <a
+href="{@docRoot}guide/topics/fundamentals/fragments.html#Transactions">performing fragment
+transactions</a>), as appropriate.</li>
+</ul>
+
+
+
+<h2 id="CustomViews">Send Accessibility Events from Custom View Components</h2>
+
+<p>If your application requires that you create a <a
+href="{@docRoot}guide/topics/ui/custom-components.html">custom view component</a>, you may need to
+do some additional work to ensure that your view is accessible.  Specifically, you should make sure
+that your view implements the {@link android.view.accessibility.AccessibilityEventSource}
+interface and emits {@link android.view.accessibility.AccessibilityEvent}s at the proper times,
+and that each {@link android.view.accessibility.AccessibilityEvent} contains relevant information
+about the state of the view.</p>
+
+<p>Events are emitted whenever something notable happens in the user interface.  Currently, there
+are five types of accessibility events that a view should send to the system as the user interacts
+with it:</p>
+
+<dl>
+<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED}</dt>
+<dd>Indicates that the user clicked on the view (for example, the user selects a button).</dd>
+
+<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}</dt>
+<dd>Indicates that the user performed a long press on the view. </dd>
+
+<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED}</dt>
+<dd>Indicates that the user selected an item from within the view. This is usually used in the
+context of an {@link android.widget.AdapterView}.</dd>
+
+<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED}</dt>
+<dd>Indicates that the user moved the focus to the view.</dd>
+
+<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}</dt>
+<dd>Indicates that the text or contents of the view changed.</dd>
+</dl>
+
+
+<p>The basic {@link android.view.View} class implements {@link
+android.view.accessibility.AccessibilityEventSource} and emits these events at the proper time in
+the standard cases.  Your custom view should extend from {@link android.view.View} (or one of its
+subclasses) to take advantage of these default implementations.</p>
+
+<p>Depending on the specifics of your custom view, your view may need to emit one of these events at
+a different time than the default {@link android.view.View} implementation.  To do so, simply call
+{@link android.view.accessibility.AccessibilityEventSource#sendAccessibilityEvent
+sendAccessibilityEvent()} with the specific event type at the correct time.</p>
+
+<p>For example, say you are implementing a custom slider bar that allows the user to select a
+numeric value by pressing the left or right arrows.  This view should emit an event of type {@link
+android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED} whenever the slider value
+changes:</p>
+
+<pre>
+&#64;Override
+public boolean onKeyUp (int keyCode, KeyEvent event) {
+  if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
+    mCurrentValue--;
+    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
+    return true;
+  }
+  ...
+}
+</pre>
+
+<p>Each {@link android.view.accessibility.AccessibilityEvent} has a set of required properties that
+describe the current state of the view.  These properties include things like the view’s class name,
+text and checked state.  The specific properties required for each event type are described in the
+{@link android.view.accessibility.AccessibilityEvent} documentation.  The {@link android.view.View}
+implementation will fill in default values for these properties. Most of these values, like the
+class name and event timestamp, will not need to be changed. However, depending on the specifics of
+your custom view, you may want to provide a different value for one or more of the properties.  For
+example, your view may have additional state information that you want to add to the event text.</p>
+
+<p>The {@link android.view.View#dispatchPopulateAccessibilityEvent
+dispatchPopulateAccessibilityEvent()} method in {@link android.view.View} provides a hook for making
+changes to the {@link android.view.accessibility.AccessibilityEvent} object before it is
+emitted.</p>
+
+<p>In the above slider bar example, the view should add the current value of the slider bar to the
+text of the event:</p>
+
+<pre>
+&#64;Override
+public boolean dispatchPopulateAccessibilityEvent(final AccessibilityEvent event) {
+  super.dispatchPopulateAccessibilityEvent(event);
+  if (!isShown()) {
+    return false;
+  }
+  CharSequence text = String.valueOf(mCurrentValue);
+  if (text.length() > AccessibilityEvent.MAX_TEXT_LENGTH) {
+    text = text.subSequence(0, AccessiblityEvent.MAX_TEXT_LENGTH);
+  }
+  event.getText().add(text);
+  return true;
+}
+</pre>
+
+
+<h2 id="Test">Test Your Application’s Accessibility</h2>
+
+<p>You can simulate the experience for many users by enabling an accessibility service that speaks
+as you move around the screen.  One such service is <a
+href="https://market.android.com/details?id=com.google.android.marvin.talkback">TalkBack</a>, by the
+<a href="http://code.google.com/p/eyes-free/">Eyes-Free Project</a>.  It comes preinstalled on many
+Android-powered devices, but is also available for free from <a
+href="https://market.android.com/details?id=com.google.android.marvin.talkback">Android
+Market</a>.</p>
+
+<p>This service requires that you have a text-to-speech engine installed on your phone.  You can
+verify if you have one installed in the <strong>Text-to-speech</strong> settings menu by selecting
+<strong>Listen to an example</strong>. If you do not hear anything spoken, install the required
+voice data by selecting <strong>Install voice data</strong>.</p>
+
+<p>Once text-to-speech is functioning correctly, you can enable TalkBack (or another accessibility
+service) in the <strong>Accessibility</strong> settings menu.  Enable both
+<strong>Accessibility</strong> and <strong>TalkBack</strong>.  As you navigate about the device, you
+should now hear spoken feedback.</p>
+
+<p>You can now attempt to use your application as a blind user would.  As you move around using only
+the directional controller, make sure that the spoken feedback you hear makes sense and is
+sufficient to navigate the application without any visual cues.</p>
diff --git a/docs/html/images/billing_product_list_entry.png b/docs/html/images/billing_product_list_entry.png
new file mode 100755
index 0000000..b7bfc7a
--- /dev/null
+++ b/docs/html/images/billing_product_list_entry.png
Binary files differ
diff --git a/docs/html/images/billing_refund.png b/docs/html/images/billing_refund.png
new file mode 100755
index 0000000..09fc33c
--- /dev/null
+++ b/docs/html/images/billing_refund.png
Binary files differ
diff --git a/docs/html/images/billing_request_purchase.png b/docs/html/images/billing_request_purchase.png
index e8a1b30..c84016e 100755
--- a/docs/html/images/billing_request_purchase.png
+++ b/docs/html/images/billing_request_purchase.png
Binary files differ
diff --git a/docs/html/images/billing_restore_transactions.png b/docs/html/images/billing_restore_transactions.png
index 116aa0e..7911304 100755
--- a/docs/html/images/billing_restore_transactions.png
+++ b/docs/html/images/billing_restore_transactions.png
Binary files differ
diff --git a/docs/html/images/drm_arch.png b/docs/html/images/drm_arch.png
new file mode 100755
index 0000000..1696a97
--- /dev/null
+++ b/docs/html/images/drm_arch.png
Binary files differ
diff --git a/docs/html/sdk/oem-usb.jd b/docs/html/sdk/oem-usb.jd
index e64c8d2..882a433 100644
--- a/docs/html/sdk/oem-usb.jd
+++ b/docs/html/sdk/oem-usb.jd
@@ -33,14 +33,17 @@
     <th>OEM</th>
     <th>Driver URL</th></tr>
 <tr><td>Acer</td>	<td><a
-href="http://www.acer.com/worldwide/support/mobile.html">http://www.acer.com/worldwide/support/
-mobile.html</a>
+href="http://www.acer.com/worldwide/support/mobile.html">http://www.acer.com/worldwide/support/mobile.html</a>
     </td></tr>
-
-<tr><td>Dell</td>	<td>
+  <tr>
+    <td>Asus</td>
+    <td><a href="http://support.asus.com/download/">http://support.asus.com/download/</a></td>
+  </tr>
+  <tr><td>
+       Dell
+    </td>	<td>
       <a
-href="http://support.dell.com/support/downloads/index.aspx?c=us&cs=19&l=en&s=dhs&~ck=anavml">http://
-support.dell.com/support/downloads/index.aspx?c=us&cs=19&l=en&s=dhs&~ck=anavml</a>  </td></tr>
+href="http://support.dell.com/support/downloads/index.aspx?c=us&cs=19&l=en&s=dhs&~ck=anavml">http://support.dell.com/support/downloads/index.aspx?c=us&cs=19&l=en&s=dhs&~ck=anavml</a>  </td></tr>
 
 <tr><td>Foxconn</td>	<td><a
 href="http://drivers.cmcs.com.tw/">http://drivers.cmcs.com.tw/</a></td>
@@ -56,17 +59,14 @@
   <tr><td>
        Garmin-Asus
     </td>	<td><a
-href="https://www.garminasus.com/en_US/support/pcsync/">https://www.garminasus.com/en_US/support/
-pcsync/</a></td>
+href="https://www.garminasus.com/en_US/support/pcsync/">https://www.garminasus.com/en_US/support/pcsync/</a></td>
 </tr><tr><td>HTC</td>	<td><a href="http://www.htc.com">http://www.htc.com </a> <br>Click on the
 support tab to select your products/device.  Different regions will have different links.</td>
 </tr>
 <tr><td>Huawei</td>	<td><a
-href="http://www.huaweidevice.com/worldwide/downloadCenter.do?method=list&flay=software&directoryId=20&treeId=0">http://www.huaweidevice.com/worldwide/downloadCenter.do?method=list&flay=software&
-directoryId=20&treeId=0</a></td>
+href="http://www.huaweidevice.com/worldwide/downloadCenter.do?method=list&flay=software&directoryId=20&treeId=0">http://www.huaweidevice.com/worldwide/downloadCenter.do?method=list&flay=software&directoryId=20&treeId=0</a></td>
 </tr><tr><td>KT Tech</td>	<td><a
-href="http://www.kttech.co.kr/cscenter/download05.asp">http://www.kttech.co.kr/cscenter/download05.
-asp</a> for EV-S100(Take)</td>
+href="http://www.kttech.co.kr/cscenter/download05.asp">http://www.kttech.co.kr/cscenter/download05.asp</a> for EV-S100(Take)</td>
 </tr>
   <tr>
     <td>
@@ -76,26 +76,19 @@
     </td>
   </tr>
   <tr><td>LGE</td>	<td><a
-href="http://www.lg.com/us/mobile-phones/mobile-support/mobile-lg-mobile-phone-support.jsp">http://
-www.lg.com/us/mobile-phones/mobile-support/mobile-lg-mobile-phone-support.jsp</a></td>
+href="http://www.lg.com/us/mobile-phones/mobile-support/mobile-lg-mobile-phone-support.jsp">http://www.lg.com/us/mobile-phones/mobile-support/mobile-lg-mobile-phone-support.jsp</a></td>
 </tr><tr><td>Motorola</td>	<td><a
-href="http://developer.motorola.com/docstools/USB_Drivers/">http://developer.motorola.com/docstools/
-USB_Drivers/</a></td>
+href="http://developer.motorola.com/docstools/USB_Drivers/">http://developer.motorola.com/docstools/USB_Drivers/</a></td>
 </tr><tr><td>Pantech</td>	<td><a
-href="http://www.isky.co.kr/cs/software/software.sky?fromUrl=index">http://www.isky.co.kr/cs/
-software/software.sky?fromUrl=index</a></td>
+href="http://www.isky.co.kr/cs/software/software.sky?fromUrl=index">http://www.isky.co.kr/cs/software/software.sky?fromUrl=index</a></td>
 </tr><tr><td>Samsung</td>	<td><a
-href="http://www.samsung.com/us/support/downloads">http://www.samsung.com/us/support/downloads</a></
-td>
+href="http://www.samsung.com/us/support/downloads">http://www.samsung.com/us/support/downloads</a></td>
 </tr><tr><td>Sharp</td>	<td><a
 href="http://k-tai.sharp.co.jp/support/">http://k-tai.sharp.co.jp/support/</a></td>
 </tr><tr><td>SK Telesys</td>	<td><a
-href="http://www.sk-w.com/service/wDownload/wDownload.jsp">http://www.sk-w.com/service/wDownload/
-wDownload.jsp</a></td></tr><tr>
+href="http://www.sk-w.com/service/wDownload/wDownload.jsp">http://www.sk-w.com/service/wDownload/wDownload.jsp</a></td></tr><tr>
 <td>Sony Ericsson</td>	<td><a
-href="http://developer.sonyericsson.com/wportal/devworld/search-downloads/android">http://developer.
-sonyericsson.com/wportal/devworld/search-downloads/android</a></td></tr><tr>
+href="http://developer.sonyericsson.com/wportal/devworld/search-downloads/android">http://developer.sonyericsson.com/wportal/devworld/search-downloads/android</a></td></tr><tr>
 <td>ZTE</td>	<td><a
-href="http://www.zte.com.cn/cn/products/mobile/services_support/index.jsp">http://www.zte.com.cn/cn/
-products/mobile/services_support/index.jsp</a></td></tr>
+href="http://www.zte.com.cn/cn/products/mobile/services_support/index.jsp">http://www.zte.com.cn/cn/products/mobile/services_support/index.jsp</a></td></tr>
 </table>
diff --git a/drm/common/DrmSupportInfo.cpp b/drm/common/DrmSupportInfo.cpp
index c0bff0e..3dee435 100644
--- a/drm/common/DrmSupportInfo.cpp
+++ b/drm/common/DrmSupportInfo.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <drm/DrmSupportInfo.h>
+#include <strings.h>
 
 using namespace android;
 
@@ -152,4 +153,3 @@
     mIndex++;
     return value;
 }
-
diff --git a/drm/java/android/drm/DrmConvertedStatus.java b/drm/java/android/drm/DrmConvertedStatus.java
old mode 100644
new mode 100755
index f200552..cecb135
--- a/drm/java/android/drm/DrmConvertedStatus.java
+++ b/drm/java/android/drm/DrmConvertedStatus.java
@@ -17,13 +17,11 @@
 package android.drm;
 
 /**
- * This is an entity class which wraps the status of the conversion, the converted
- * data/checksum data and the offset. Offset is going to be used in the case of close
- * session where the agent will inform where the header and body signature should be added
- *
- * As a result of {@link DrmManagerClient#convertData(int, byte [])} and
- * {@link DrmManagerClient#closeConvertSession(int)} an instance of DrmConvertedStatus
- * would be returned.
+ * An entity class that wraps converted data, conversion status, and the
+ * offset for appending the header and body signature to the converted data. An instance of this
+ * class is returned by the {@link DrmManagerClient#convertData convertData()} and
+ * {@link DrmManagerClient#closeConvertSession closeConvertSession()} methods. The offset is provided only when a
+ * conversion session is closed by calling {@link DrmManagerClient#closeConvertSession closeConvertSession()}.
  *
  */
 public class DrmConvertedStatus {
@@ -32,16 +30,19 @@
     public static final int STATUS_INPUTDATA_ERROR = 2;
     public static final int STATUS_ERROR = 3;
 
+    /** Status code for the conversion.*/
     public final int statusCode;
+    /** Converted data.*/
     public final byte[] convertedData;
+    /** Offset value for the body and header signature.*/
     public final int offset;
 
     /**
-     * constructor to create DrmConvertedStatus object with given parameters
+     * Creates a <code>DrmConvertedStatus</code> object with the specified parameters.
      *
-     * @param _statusCode Status of the conversion
-     * @param _convertedData Converted data/checksum data
-     * @param _offset Offset value
+     * @param _statusCode Conversion status.
+     * @param _convertedData Converted data.
+     * @param _offset Offset value for appending the header and body signature.
      */
     public DrmConvertedStatus(int _statusCode, byte[] _convertedData, int _offset) {
         statusCode = _statusCode;
diff --git a/drm/java/android/drm/DrmErrorEvent.java b/drm/java/android/drm/DrmErrorEvent.java
old mode 100644
new mode 100755
index 7cc9a87..2cb82e6
--- a/drm/java/android/drm/DrmErrorEvent.java
+++ b/drm/java/android/drm/DrmErrorEvent.java
@@ -19,70 +19,69 @@
 import java.util.HashMap;
 
 /**
- * This is an entity class which would be passed to caller in
- * {@link DrmManagerClient.OnErrorListener#onError(DrmManagerClient, DrmErrorEvent)}
+ * An entity class that is passed to the
+ * {@link DrmManagerClient.OnErrorListener#onError onError()} callback.
  *
  */
 public class DrmErrorEvent extends DrmEvent {
     /**
-     * TYPE_RIGHTS_NOT_INSTALLED, when something went wrong installing the rights.
+     * Something went wrong installing the rights.
      */
     public static final int TYPE_RIGHTS_NOT_INSTALLED = 2001;
     /**
-     * TYPE_RIGHTS_RENEWAL_NOT_ALLOWED, when the server rejects renewal of rights.
+     * The server rejected the renewal of rights.
      */
     public static final int TYPE_RIGHTS_RENEWAL_NOT_ALLOWED = 2002;
     /**
-     * TYPE_NOT_SUPPORTED, when answer from server can not be handled by the native agent.
+     * Response from the server cannot be handled by the DRM plug-in (agent).
      */
     public static final int TYPE_NOT_SUPPORTED = 2003;
     /**
-     * TYPE_OUT_OF_MEMORY, when memory allocation fail during renewal.
-     * Can in the future perhaps be used to trigger garbage collector.
+     * Memory allocation failed during renewal. Can in the future perhaps be used to trigger 
+     * garbage collector.
      */
     public static final int TYPE_OUT_OF_MEMORY = 2004;
     /**
-     * TYPE_NO_INTERNET_CONNECTION, when the Internet connection is missing and no attempt
-     * can be made to renew rights.
+     * An Internet connection is not available and no attempt can be made to renew rights.
      */
     public static final int TYPE_NO_INTERNET_CONNECTION = 2005;
     /**
-     * TYPE_PROCESS_DRM_INFO_FAILED, when failed to process DrmInfo.
+     * Failed to process {@link DrmInfo}. This error event is sent when a
+     * {@link DrmManagerClient#processDrmInfo processDrmInfo()} call fails.
      */
     public static final int TYPE_PROCESS_DRM_INFO_FAILED = 2006;
     /**
-     * TYPE_REMOVE_ALL_RIGHTS_FAILED, when failed to remove all the rights objects
-     * associated with all DRM schemes.
+     * Failed to remove all the rights objects associated with all DRM schemes.
      */
     public static final int TYPE_REMOVE_ALL_RIGHTS_FAILED = 2007;
     /**
-     * TYPE_ACQUIRE_DRM_INFO_FAILED, when failed to acquire DrmInfo.
+     * Failed to acquire {@link DrmInfo}. This error event is sent when an
+     * {@link DrmManagerClient#acquireDrmInfo acquireDrmInfo()} call fails.
      */
     public static final int TYPE_ACQUIRE_DRM_INFO_FAILED = 2008;
 
     /**
-     * constructor to create DrmErrorEvent object with given parameters
+     * Creates a <code>DrmErrorEvent</code> object with the specified parameters.
      *
-     * @param uniqueId Unique session identifier
-     * @param type Type of the event. It could be one of the types defined above
-     * @param message Message description
+     * @param uniqueId Unique session identifier.
+     * @param type Type of the event. Could be any of the event types defined above.
+     * @param message Message description.
      */
     public DrmErrorEvent(int uniqueId, int type, String message) {
         super(uniqueId, type, message);
     }
 
     /**
-     * constructor to create DrmErrorEvent object with given parameters
+     * Creates a <code>DrmErrorEvent</code> object with the specified parameters.
      *
-     * @param uniqueId Unique session identifier
-     * @param type Type of the event. It could be one of the types defined above
-     * @param message Message description
+     * @param uniqueId Unique session identifier.
+     * @param type Type of the event. Could be any of the event types defined above.
+     * @param message Message description.
      * @param attributes Attributes for extensible information. Could be any
-     * information provided by the plugin
+     * information provided by the plug-in.
      */
     public DrmErrorEvent(int uniqueId, int type, String message,
                             HashMap<String, Object> attributes) {
         super(uniqueId, type, message, attributes);
     }
 }
-
diff --git a/drm/java/android/drm/DrmEvent.java b/drm/java/android/drm/DrmEvent.java
old mode 100644
new mode 100755
index eba458b..4053eb3
--- a/drm/java/android/drm/DrmEvent.java
+++ b/drm/java/android/drm/DrmEvent.java
@@ -19,22 +19,26 @@
 import java.util.HashMap;
 
 /**
- * This is the base class which would be used to notify the caller
- * about any event occurred in DRM framework.
+ * A base class that is used to send asynchronous event information from the DRM framework.
  *
  */
 public class DrmEvent {
     /**
-     * Constant field signifies that all the rights information associated with
-     * all DRM schemes are removed successfully
+     * All of the rights information associated with all DRM schemes have been successfully removed.
      */
     public static final int TYPE_ALL_RIGHTS_REMOVED = 1001;
     /**
-     * Constant field signifies that given information is processed successfully
+     * The given DRM information has been successfully processed.
      */
     public static final int TYPE_DRM_INFO_PROCESSED = 1002;
-
+    /**
+     * The key that is used in the <code>attributes</code> HashMap to pass the return status.
+     */
     public static final String DRM_INFO_STATUS_OBJECT = "drm_info_status_object";
+    /**
+     * The key that is used in the <code>attributes</code> HashMap to pass the
+     * {@link DrmInfo} object.
+     */
     public static final String DRM_INFO_OBJECT = "drm_info_object";
 
     private final int mUniqueId;
@@ -44,12 +48,12 @@
     private HashMap<String, Object> mAttributes = new HashMap<String, Object>();
 
     /**
-     * constructor for DrmEvent class
+     * Creates a <code>DrmEvent</code> object with the specified parameters.
      *
-     * @param uniqueId Unique session identifier
-     * @param type Type of information
-     * @param message Message description
-     * @param attributes Attributes for extensible information
+     * @param uniqueId Unique session identifier.
+     * @param type Type of information.
+     * @param message Message description.
+     * @param attributes Attributes for extensible information.
      */
     protected DrmEvent(int uniqueId, int type, String message,
                             HashMap<String, Object> attributes) {
@@ -66,11 +70,11 @@
     }
 
     /**
-     * constructor for DrmEvent class
+     * Creates a <code>DrmEvent</code> object with the specified parameters.
      *
-     * @param uniqueId Unique session identifier
-     * @param type Type of information
-     * @param message Message description
+     * @param uniqueId Unique session identifier.
+     * @param type Type of information.
+     * @param message Message description.
      */
     protected DrmEvent(int uniqueId, int type, String message) {
         mUniqueId = uniqueId;
@@ -82,40 +86,39 @@
     }
 
     /**
-     * Returns the Unique Id associated with this object
+     * Retrieves the unique session identifier associated with this object.
      *
-     * @return Unique Id
+     * @return The unique session identifier.
      */
     public int getUniqueId() {
         return mUniqueId;
     }
 
     /**
-     * Returns the Type of information associated with this object
+     * Retrieves the type of information that is associated with this object.
      *
-     * @return Type of information
+     * @return The type of information.
      */
     public int getType() {
         return mType;
     }
 
     /**
-     * Returns the message description associated with this object
+     * Retrieves the message description associated with this object.
      *
-     * @return message description
+     * @return The message description.
      */
     public String getMessage() {
         return mMessage;
     }
 
     /**
-     * Returns the attribute corresponding to the specified key
+     * Retrieves the attribute associated with the specified key.
      *
-     * @return one of the attributes or null if no mapping for
-     * the key is found
+     * @return One of the attributes or null if no mapping for
+     * the key is found.
      */
     public Object getAttribute(String key) {
         return mAttributes.get(key);
     }
 }
-
diff --git a/drm/java/android/drm/DrmInfo.java b/drm/java/android/drm/DrmInfo.java
old mode 100644
new mode 100755
index 7d3fbf1..8812bfe
--- a/drm/java/android/drm/DrmInfo.java
+++ b/drm/java/android/drm/DrmInfo.java
@@ -21,14 +21,13 @@
 import java.util.Iterator;
 
 /**
- * This is an entity class in which necessary information required to transact
- * between device and online DRM server is described. DRM Framework achieves
- * server registration, license acquisition and any other server related transaction
- * by passing an instance of this class to {@link DrmManagerClient#processDrmInfo(DrmInfo)}.
- *
- * Caller can retrieve the {@link DrmInfo} instance by using
- * {@link DrmManagerClient#acquireDrmInfo(DrmInfoRequest)}
- * by passing {@link DrmInfoRequest} instance.
+ * An entity class that describes the information required to send transactions
+ * between a device and an online DRM server. The DRM framework achieves
+ * server registration, license acquisition, and any other server-related transactions
+ * by passing an instance of this class to {@link DrmManagerClient#processDrmInfo}.
+ *<p>
+ * The caller can retrieve the {@link DrmInfo} instance by passing a {@link DrmInfoRequest}
+ * instance to {@link DrmManagerClient#acquireDrmInfo}.
  *
  */
 public class DrmInfo {
@@ -40,11 +39,11 @@
     private final HashMap<String, Object> mAttributes = new HashMap<String, Object>();
 
     /**
-     * constructor to create DrmInfo object with given parameters
+     * Creates a <code>DrmInfo</code> object with the given parameters.
      *
-     * @param infoType Type of information
-     * @param data Trigger data
-     * @param mimeType MIME type
+     * @param infoType The type of information.
+     * @param data The trigger data.
+     * @param mimeType The MIME type.
      */
     public DrmInfo(int infoType, byte[] data, String mimeType) {
         mInfoType = infoType;
@@ -53,11 +52,11 @@
     }
 
     /**
-     * constructor to create DrmInfo object with given parameters
+     * Creates a <code>DrmInfo</code> object with the given parameters.
      *
-     * @param infoType Type of information
-     * @param path Trigger data
-     * @param mimeType MIME type
+     * @param infoType The type of information.
+     * @param path The trigger data.
+     * @param mimeType The MIME type.
      */
     public DrmInfo(int infoType, String path, String mimeType) {
         mInfoType = infoType;
@@ -73,67 +72,70 @@
     }
 
     /**
-     * Adds optional information as <key, value> pair to this object
+     * Adds optional information as key-value pairs to this object. To add a custom object
+     * to the <code>DrmInfo</code> object, you must override the {@link #toString} implementation.
      *
-     * @param key Key to add
-     * @param value Value to add
-     *     To put custom object into DrmInfo, custom object has to
-     *     override toString() implementation.
+     * @param key Key to add.
+     * @param value Value to add.
+     *
      */
     public void put(String key, Object value) {
         mAttributes.put(key, value);
     }
 
     /**
-     * Retrieves the value of given key, if not found returns null
+     * Retrieves the value of a given key.
      *
-     * @param key Key whose value to be retrieved
-     * @return The value or null
+     * @param key The key whose value is being retrieved.
+     *
+     * @return The value of the key being retrieved. Returns null if the key cannot be found.
      */
     public Object get(String key) {
         return mAttributes.get(key);
     }
 
     /**
-     * Returns Iterator object to walk through the keys associated with this instance
+     * Retrieves an iterator object that you can use to iterate over the keys associated with
+     * this <code>DrmInfo</code> object.
      *
-     * @return Iterator object
+     * @return The iterator object.
      */
     public Iterator<String> keyIterator() {
         return mAttributes.keySet().iterator();
     }
 
     /**
-     * Returns Iterator object to walk through the values associated with this instance
+     * Retrieves an iterator object that you can use to iterate over the values associated with
+     * this <code>DrmInfo</code> object.
      *
-     * @return Iterator object
+     * @return The iterator object.
      */
     public Iterator<Object> iterator() {
         return mAttributes.values().iterator();
     }
 
     /**
-     * Returns the trigger data associated with this object
+     * Retrieves the trigger data associated with this object.
      *
-     * @return Trigger data
+     * @return The trigger data.
      */
     public byte[] getData() {
         return mData;
     }
 
     /**
-     * Returns the mimetype associated with this object
+     * Retrieves the MIME type associated with this object.
      *
-     * @return MIME type
+     * @return The MIME type.
      */
     public String getMimeType() {
         return mMimeType;
     }
 
     /**
-     * Returns information type associated with this instance
+     * Retrieves the information type associated with this object.
      *
-     * @return Information type
+     * @return The information type.
      */
     public int getInfoType() {
         return mInfoType;
diff --git a/drm/java/android/drm/DrmInfoEvent.java b/drm/java/android/drm/DrmInfoEvent.java
old mode 100644
new mode 100755
index 190199a..67aa0a9
--- a/drm/java/android/drm/DrmInfoEvent.java
+++ b/drm/java/android/drm/DrmInfoEvent.java
@@ -19,58 +19,56 @@
 import java.util.HashMap;
 
 /**
- * This is an entity class which would be passed to caller in
- * {@link DrmManagerClient.OnInfoListener#onInfo(DrmManagerClient, DrmInfoEvent)}
+ * An entity class that is passed to the 
+ * {@link DrmManagerClient.OnInfoListener#onInfo onInfo()} callback.
  *
  */
 public class DrmInfoEvent extends DrmEvent {
     /**
-     * TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT, when registration has been already done
-     * by another account ID.
+     * The registration has already been done by another account ID.
      */
     public static final int TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT = 1;
     /**
-     * TYPE_REMOVE_RIGHTS, when the rights needs to be removed completely.
+     * The rights need to be removed completely.
      */
     public static final int TYPE_REMOVE_RIGHTS = 2;
     /**
-     * TYPE_RIGHTS_INSTALLED, when the rights are downloaded and installed ok.
+     * The rights have been successfully downloaded and installed.
      */
     public static final int TYPE_RIGHTS_INSTALLED = 3;
     /**
-     * TYPE_WAIT_FOR_RIGHTS, rights object is on it's way to phone,
-     * wait before calling checkRights again.
+     * The rights object is being delivered to the device. You must wait before
+     * calling {@link DrmManagerClient#acquireRights acquireRights()} again.
      */
     public static final int TYPE_WAIT_FOR_RIGHTS = 4;
     /**
-     * TYPE_ACCOUNT_ALREADY_REGISTERED, when registration has been
-     * already done for the given account.
+     * The registration has already been done for the given account.
      */
     public static final int TYPE_ACCOUNT_ALREADY_REGISTERED = 5;
     /**
-     * TYPE_RIGHTS_REMOVED, when the rights has been removed.
+     * The rights have been removed.
      */
     public static final int TYPE_RIGHTS_REMOVED = 6;
 
     /**
-     * constructor to create DrmInfoEvent object with given parameters
+     * Creates a <code>DrmInfoEvent</code> object with the specified parameters.
      *
-     * @param uniqueId Unique session identifier
-     * @param type Type of the event. It could be one of the types defined above
-     * @param message Message description
+     * @param uniqueId Unique session identifier.
+     * @param type Type of the event. Could be any of the event types defined above.
+     * @param message Message description.
      */
     public DrmInfoEvent(int uniqueId, int type, String message) {
         super(uniqueId, type, message);
     }
 
     /**
-     * constructor to create DrmInfoEvent object with given parameters
+     * Creates a <code>DrmInfoEvent</code> object with the specified parameters.
      *
-     * @param uniqueId Unique session identifier
-     * @param type Type of the event. It could be one of the types defined above
-     * @param message Message description
+     * @param uniqueId Unique session identifier.
+     * @param type Type of the event. Could be any of the event types defined above.
+     * @param message Message description.
      * @param attributes Attributes for extensible information. Could be any
-     * information provided by the plugin
+     * information provided by the plug-in.
      */
     public DrmInfoEvent(int uniqueId, int type, String message,
                             HashMap<String, Object> attributes) {
diff --git a/drm/java/android/drm/DrmInfoRequest.java b/drm/java/android/drm/DrmInfoRequest.java
old mode 100644
new mode 100755
index 366a342..2222ae8
--- a/drm/java/android/drm/DrmInfoRequest.java
+++ b/drm/java/android/drm/DrmInfoRequest.java
@@ -20,30 +20,37 @@
 import java.util.Iterator;
 
 /**
- * This is an entity class used to pass required parameters to get
- * the necessary information to communicate with online DRM server
- *
- * An instance of this class is passed to {@link DrmManagerClient#acquireDrmInfo(DrmInfoRequest)}
- * to get the instance of {@link DrmInfo}
+ * An entity class that is used to pass information to an online DRM server. An instance of this
+ * class is passed to the {@link DrmManagerClient#acquireDrmInfo acquireDrmInfo()} method to get an
+ * instance of a {@link DrmInfo}.
  *
  */
 public class DrmInfoRequest {
     // Changes in following constants should be in sync with DrmInfoRequest.h
     /**
-     * Constants defines the type of {@link DrmInfoRequest}
+     * Acquires DRM server registration information.
      */
     public static final int TYPE_REGISTRATION_INFO = 1;
+    /**
+    * Acquires information for unregistering the DRM server.
+    */
     public static final int TYPE_UNREGISTRATION_INFO = 2;
+    /**
+    * Acquires rights information.
+    */
     public static final int TYPE_RIGHTS_ACQUISITION_INFO = 3;
+    /**
+    * Acquires the progress of the rights acquisition.
+    */
     public static final int TYPE_RIGHTS_ACQUISITION_PROGRESS_INFO = 4;
 
     /**
-     * Key to pass the unique id for the account or the user
+     * Key that is used to pass the unique session ID for the account or the user.
      */
     public static final String ACCOUNT_ID = "account_id";
 
     /**
-     * Key to pass the unique id used for subscription
+     * Key that is used to pass the unique session ID for the subscription.
      */
     public static final String SUBSCRIPTION_ID = "subscription_id";
 
@@ -52,10 +59,10 @@
     private final HashMap<String, Object> mRequestInformation = new HashMap<String, Object>();
 
     /**
-     * constructor to create DrmInfoRequest object with type and mimetype
+     * Creates a <code>DrmInfoRequest</code> object with type and MIME type.
      *
-     * @param infoType Type of information
-     * @param mimeType MIME type
+     * @param infoType Type of information.
+     * @param mimeType MIME type.
      */
     public DrmInfoRequest(int infoType, String mimeType) {
         mInfoType = infoType;
@@ -63,56 +70,60 @@
     }
 
     /**
-     * Returns the mimetype associated with this object
+     * Retrieves the MIME type associated with this object.
      *
-     * @return MIME type
+     * @return The MIME type.
      */
     public String getMimeType() {
         return mMimeType;
     }
 
     /**
-     * Returns Information type associated with this instance
+     * Retrieves the information type associated with this object.
      *
-     * @return Information type
+     * @return The information type.
      */
     public int getInfoType() {
         return mInfoType;
     }
 
     /**
-     * Adds optional information as <key, value> pair to this object.
+     * Adds optional information as key-value pairs to this object.
      *
-     * @param key Key to add
-     * @param value Value to add
+     * @param key The key to add.
+     * @param value The value to add.
      */
     public void put(String key, Object value) {
         mRequestInformation.put(key, value);
     }
 
     /**
-     * Retrieves the value of given key, if not found returns null
+     * Retrieves the value of a given key.
      *
-     * @param key Key whose value to be retrieved
-     * @return The value or null
+     * @param key The key whose value is being retrieved.
+     *
+     * @return The value of the key that is being retrieved. Returns null if the key cannot be
+     * found.
      */
     public Object get(String key) {
         return mRequestInformation.get(key);
     }
 
     /**
-     * Returns Iterator object to walk through the keys associated with this instance
+     * Retrieves an iterator object that you can use to iterate over the keys associated with
+     * this <code>DrmInfoRequest</code> object.
      *
-     * @return Iterator object
+     * @return The iterator object.
      */
     public Iterator<String> keyIterator() {
         return mRequestInformation.keySet().iterator();
     }
 
     /**
-     * Returns Iterator object to walk through the values associated with this instance
+     * Retrieves an iterator object that you can use to iterate over the values associated with
+     * this <code>DrmInfoRequest</code> object.
      *
-     * @return Iterator object
+     * @return The iterator object.
      */
     public Iterator<Object> iterator() {
         return mRequestInformation.values().iterator();
diff --git a/drm/java/android/drm/DrmInfoStatus.java b/drm/java/android/drm/DrmInfoStatus.java
old mode 100644
new mode 100755
index b37ea51..b04694b
--- a/drm/java/android/drm/DrmInfoStatus.java
+++ b/drm/java/android/drm/DrmInfoStatus.java
@@ -17,12 +17,12 @@
 package android.drm;
 
 /**
- * This is an entity class which wraps the result of communication between device
- * and online DRM server.
- *
- * As a result of {@link DrmManagerClient#processDrmInfo(DrmInfo)} an instance of DrmInfoStatus
- * would be returned. This class holds {@link ProcessedData}, which could be used to instantiate
- * {@link DrmRights#DrmRights(ProcessedData, String)} in license acquisition.
+ * An entity class that wraps the result of communication between a device and an online DRM
+ * server. Specifically, when the {@link DrmManagerClient#processDrmInfo processDrmInfo()} method
+ * is called, an instance of <code>DrmInfoStatus</code> is returned.
+ *<p>
+ * This class contains the {@link ProcessedData} object, which can be used to instantiate a
+ * {@link DrmRights} object during license acquisition.
  *
  */
 public class DrmInfoStatus {
@@ -30,18 +30,30 @@
     public static final int STATUS_OK = 1;
     public static final int STATUS_ERROR = 2;
 
+    /**
+    * The status of the communication.
+    */
     public final int statusCode;
+    /**
+    * The type of DRM information processed.
+    */
     public final int infoType;
+    /**
+    * The MIME type of the content.
+    */
     public final String mimeType;
+    /**
+    * The processed data.
+    */
     public final ProcessedData data;
 
     /**
-     * constructor to create DrmInfoStatus object with given parameters
+     * Creates a <code>DrmInfoStatus</code> object with the specified parameters.
      *
-     * @param _statusCode Status of the communication
-     * @param _infoType Type of the DRM information processed
-     * @param _data The processed data
-     * @param _mimeType MIME type
+     * @param _statusCode The status of the communication.
+     * @param _infoType The type of the DRM information processed.
+     * @param _data The processed data.
+     * @param _mimeType The MIME type.
      */
     public DrmInfoStatus(int _statusCode, int _infoType, ProcessedData _data, String _mimeType) {
         statusCode = _statusCode;
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
old mode 100644
new mode 100755
index f7479b5..f3a0343
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -35,18 +35,17 @@
 import java.util.HashMap;
 
 /**
- * Interface of DRM Framework.
- * Java application will instantiate this class
- * to access DRM agent through DRM Framework.
+ * The main programming interface for the DRM framework. An application must instantiate this class
+ * to access DRM agents through the DRM framework.
  *
  */
 public class DrmManagerClient {
     /**
-     * Constant field signifies the success or no error occurred
+     * Indicates that a request was successful or that no error occurred.
      */
     public static final int ERROR_NONE = 0;
     /**
-     * Constant field signifies that error occurred and the reason is not known
+     * Indicates that an error occurred and the reason is not known.
      */
     public static final int ERROR_UNKNOWN = -2000;
 
@@ -58,43 +57,45 @@
     }
 
     /**
-     * Interface definition of a callback to be invoked to communicate
-     * some info and/or warning about DrmManagerClient.
+     * Interface definition for a callback that receives status messages and warnings
+     * during registration and rights acquisition.
      */
     public interface OnInfoListener {
         /**
-         * Called to indicate an info or a warning.
+         * Called when the DRM framework sends status or warning information during registration
+         * and rights acquisition.
          *
-         * @param client DrmManagerClient instance
-         * @param event instance which wraps reason and necessary information
+         * @param client The <code>DrmManagerClient</code> instance.
+         * @param event The {@link DrmInfoEvent} instance that wraps the status information or 
+         * warnings.
          */
         public void onInfo(DrmManagerClient client, DrmInfoEvent event);
     }
 
     /**
-     * Interface definition of a callback to be invoked to communicate
-     * the result of time consuming APIs asynchronously
+     * Interface definition for a callback that receives information
+     * about DRM processing events.
      */
     public interface OnEventListener {
         /**
-         * Called to indicate the result of asynchronous APIs.
+         * Called when the DRM framework sends information about a DRM processing request.
          *
-         * @param client DrmManagerClient instance
-         * @param event instance which wraps type and message
+         * @param client The <code>DrmManagerClient</code> instance.
+         * @param event The {@link DrmEvent} instance that wraps the information being
+         * conveyed, such as the information type and message.
          */
         public void onEvent(DrmManagerClient client, DrmEvent event);
     }
 
     /**
-     * Interface definition of a callback to be invoked to communicate
-     * the error occurred
+     * Interface definition for a callback that receives information about DRM framework errors.
      */
     public interface OnErrorListener {
         /**
-         * Called to indicate the error occurred.
+         * Called when the DRM framework sends error information.
          *
-         * @param client DrmManagerClient instance
-         * @param event instance which wraps error type and message
+         * @param client The <code>DrmManagerClient</code> instance.
+         * @param event The {@link DrmErrorEvent} instance that wraps the error type and message.
          */
         public void onError(DrmManagerClient client, DrmErrorEvent event);
     }
@@ -231,9 +232,9 @@
     }
 
     /**
-     * To instantiate DrmManagerClient
+     * Creates a <code>DrmManagerClient</code>.
      *
-     * @param context context of the caller
+     * @param context Context of the caller.
      */
     public DrmManagerClient(Context context) {
         mContext = context;
@@ -257,10 +258,10 @@
     }
 
     /**
-     * Register a callback to be invoked when the caller required to receive
-     * supplementary information.
+     * Registers an {@link DrmManagerClient.OnInfoListener} callback, which is invoked when the 
+     * DRM framework sends status or warning information during registration or rights acquisition.
      *
-     * @param infoListener
+     * @param infoListener Interface definition for the callback.
      */
     public synchronized void setOnInfoListener(OnInfoListener infoListener) {
         if (null != infoListener) {
@@ -269,10 +270,10 @@
     }
 
     /**
-     * Register a callback to be invoked when the caller required to receive
-     * the result of asynchronous APIs.
+     * Registers an {@link DrmManagerClient.OnEventListener} callback, which is invoked when the 
+     * DRM framework sends information about DRM processing.
      *
-     * @param eventListener
+     * @param eventListener Interface definition for the callback.
      */
     public synchronized void setOnEventListener(OnEventListener eventListener) {
         if (null != eventListener) {
@@ -281,10 +282,10 @@
     }
 
     /**
-     * Register a callback to be invoked when the caller required to receive
-     * error result of asynchronous APIs.
+     * Registers an {@link DrmManagerClient.OnErrorListener} callback, which is invoked when 
+     * the DRM framework sends error information.
      *
-     * @param errorListener
+     * @param errorListener Interface definition for the callback.
      */
     public synchronized void setOnErrorListener(OnErrorListener errorListener) {
         if (null != errorListener) {
@@ -293,9 +294,10 @@
     }
 
     /**
-     * Retrieves informations about all the plug-ins registered with DrmFramework.
+     * Retrieves information about all the DRM plug-ins (agents) that are registered with
+     * the DRM framework.
      *
-     * @return Array of DrmEngine plug-in strings
+     * @return A <code>String</code> array of DRM plug-in descriptions.
      */
     public String[] getAvailableDrmEngines() {
         DrmSupportInfo[] supportInfos = _getAllSupportInfo(mUniqueId);
@@ -310,12 +312,13 @@
     }
 
     /**
-     * Get constraints information evaluated from DRM content
+     * Retrieves constraint information for rights-protected content.
      *
-     * @param path Content path from where DRM constraints would be retrieved.
-     * @param action Actions defined in {@link DrmStore.Action}
-     * @return ContentValues instance in which constraints key-value pairs are embedded
-     *         or null in case of failure
+     * @param path Path to the content from which you are retrieving DRM constraints.
+     * @param action Action defined in {@link DrmStore.Action}.
+     *
+     * @return A {@link android.content.ContentValues} instance that contains
+     * key-value pairs representing the constraints. Null in case of failure.
      */
     public ContentValues getConstraints(String path, int action) {
         if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) {
@@ -325,11 +328,12 @@
     }
 
    /**
-    * Get metadata information from DRM content
+    * Retrieves metadata information for rights-protected content.
     *
-    * @param path Content path from where DRM metadata would be retrieved.
-    * @return ContentValues instance in which metadata key-value pairs are embedded
-    *         or null in case of failure
+    * @param path Path to the content from which you are retrieving metadata information.
+    *
+    * @return A {@link android.content.ContentValues} instance that contains
+    * key-value pairs representing the metadata. Null in case of failure.
     */
     public ContentValues getMetadata(String path) {
         if (null == path || path.equals("")) {
@@ -339,12 +343,13 @@
     }
 
     /**
-     * Get constraints information evaluated from DRM content
+     * Retrieves constraint information for rights-protected content.
      *
-     * @param uri Content URI from where DRM constraints would be retrieved.
-     * @param action Actions defined in {@link DrmStore.Action}
-     * @return ContentValues instance in which constraints key-value pairs are embedded
-     *         or null in case of failure
+     * @param uri URI for the content from which you are retrieving DRM constraints.
+     * @param action Action defined in {@link DrmStore.Action}.
+     *
+     * @return A {@link android.content.ContentValues} instance that contains
+     * key-value pairs representing the constraints. Null in case of failure.
      */
     public ContentValues getConstraints(Uri uri, int action) {
         if (null == uri || Uri.EMPTY == uri) {
@@ -354,11 +359,12 @@
     }
 
    /**
-    * Get metadata information from DRM content
+    * Retrieves metadata information for rights-protected content.
     *
-    * @param uri Content URI from where DRM metadata would be retrieved.
-    * @return ContentValues instance in which metadata key-value pairs are embedded
-    *         or null in case of failure
+    * @param uri URI for the content from which you are retrieving metadata information.
+    *
+    * @return A {@link android.content.ContentValues} instance that contains
+    * key-value pairs representing the constraints. Null in case of failure.
     */
     public ContentValues getMetadata(Uri uri) {
         if (null == uri || Uri.EMPTY == uri) {
@@ -368,18 +374,19 @@
     }
 
     /**
-     * Save DRM rights to specified rights path
-     * and make association with content path.
+     * Saves rights to a specified path and associates that path with the content path.
+     * 
+     * <p class="note"><strong>Note:</strong> For OMA or WM-DRM, <code>rightsPath</code> and
+     * <code>contentPath</code> can be null.</p>
      *
-     * <p class="note">In case of OMA or WM-DRM, rightsPath and contentPath could be null.</p>
+     * @param drmRights The {@link DrmRights} to be saved.
+     * @param rightsPath File path where rights will be saved.
+     * @param contentPath File path where content is saved.
      *
-     * @param drmRights DrmRights to be saved
-     * @param rightsPath File path where rights to be saved
-     * @param contentPath File path where content was saved
-     * @return
-     *     ERROR_NONE for success
-     *     ERROR_UNKNOWN for failure
-     * @throws IOException if failed to save rights information in the given path
+     * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
+     *
+     * @throws IOException If the call failed to save rights information at the given
+     * <code>rightsPath</code>.
      */
     public int saveRights(
             DrmRights drmRights, String rightsPath, String contentPath) throws IOException {
@@ -393,9 +400,10 @@
     }
 
     /**
-     * Install new DRM Engine Plug-in at the runtime
+     * Installs a new DRM plug-in (agent) at runtime.
      *
-     * @param engineFilePath Path of the plug-in file to be installed
+     * @param engineFilePath File path to the plug-in file to be installed.
+     *
      * {@hide}
      */
     public void installDrmEngine(String engineFilePath) {
@@ -407,13 +415,12 @@
     }
 
     /**
-     * Check whether the given mimetype or path can be handled.
+     * Checks whether the given MIME type or path can be handled.
      *
-     * @param path Path of the content to be handled
-     * @param mimeType Mimetype of the object to be handled
-     * @return
-     *        true - if the given mimeType or path can be handled
-     *        false - cannot be handled.
+     * @param path Path of the content to be handled.
+     * @param mimeType MIME type of the object to be handled.
+     *
+     * @return True if the given MIME type or path can be handled; false if they cannot be handled.
      */
     public boolean canHandle(String path, String mimeType) {
         if ((null == path || path.equals("")) && (null == mimeType || mimeType.equals(""))) {
@@ -423,13 +430,12 @@
     }
 
     /**
-     * Check whether the given mimetype or uri can be handled.
+     * Checks whether the given MIME type or URI can be handled.
      *
-     * @param uri Content URI of the data to be handled.
-     * @param mimeType Mimetype of the object to be handled
-     * @return
-     *        true - if the given mimeType or path can be handled
-     *        false - cannot be handled.
+     * @param uri URI for the content to be handled.
+     * @param mimeType MIME type of the object to be handled
+     *
+     * @return True if the given MIME type or URI can be handled; false if they cannot be handled.
      */
     public boolean canHandle(Uri uri, String mimeType) {
         if ((null == uri || Uri.EMPTY == uri) && (null == mimeType || mimeType.equals(""))) {
@@ -439,12 +445,10 @@
     }
 
     /**
-     * Executes given drm information based on its type
+     * Processes the given DRM information based on the information type.
      *
-     * @param drmInfo Information needs to be processed
-     * @return
-     *     ERROR_NONE for success
-     *     ERROR_UNKNOWN for failure
+     * @param drmInfo The {@link DrmInfo} to be processed.
+     * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
      */
     public int processDrmInfo(DrmInfo drmInfo) {
         if (null == drmInfo || !drmInfo.isValid()) {
@@ -459,10 +463,12 @@
     }
 
     /**
-     * Retrieves necessary information for register, unregister or rights acquisition.
+     * Retrieves information for registering, unregistering, or acquiring rights.
      *
-     * @param drmInfoRequest Request information to retrieve drmInfo
-     * @return DrmInfo Instance as a result of processing given input
+     * @param drmInfoRequest The {@link DrmInfoRequest} that specifies the type of DRM
+     * information being retrieved.
+     *
+     * @return A {@link DrmInfo} instance.
      */
     public DrmInfo acquireDrmInfo(DrmInfoRequest drmInfoRequest) {
         if (null == drmInfoRequest || !drmInfoRequest.isValid()) {
@@ -472,17 +478,18 @@
     }
 
     /**
-     * Executes given DrmInfoRequest and returns the rights information asynchronously.
-     * This is a utility API which consists of {@link #acquireDrmInfo(DrmInfoRequest)}
-     * and {@link #processDrmInfo(DrmInfo)}.
-     * It can be used if selected DRM agent can work with this combined sequences.
-     * In case of some DRM schemes, such as OMA DRM, application needs to invoke
-     * {@link #acquireDrmInfo(DrmInfoRequest)} and {@link #processDrmInfo(DrmInfo)}, separately.
+     * Processes a given {@link DrmInfoRequest} and returns the rights information asynchronously.
+     *<p>
+     * This is a utility method that consists of an
+     * {@link #acquireDrmInfo(DrmInfoRequest) acquireDrmInfo()} and a
+     * {@link #processDrmInfo(DrmInfo) processDrmInfo()} method call. This utility method can be 
+     * used only if the selected DRM plug-in (agent) supports this sequence of calls. Some DRM
+     * agents, such as OMA, do not support this utility method, in which case an application must
+     * invoke {@link #acquireDrmInfo(DrmInfoRequest) acquireDrmInfo()} and
+     * {@link #processDrmInfo(DrmInfo) processDrmInfo()} separately.
      *
-     * @param drmInfoRequest Request information to retrieve drmInfo
-     * @return
-     *     ERROR_NONE for success
-     *     ERROR_UNKNOWN for failure
+     * @param drmInfoRequest The {@link DrmInfoRequest} used to acquire the rights.
+     * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
      */
     public int acquireRights(DrmInfoRequest drmInfoRequest) {
         DrmInfo drmInfo = acquireDrmInfo(drmInfoRequest);
@@ -493,14 +500,14 @@
     }
 
     /**
-     * Retrieves the type of the protected object (content, rights, etc..)
-     * using specified path or mimetype. At least one parameter should be non null
-     * to retrieve DRM object type
+     * Retrieves the type of rights-protected object (for example, content object, rights
+     * object, and so on) using the specified path or MIME type. At least one parameter must
+     * be specified to retrieve the DRM object type.
      *
-     * @param path Path of the content or null.
-     * @param mimeType Mimetype of the content or null.
-     * @return Type of the DRM content.
-     * @see DrmStore.DrmObjectType
+     * @param path Path to the content or null.
+     * @param mimeType MIME type of the content or null.
+     * 
+     * @return An <code>int</code> that corresponds to a {@link DrmStore.DrmObjectType}.
      */
     public int getDrmObjectType(String path, String mimeType) {
         if ((null == path || path.equals("")) && (null == mimeType || mimeType.equals(""))) {
@@ -510,14 +517,14 @@
     }
 
     /**
-     * Retrieves the type of the protected object (content, rights, etc..)
-     * using specified uri or mimetype. At least one parameter should be non null
-     * to retrieve DRM object type
+     * Retrieves the type of rights-protected object (for example, content object, rights
+     * object, and so on) using the specified URI or MIME type. At least one parameter must
+     * be specified to retrieve the DRM object type.
      *
-     * @param uri The content URI of the data
-     * @param mimeType Mimetype of the content or null.
-     * @return Type of the DRM content.
-     * @see DrmStore.DrmObjectType
+     * @param uri URI for the content or null.
+     * @param mimeType MIME type of the content or null.
+     * 
+     * @return An <code>int</code> that corresponds to a {@link DrmStore.DrmObjectType}.
      */
     public int getDrmObjectType(Uri uri, String mimeType) {
         if ((null == uri || Uri.EMPTY == uri) && (null == mimeType || mimeType.equals(""))) {
@@ -534,10 +541,11 @@
     }
 
     /**
-     * Retrieves the mime type embedded inside the original content
+     * Retrieves the MIME type embedded in the original content.
      *
-     * @param path Path of the protected content
-     * @return Mimetype of the original content, such as "video/mpeg"
+     * @param path Path to the rights-protected content.
+     *
+     * @return The MIME type of the original content, such as <code>video/mpeg</code>.
      */
     public String getOriginalMimeType(String path) {
         if (null == path || path.equals("")) {
@@ -547,10 +555,11 @@
     }
 
     /**
-     * Retrieves the mime type embedded inside the original content
+     * Retrieves the MIME type embedded in the original content.
      *
-     * @param uri The content URI of the data
-     * @return Mimetype of the original content, such as "video/mpeg"
+     * @param uri URI of the rights-protected content.
+     *
+     * @return MIME type of the original content, such as <code>video/mpeg</code>.
      */
     public String getOriginalMimeType(Uri uri) {
         if (null == uri || Uri.EMPTY == uri) {
@@ -560,22 +569,22 @@
     }
 
     /**
-     * Check whether the given content has valid rights or not
+     * Checks whether the given content has valid rights.
      *
-     * @param path Path of the protected content
-     * @return Status of the rights for the protected content
-     * @see DrmStore.RightsStatus
+     * @param path Path to the rights-protected content.
+     *
+     * @return An <code>int</code> representing the {@link DrmStore.RightsStatus} of the content.
      */
     public int checkRightsStatus(String path) {
         return checkRightsStatus(path, DrmStore.Action.DEFAULT);
     }
 
     /**
-     * Check whether the given content has valid rights or not
+     * Check whether the given content has valid rights.
      *
-     * @param uri The content URI of the data
-     * @return Status of the rights for the protected content
-     * @see DrmStore.RightsStatus
+     * @param uri URI of the rights-protected content.
+     *
+     * @return An <code>int</code> representing the {@link DrmStore.RightsStatus} of the content.
      */
     public int checkRightsStatus(Uri uri) {
         if (null == uri || Uri.EMPTY == uri) {
@@ -585,12 +594,13 @@
     }
 
     /**
-     * Check whether the given content has valid rights or not for specified action.
+     * Checks whether the given rights-protected content has valid rights for the specified
+     * {@link DrmStore.Action}.
      *
-     * @param path Path of the protected content
-     * @param action Action to perform
-     * @return Status of the rights for the protected content
-     * @see DrmStore.RightsStatus
+     * @param path Path to the rights-protected content.
+     * @param action The {@link DrmStore.Action} to perform.
+     *
+     * @return An <code>int</code> representing the {@link DrmStore.RightsStatus} of the content.
      */
     public int checkRightsStatus(String path, int action) {
         if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) {
@@ -600,12 +610,13 @@
     }
 
     /**
-     * Check whether the given content has valid rights or not for specified action.
+     * Checks whether the given rights-protected content has valid rights for the specified
+     * {@link DrmStore.Action}.
      *
-     * @param uri The content URI of the data
-     * @param action Action to perform
-     * @return Status of the rights for the protected content
-     * @see DrmStore.RightsStatus
+     * @param uri URI for the rights-protected content.
+     * @param action The {@link DrmStore.Action} to perform.
+     *
+     * @return An <code>int</code> representing the {@link DrmStore.RightsStatus} of the content.
      */
     public int checkRightsStatus(Uri uri, int action) {
         if (null == uri || Uri.EMPTY == uri) {
@@ -615,12 +626,11 @@
     }
 
     /**
-     * Removes the rights associated with the given protected content
+     * Removes the rights associated with the given rights-protected content.
      *
-     * @param path Path of the protected content
-     * @return
-     *     ERROR_NONE for success
-     *     ERROR_UNKNOWN for failure
+     * @param path Path to the rights-protected content.
+     *
+     * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
      */
     public int removeRights(String path) {
         if (null == path || path.equals("")) {
@@ -630,12 +640,11 @@
     }
 
     /**
-     * Removes the rights associated with the given protected content
+     * Removes the rights associated with the given rights-protected content.
      *
-     * @param uri The content URI of the data
-     * @return
-     *     ERROR_NONE for success
-     *     ERROR_UNKNOWN for failure
+     * @param uri URI for the rights-protected content.
+     *
+     * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
      */
     public int removeRights(Uri uri) {
         if (null == uri || Uri.EMPTY == uri) {
@@ -645,12 +654,10 @@
     }
 
     /**
-     * Removes all the rights information of every plug-in associated with
-     * DRM framework. Will be used in master reset
+     * Removes all the rights information of every DRM plug-in (agent) associated with
+     * the DRM framework. Will be used during a master reset.
      *
-     * @return
-     *     ERROR_NONE for success
-     *     ERROR_UNKNOWN for failure
+     * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
      */
     public int removeAllRights() {
         int result = ERROR_UNKNOWN;
@@ -662,13 +669,14 @@
     }
 
     /**
-     * This API is for Forward Lock based DRM scheme.
-     * Each time the application tries to download a new DRM file
-     * which needs to be converted, then the application has to
-     * begin with calling this API.
+     * Initiates a new conversion session. An application must initiate a conversion session
+     * with this method each time it downloads a rights-protected file that needs to be converted.
+     *<p>
+     * This method applies only to forward-locking (copy protection) DRM schemes.
      *
-     * @param mimeType Description/MIME type of the input data packet
-     * @return convert ID which will be used for maintaining convert session.
+     * @param mimeType MIME type of the input data packet.
+     *
+     * @return A convert ID that is used used to maintain the conversion session.
      */
     public int openConvertSession(String mimeType) {
         if (null == mimeType || mimeType.equals("")) {
@@ -678,16 +686,17 @@
     }
 
     /**
-     * Accepts and converts the input data which is part of DRM file.
-     * The resultant converted data and the status is returned in the DrmConvertedInfo
-     * object. This method will be called each time there are new block
-     * of data received by the application.
+     * Converts the input data (content) that is part of a rights-protected file. The converted
+     * data and status is returned in a {@link DrmConvertedStatus} object. This method should be
+     * called each time there is a new block of data received by the application.
      *
-     * @param convertId Handle for the convert session
-     * @param inputData Input Data which need to be converted
-     * @return Return object contains the status of the data conversion,
-     *         the output converted data and offset. In this case the
-     *         application will ignore the offset information.
+     * @param convertId Handle for the conversion session.
+     * @param inputData Input data that needs to be converted.
+     *
+     * @return A {@link DrmConvertedStatus} object that contains the status of the data conversion,
+     * the converted data, and offset for the header and body signature. An application can 
+     * ignore the offset because it is only relevant to the
+     * {@link #closeConvertSession closeConvertSession()} method.
      */
     public DrmConvertedStatus convertData(int convertId, byte[] inputData) {
         if (null == inputData || 0 >= inputData.length) {
@@ -697,16 +706,15 @@
     }
 
     /**
-     * Informs the Drm Agent when there is no more data which need to be converted
-     * or when an error occurs. Upon successful conversion of the complete data,
-     * the agent will inform that where the header and body signature
-     * should be added. This signature appending is needed to integrity
-     * protect the converted file.
+     * Informs the DRM plug-in (agent) that there is no more data to convert or that an error 
+     * has occurred. Upon successful conversion of the data, the DRM agent will provide an offset
+     * value indicating where the header and body signature should be added. Appending the 
+     * signature is necessary to protect the integrity of the converted file.
      *
-     * @param convertId Handle for the convert session
-     * @return Return object contains the status of the data conversion,
-     *     the header and body signature data. It also informs
-     *     the application on which offset these signature data should be appended.
+     * @param convertId Handle for the conversion session.
+     *
+     * @return A {@link DrmConvertedStatus} object that contains the status of the data conversion,
+     * the converted data, and the offset for the header and body signature.
      */
     public DrmConvertedStatus closeConvertSession(int convertId) {
         return _closeConvertSession(mUniqueId, convertId);
diff --git a/drm/java/android/drm/DrmRights.java b/drm/java/android/drm/DrmRights.java
old mode 100644
new mode 100755
index 103af07..5907956
--- a/drm/java/android/drm/DrmRights.java
+++ b/drm/java/android/drm/DrmRights.java
@@ -20,14 +20,16 @@
 import java.io.IOException;
 
 /**
- * This is an entity class which wraps the license information which was
- * retrieved from the online DRM server.
- *
- * Caller can instantiate {@link DrmRights} by
- * invoking {@link DrmRights#DrmRights(ProcessedData, String)}
- * constructor by using the result of {@link DrmManagerClient#processDrmInfo(DrmInfo)} interface.
- * Caller can also instantiate {@link DrmRights} using the file path
- * which contains rights information.
+ * An entity class that wraps the license information retrieved from the online DRM server.
+ *<p>
+ * A caller can instantiate a {@link DrmRights} object by first invoking the
+ * {@link DrmManagerClient#processDrmInfo(DrmInfo)} method and then using the resulting
+ * {@link ProcessedData} object to invoke the {@link DrmRights#DrmRights(ProcessedData, String)}
+ * constructor.
+ *<p>
+ * A caller can also instantiate a {@link DrmRights} object by using the
+ * {@link DrmRights#DrmRights(String, String)} constructor, which takes a path to a file
+ * containing rights information instead of a <code>ProcessedData</code>.
  *
  */
 public class DrmRights {
@@ -37,10 +39,10 @@
     private String mSubscriptionId = "";
 
     /**
-     * constructor to create DrmRights object with given parameters
+     * Creates a <code>DrmRights</code> object with the given parameters.
      *
-     * @param rightsFilePath Path of the file containing rights data
-     * @param mimeType MIME type
+     * @param rightsFilePath Path to the file containing rights information.
+     * @param mimeType MIME type.
      */
     public DrmRights(String rightsFilePath, String mimeType) {
         File file = new File(rightsFilePath);
@@ -48,11 +50,11 @@
     }
 
     /**
-     * constructor to create DrmRights object with given parameters
+     * Creates a <code>DrmRights</code> object with the given parameters.
      *
-     * @param rightsFilePath Path of the file containing rights data
-     * @param mimeType MIME type
-     * @param accountId Account Id of the user
+     * @param rightsFilePath Path to the file containing rights information.
+     * @param mimeType MIME type.
+     * @param accountId Account ID of the user.
      */
     public DrmRights(String rightsFilePath, String mimeType, String accountId) {
         this(rightsFilePath, mimeType);
@@ -63,12 +65,12 @@
     }
 
     /**
-     * constructor to create DrmRights object with given parameters
+     * Creates a <code>DrmRights</code> object with the given parameters.
      *
-     * @param rightsFilePath Path of the file containing rights data
-     * @param mimeType MIME type
-     * @param accountId Account Id of the user
-     * @param subscriptionId Subscription Id of the user
+     * @param rightsFilePath Path to the file containing rights information.
+     * @param mimeType MIME type.
+     * @param accountId Account ID of the user.
+     * @param subscriptionId Subscription ID of the user.
      */
     public DrmRights(
             String rightsFilePath, String mimeType, String accountId, String subscriptionId) {
@@ -84,10 +86,10 @@
     }
 
     /**
-     * constructor to create DrmRights object with given parameters
+     * Creates a <code>DrmRights</code> object with the given parameters.
      *
-     * @param rightsFile File containing rights data
-     * @param mimeType MIME type
+     * @param rightsFile File containing rights information.
+     * @param mimeType MIME type.
      */
     public DrmRights(File rightsFile, String mimeType) {
         instantiate(rightsFile, mimeType);
@@ -104,16 +106,20 @@
     }
 
     /**
-     * constructor to create DrmRights object with given parameters
-     * The user can pass String or binary data<p>
-     * Usage:<p>
-     *        i)  String(e.g. data is instance of String):<br>
-     *            - new DrmRights(data.getBytes(), mimeType)<p>
-     *        ii) Binary data<br>
-     *            - new DrmRights(binaryData[], mimeType)<br>
+     * Creates a <code>DrmRights</code> object with the given parameters.
+     *<p>
+     * The application can pass the processed data as a <code>String</code> or as binary data.
+     *<p>
+     * The following code snippet shows how to pass the processed data as a <code>String</code>:
+     *<p>
+     * new DrmRights(data.getBytes(), mimeType)
+     *<p>
+     * The following code snippet shows how to pass the processed data as binary data:
+     *<p>
+     * new DrmRights(binaryData[], mimeType)
      *
-     * @param data Processed data
-     * @param mimeType MIME type
+     * @param data A {@link ProcessedData} object.
+     * @param mimeType The MIME type.
      */
     public DrmRights(ProcessedData data, String mimeType) {
         mData = data.getData();
@@ -132,47 +138,45 @@
     }
 
     /**
-     * Returns the rights data associated with this object
+     * Retrieves the rights data associated with this <code>DrmRights</code> object.
      *
-     * @return Rights data
+     * @return A <code>byte</code> array representing the rights data.
      */
     public byte[] getData() {
         return mData;
     }
 
     /**
-     * Returns the mimetype associated with this object
+     * Retrieves the MIME type associated with this <code>DrmRights</code> object.
      *
-     * @return MIME type
+     * @return The MIME type.
      */
     public String getMimeType() {
         return mMimeType;
     }
 
     /**
-     * Returns the account-id associated with this object
+     * Retrieves the account ID associated with this <code>DrmRights</code> object.
      *
-     * @return Account Id
+     * @return The account ID.
      */
     public String getAccountId() {
         return mAccountId;
     }
 
     /**
-     * Returns the subscription-id associated with this object
+     * Retrieves the subscription ID associated with this <code>DrmRights</code> object.
      *
-     * @return Subscription Id
+     * @return The subscription ID.
      */
     public String getSubscriptionId() {
         return mSubscriptionId;
     }
 
     /**
-     * Returns whether this instance is valid or not
+     * Determines whether this instance is valid or not.
      *
-     * @return
-     *     true if valid
-     *     false if invalid
+     * @return True if valid; false if invalid.
      */
     /*package*/ boolean isValid() {
         return (null != mMimeType && !mMimeType.equals("")
diff --git a/drm/java/android/drm/DrmStore.java b/drm/java/android/drm/DrmStore.java
old mode 100644
new mode 100755
index 44df90c..ae311de
--- a/drm/java/android/drm/DrmStore.java
+++ b/drm/java/android/drm/DrmStore.java
@@ -17,91 +17,97 @@
 package android.drm;
 
 /**
- * This class defines all the constants used by DRM framework
+ * Defines constants that are used by the DRM framework.
  *
  */
 public class DrmStore {
     /**
-     * Columns representing drm constraints
+     * Interface definition for the columns that represent DRM constraints.
      */
     public interface ConstraintsColumns {
         /**
-         * The max repeat count
-         * <P>Type: INTEGER</P>
+         * The maximum repeat count.
+         * <p>
+         * Type: INTEGER
          */
         public static final String MAX_REPEAT_COUNT = "max_repeat_count";
 
         /**
-         * The remaining repeat count
-         * <P>Type: INTEGER</P>
+         * The remaining repeat count.
+         * <p>
+         * Type: INTEGER
          */
         public static final String REMAINING_REPEAT_COUNT = "remaining_repeat_count";
 
         /**
-         * The time before which the protected file can not be played/viewed
-         * <P>Type: TEXT</P>
+         * The time before which the rights-protected file cannot be played/viewed.
+         * <p>
+         * Type: TEXT
          */
         public static final String LICENSE_START_TIME = "license_start_time";
 
         /**
-         * The time after which the protected file can not be played/viewed
-         * <P>Type: TEXT</P>
+         * The time after which the rights-protected file cannot be played/viewed.
+         * <p>
+         * Type: TEXT
          */
         public static final String LICENSE_EXPIRY_TIME = "license_expiry_time";
 
         /**
-         * The available time for license
-         * <P>Type: TEXT</P>
+         * The available time left before the license expires.
+         * <p>
+         * Type: TEXT
          */
         public static final String LICENSE_AVAILABLE_TIME = "license_available_time";
 
         /**
-         * The data stream for extended metadata
-         * <P>Type: TEXT</P>
+         * The data stream for extended metadata.
+         * <p>
+         * Type: TEXT
          */
         public static final String EXTENDED_METADATA = "extended_metadata";
     }
 
     /**
-     * Defines constants related to DRM types
+     * Defines DRM object types.
      */
     public static class DrmObjectType {
         /**
-         * Field specifies the unknown type
+         * An unknown object type.
          */
         public static final int UNKNOWN = 0x00;
         /**
-         * Field specifies the protected content type
+         * A rights-protected file object type.
          */
         public static final int CONTENT = 0x01;
         /**
-         * Field specifies the rights information
+         * A rights information object type.
          */
         public static final int RIGHTS_OBJECT = 0x02;
         /**
-         * Field specifies the trigger information
+         * A trigger information object type.
          */
         public static final int TRIGGER_OBJECT = 0x03;
     }
 
     /**
-     * Defines constants related to playback
+     * Defines playback states for content.
      */
     public static class Playback {
         /**
-         * Constant field signifies playback start
+         * Playback started.
          */
         public static final int START = 0x00;
         /**
-         * Constant field signifies playback stop
+         * Playback stopped.
          */
         public static final int STOP = 0x01;
         /**
-         * Constant field signifies playback paused
+         * Playback paused.
          */
         public static final int PAUSE = 0x02;
         /**
-         * Constant field signifies playback resumed
+         * Playback resumed.
          */
         public static final int RESUME = 0x03;
 
@@ -120,39 +126,39 @@
     }
 
     /**
-     * Defines actions that can be performed on protected content
+     * Defines actions that can be performed on rights-protected content.
      */
     public static class Action {
         /**
-         * Constant field signifies that the default action
+         * The default action.
          */
         public static final int DEFAULT = 0x00;
         /**
-         * Constant field signifies that the content can be played
+         * The rights-protected content can be played.
          */
         public static final int PLAY = 0x01;
         /**
-         * Constant field signifies that the content can be set as ring tone
+         * The rights-protected content can be set as a ringtone.
          */
         public static final int RINGTONE = 0x02;
         /**
-         * Constant field signifies that the content can be transfered
+         * The rights-protected content can be transferred.
          */
         public static final int TRANSFER = 0x03;
         /**
-         * Constant field signifies that the content can be set as output
+         * The rights-protected content can be set as output.
          */
         public static final int OUTPUT = 0x04;
         /**
-         * Constant field signifies that preview is allowed
+         * The rights-protected content can be previewed.
          */
         public static final int PREVIEW = 0x05;
         /**
-         * Constant field signifies that the content can be executed
+         * The rights-protected content can be executed.
          */
         public static final int EXECUTE = 0x06;
         /**
-         * Constant field signifies that the content can displayed
+         * The rights-protected content can be displayed.
          */
         public static final int DISPLAY = 0x07;
 
@@ -175,23 +181,23 @@
     }
 
     /**
-     * Defines constants related to status of the rights
+     * Defines status notifications for digital rights.
      */
     public static class RightsStatus {
         /**
-         * Constant field signifies that the rights are valid
+         * The digital rights are valid.
          */
         public static final int RIGHTS_VALID = 0x00;
         /**
-         * Constant field signifies that the rights are invalid
+         * The digital rights are invalid.
          */
         public static final int RIGHTS_INVALID = 0x01;
         /**
-         * Constant field signifies that the rights are expired for the content
+         * The digital rights have expired.
          */
         public static final int RIGHTS_EXPIRED = 0x02;
         /**
-         * Constant field signifies that the rights are not acquired for the content
+         * The digital rights have not been acquired for the rights-protected content.
          */
         public static final int RIGHTS_NOT_ACQUIRED = 0x03;
     }
diff --git a/drm/java/android/drm/DrmSupportInfo.java b/drm/java/android/drm/DrmSupportInfo.java
old mode 100644
new mode 100755
index 0886af8..720c545
--- a/drm/java/android/drm/DrmSupportInfo.java
+++ b/drm/java/android/drm/DrmSupportInfo.java
@@ -20,11 +20,11 @@
 import java.util.Iterator;
 
 /**
- * This is an entity class which wraps the capability of each plug-in,
- * such as mimetype's and file suffixes it could handle.
- *
- * Plug-in developer could return the capability of the plugin by passing
- * {@link DrmSupportInfo} instance.
+ * An entity class that wraps the capability of each DRM plug-in (agent),
+ * such as the MIME type and file suffix the DRM plug-in can handle.
+ *<p>
+ * Plug-in developers can expose the capability of their plug-in by passing an instance of this
+ * class to an application.
  *
  */
 public class DrmSupportInfo {
@@ -33,47 +33,47 @@
     private String mDescription = "";
 
     /**
-     * Add the mime-type to the support info such that respective plug-in is
-     * capable of handling the given mime-type.
+     * Adds the specified MIME type to the list of MIME types this DRM plug-in supports.
      *
-     * @param mimeType MIME type
+     * @param mimeType MIME type that can be handles by this DRM plug-in.
      */
     public void addMimeType(String mimeType) {
         mMimeTypeList.add(mimeType);
     }
 
     /**
-     * Add the file suffix to the support info such that respective plug-in is
-     * capable of handling the given file suffix.
+     * Adds the specified file suffix to the list of file suffixes this DRM plug-in supports.
      *
-     * @param fileSuffix File suffix which can be handled
+     * @param fileSuffix File suffix that can be handled by this DRM plug-in.
      */
     public void addFileSuffix(String fileSuffix) {
         mFileSuffixList.add(fileSuffix);
     }
 
     /**
-     * Returns the iterator to walk to through mime types of this object
+     * Retrieves an iterator object that you can use to iterate over the MIME types that 
+     * this DRM plug-in supports.
      *
-     * @return Iterator object
+     * @return The iterator object
      */
     public Iterator<String> getMimeTypeIterator() {
         return mMimeTypeList.iterator();
     }
 
     /**
-     * Returns the iterator to walk to through file suffixes of this object
+     * Retrieves an iterator object that you can use to iterate over the file suffixes that
+     * this DRM plug-in supports.
      *
-     * @return Iterator object
+     * @return The iterator object.
      */
     public Iterator<String> getFileSuffixIterator() {
         return mFileSuffixList.iterator();
     }
 
     /**
-     * Set the unique description about the plugin
+     * Sets a description for the DRM plug-in (agent).
      *
-     * @param description Unique description
+     * @param description Unique description of plug-in.
      */
     public void setDescription(String description) {
         if (null != description) {
@@ -82,30 +82,28 @@
     }
 
     /**
-     * Returns the unique description associated with the plugin
+     * Retrieves the DRM plug-in (agent) description.
      *
-     * @return Unique description
+     * @return The plug-in description.
      */
     public String getDescriprition() {
         return mDescription;
     }
 
     /**
-     * Overridden hash code implementation
+     * Overridden hash code implementation.
      *
-     * @return Hash code value
+     * @return The hash code value.
      */
     public int hashCode() {
         return mFileSuffixList.hashCode() + mMimeTypeList.hashCode() + mDescription.hashCode();
     }
 
     /**
-     * Overridden equals implementation
+     * Overridden <code>equals</code> implementation.
      *
-     * @param object The object to be compared
-     * @return
-     *     true if equal
-     *     false if not equal
+     * @param object The object to be compared.
+     * @return True if equal; false if not equal.
      */
     public boolean equals(Object object) {
         boolean result = false;
@@ -119,12 +117,10 @@
     }
 
     /**
-     * Returns whether given mime-type is supported or not
+     * Determines whether a given MIME type is supported.
      *
-     * @param mimeType MIME type
-     * @return
-     *     true if mime type is supported
-     *     false if mime type is not supported
+     * @param mimeType MIME type.
+     * @return True if Mime type is supported; false if MIME type is not supported.
      */
     /* package */ boolean isSupportedMimeType(String mimeType) {
         if (null != mimeType && !mimeType.equals("")) {
@@ -139,12 +135,10 @@
     }
 
     /**
-     * Returns whether given file suffix is supported or not
+     * Determines whether a given file suffix is supported.
      *
-     * @param fileSuffix File suffix
-     * @return
-     *     true - if file suffix is supported
-     *     false - if file suffix is not supported
+     * @param fileSuffix File suffix.
+     * @return True if file suffix is supported; false if file suffix is not supported.
      */
     /* package */ boolean isSupportedFileSuffix(String fileSuffix) {
         return mFileSuffixList.contains(fileSuffix);
diff --git a/drm/java/android/drm/DrmUtils.java b/drm/java/android/drm/DrmUtils.java
old mode 100644
new mode 100755
index 8903485..dc5f1fa
--- a/drm/java/android/drm/DrmUtils.java
+++ b/drm/java/android/drm/DrmUtils.java
@@ -28,9 +28,11 @@
 import java.util.Iterator;
 
 /**
- * The utility class used in the DRM Framework. This inclueds APIs for file operations
- * and ExtendedMetadataParser for parsing extended metadata BLOB in DRM constraints.
- *
+ * A utility class that provides operations for parsing extended metadata embedded in
+ * DRM constraint information. If a DRM scheme has specific constraints beyond the standard
+ * constraints, the constraints will show up in the
+ * {@link DrmStore.ConstraintsColumns#EXTENDED_METADATA} key. You can use
+ * {@link DrmUtils.ExtendedMetadataParser} to iterate over those values.
  */
 public class DrmUtils {
     /* Should be used when we need to read from local file */
@@ -99,13 +101,10 @@
     }
 
     /**
-     * Get an instance of ExtendedMetadataParser to be used for parsing
-     * extended metadata BLOB in DRM constraints. <br>
+     * Gets an instance of {@link DrmUtils.ExtendedMetadataParser}, which can be used to parse
+     * extended metadata embedded in DRM constraint information.
      *
-     * extendedMetadata BLOB is retrieved by specifing
-     * key DrmStore.ConstraintsColumns.EXTENDED_METADATA.
-     *
-     * @param extendedMetadata BLOB in which key-value pairs of extended metadata are embedded.
+     * @param extendedMetadata Object in which key-value pairs of extended metadata are embedded.
      *
      */
     public static ExtendedMetadataParser getExtendedMetadataParser(byte[] extendedMetadata) {
@@ -113,9 +112,10 @@
     }
 
     /**
-     * Utility parser to parse the extended meta-data embedded inside DRM constraints<br><br>
-     *
-     * Usage example<br>
+     * Utility that parses extended metadata embedded in DRM constraint information.
+     *<p>
+     * Usage example:
+     *<p>
      * byte[] extendedMetadata<br>
      * &nbsp;&nbsp;&nbsp;&nbsp; =
      *         constraints.getAsByteArray(DrmStore.ConstraintsColumns.EXTENDED_METADATA);<br>
diff --git a/drm/java/android/drm/ProcessedData.java b/drm/java/android/drm/ProcessedData.java
old mode 100644
new mode 100755
index 579264f..06e03e7
--- a/drm/java/android/drm/ProcessedData.java
+++ b/drm/java/android/drm/ProcessedData.java
@@ -17,11 +17,11 @@
 package android.drm;
 
 /**
- * This is an entity class which wraps the result of transaction between
- * device and online DRM server by using {@link DrmManagerClient#processDrmInfo(DrmInfo)}
+ * An entity class that wraps the result of a 
+ * {@link DrmManagerClient#processDrmInfo(DrmInfo) processDrmInfo()}
+ * transaction between a device and a DRM server.
  *
- * In license acquisition scenario this class would hold the binary data
- * of rights information.
+ * In a license acquisition scenario this class holds the rights information in binary form.
  *
  */
 public class ProcessedData {
@@ -30,10 +30,10 @@
     private String mSubscriptionId = "";
 
     /**
-     * constructor to create ProcessedData object with given parameters
+     * Creates a <code>ProcessedData</code> object with the given parameters.
      *
-     * @param data Rights data
-     * @param accountId Account Id of the user
+     * @param data Rights data.
+     * @param accountId Account ID of the user.
      */
     /* package */ ProcessedData(byte[] data, String accountId) {
         mData = data;
@@ -41,11 +41,11 @@
     }
 
     /**
-     * constructor to create ProcessedData object with given parameters
+     * Creates a <code>ProcessedData</code> object with the given parameters.
      *
-     * @param data Rights data
-     * @param accountId Account Id of the user
-     * @param subscriptionId Subscription Id of the user
+     * @param data Rights data.
+     * @param accountId Account ID of the user.
+     * @param subscriptionId Subscription ID of the user.
      */
     /* package */ ProcessedData(byte[] data, String accountId, String subscriptionId) {
         mData = data;
@@ -54,27 +54,27 @@
     }
 
     /**
-     * Returns the processed data as a result.
+     * Retrieves the processed data.
      *
-     * @return Rights data associated
+     * @return The rights data.
      */
     public byte[] getData() {
         return mData;
     }
 
     /**
-     * Returns the account-id associated with this object
+     * Retrieves the account ID associated with this object.
      *
-     * @return Account Id associated
+     * @return The account ID of the user.
      */
     public String getAccountId() {
         return mAccountId;
     }
 
     /**
-     * Returns the subscription-id associated with this object
+     * Returns the subscription ID associated with this object.
      *
-     * @return Subscription Id associated
+     * @return The subscription ID of the user.
      */
     public String getSubscriptionId() {
         return mSubscriptionId;
diff --git a/drm/java/android/drm/package.html b/drm/java/android/drm/package.html
new file mode 100755
index 0000000..161d6e0
--- /dev/null
+++ b/drm/java/android/drm/package.html
@@ -0,0 +1,85 @@
+<HTML>
+<BODY>
+<p>Provides classes for managing DRM content and determining the capabilities of DRM plugins
+(agents). Common uses of the DRM API include:</p>
+<ul>
+  <li>Determining which DRM plug-ins (agents) are installed on a device.</li>
+  <li>Retrieving information about specific plug-ins, such as the MIME types and file suffixes
+  they support.</li>
+  <li>Registering a user or a device with an online DRM service.</li>
+  <li>Retrieving license constraints for rights-protected content.</li>
+  <li>Checking whether a user has the proper rights to play or use rights-protected
+  content.</li>
+  <li>Associating rights-protected content with its license so you can use the
+  {@link android.media.MediaPlayer} API to play the content.</li>
+</ul>
+
+<h2>DRM Overview</h2>
+
+<p>The Android platform provides an extensible DRM framework that lets applications manage
+rights-protected content according to the license constraints that are associated with the
+content. The DRM framework supports many DRM schemes; which DRM schemes a device supports
+is up to the device manufacturer.</p>
+
+<p>The Android DRM framework is implemented in two architectural layers (see figure below):</p>
+<ul>
+  <li>A DRM framework API, which is exposed to applications through the Android
+application framework and runs through the Dalvik VM for standard applications.</li>
+  <li>A native code DRM manager, which implements the DRM framework and exposes an
+interface for DRM plug-ins (agents) to handle rights management and decryption for various
+DRM schemes.</li>
+</ul>
+
+<img src="../../../images/drm_arch.png" alt="DRM architecture diagram" border="0"/>
+
+<p>For application developers, the DRM framework offers an abstract, unified API that
+simplifies the management of rights-protected content. The API hides the complexity of DRM
+operations and allows a consistent operation mode for both rights-protected and unprotected content
+across a variety of DRM schemes. For device manufacturers, content owners, and Internet digital
+media providers the DRM framework’s plugin architecture provides a means of adding support for a
+specific DRM scheme to the Android system.</p>
+
+<h2>Using the DRM API</h2>
+
+<p>In a typical DRM session, an Android application uses the DRM framework API to
+instantiate a {@link android.drm.DrmManagerClient}. The application calls various methods
+on the DRM client to query rights and perform other DRM-related tasks. Each
+{@link android.drm.DrmManagerClient} instance has its own unique ID, so the DRM manager is able to
+differentiate callers.</p>
+
+<p>Although each DRM plug-in may require a different sequence
+of API calls, the general call sequence for an application is as follows:</p>
+
+<ul>
+  <li>Register the device with an online DRM service.
+    <p>You can do this by first using the {@link android.drm.DrmManagerClient#acquireDrmInfo
+acquireDrmInfo()} method to acquire the registration information, and then using the {@link
+android.drm.DrmManagerClient#processDrmInfo processDrmInfo()} method to process the
+registration information.</p>
+  </li>
+  <li>Acquire the license that's associated with the rights-protected content.
+    <p>You can do this by first using the {@link android.drm.DrmManagerClient#acquireDrmInfo
+acquireDrmInfo()} method to acquire the license information, and then using the {@link
+android.drm.DrmManagerClient#processDrmInfo processDrmInfo()} method to process the
+license information. You can also use the {@link
+android.drm.DrmManagerClient#acquireRights acquireRights()} method.</p>
+  </li>
+  <li>Extract constraint information from the license.
+    <p>You can use the {@link android.drm.DrmManagerClient#getConstraints getConstraints()}
+    method to do this.</p>
+  </li>
+  <li>Associate the rights-protected content with its license.
+    <p>You can use the {@link android.drm.DrmManagerClient#saveRights saveRights()} method
+    to do this.</p>
+  </li>
+</ul>
+
+<p>After you make an association between the rights-protected content and its license,
+the DRM manager automatically handles rights management for that content. Specifically, the
+DRM manager will handle all further licensing checks when you attempt to play the content using
+the {@link android.media.MediaPlayer} API.</p>
+
+<p>To learn how to use the DRM API with a specific DRM plug-in, see the documentation provided
+by the plug-in developer.</p>
+</BODY>
+</HTML>
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 965abe9..e493b18 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1330,6 +1330,29 @@
     }
 
     /**
+     * Draw the glyphs, with origin at (x,y), using the specified paint. The
+     * origin is interpreted based on the Align setting in the paint.
+     *
+     * @param glyphs The glyphs to be drawn
+     * @param x      The x-coordinate of the origin of the text being drawn
+     * @param y      The y-coordinate of the origin of the text being drawn
+     * @param paint  The paint used for the text (e.g. color, size, style)
+     *
+     * @hide
+     *
+     * Used only for BiDi / RTL Tests
+     */
+    public void drawGlyphs(char[] glyphs, int index, int count, float x, float y,
+                         Paint paint) {
+        if ((index | count | (index + count) |
+            (glyphs.length - index - count)) < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        native_drawGlyphs(mNativeCanvas, glyphs, index, count, x, y, paint.mBidiFlags,
+                paint.mNativePaint);
+    }
+
+    /**
      * Draw the text, with origin at (x,y), using the specified paint. The
      * origin is interpreted based on the Align setting in the paint.
      *
@@ -1722,7 +1745,9 @@
     private static native void native_drawText(int nativeCanvas, String text,
                                                int start, int end, float x,
                                                float y, int flags, int paint);
-
+    private static native void native_drawGlyphs(int nativeCanvas, char[] glyphs,
+                                               int index, int count, float x,
+                                               float y, int flags, int paint);
     private static native void native_drawTextRun(int nativeCanvas, String text,
             int start, int end, int contextStart, int contextEnd,
             float x, float y, int flags, int paint);
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 0a23bae..96eb936 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1455,6 +1455,43 @@
     }
 
     /**
+     * Return the glypth Ids for the characters in the string.
+     *
+     * @param text   The text to measure
+     * @param start  The index of the first char to to measure
+     * @param end    The end of the text slice to measure
+     * @param contextStart the index of the first character to use for shaping context,
+     * must be <= start
+     * @param contextEnd the index past the last character to use for shaping context,
+     * must be >= end
+     * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
+     * or {@link #DIRECTION_RTL}
+     * @param glyphs array to receive the glyph Ids of the characters.
+     *               Must be at least a large as the text.
+     * @return       the number of glyphs in the returned array
+     *
+     * @hide
+     *
+     * Used only for BiDi / RTL Tests
+     */
+    public int getTextGlypths(String text, int start, int end, int contextStart, int contextEnd,
+            int flags, char[] glyphs) {
+        if ((start | end | contextStart | contextEnd | (end - start)
+                | (start - contextStart) | (contextEnd - end) | (text.length() - end)
+                | (text.length() - contextEnd)) < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        if (end - start > glyphs.length) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
+            throw new IllegalArgumentException("unknown flags value: " + flags);
+        }
+        return native_getTextGlyphs(mNativePaint, text, start, end, contextStart, contextEnd,
+                flags, glyphs);
+    }
+
+    /**
      * Convenience overload that takes a char array instead of a
      * String.
      *
@@ -1859,6 +1896,10 @@
     private static native int native_getTextWidths(int native_object,
                             String text, int start, int end, float[] widths);
 
+    private static native int native_getTextGlyphs(int native_object,
+            String text, int start, int end, int contextStart, int contextEnd,
+            int flags, char[] glyphs);
+
     private static native float native_getTextRunAdvances(int native_object,
             char[] text, int index, int count, int contextIndex, int contextCount,
             int flags, float[] advances, int advancesIndex);
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index b8327a8..cfae0c1 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -153,7 +153,6 @@
      * the SurfaceTexture. Unless otherwise specified by the image source, timestamps cannot
      * generally be compared across SurfaceTexture instances, or across multiple program
      * invocations. It is mostly useful for determining time offsets between subsequent frames.
-     * @hide
      */
     public long getTimestamp() {
         return nativeGetTimestamp();
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 2c09ddc..22fbdf9 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -88,6 +88,7 @@
      * Create an empty drawable, setting initial target density based on
      * the display metrics of the resources.
      */
+    @SuppressWarnings({"UnusedParameters"})
     public BitmapDrawable(Resources res) {
         mBitmapState = new BitmapState((Bitmap) null);
         mBitmapState.mTargetDensity = mTargetDensity;
@@ -128,6 +129,7 @@
     /**
      * Create a drawable by opening a given file path and decoding the bitmap.
      */
+    @SuppressWarnings({"UnusedParameters"})
     public BitmapDrawable(Resources res, String filepath) {
         this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
         mBitmapState.mTargetDensity = mTargetDensity;
@@ -152,6 +154,7 @@
     /**
      * Create a drawable by decoding a bitmap from the given input stream.
      */
+    @SuppressWarnings({"UnusedParameters"})
     public BitmapDrawable(Resources res, java.io.InputStream is) {
         this(new BitmapState(BitmapFactory.decodeStream(is)), null);
         mBitmapState.mTargetDensity = mTargetDensity;
@@ -160,10 +163,16 @@
         }
     }
 
+    /**
+     * Returns the paint used to render this drawable.
+     */
     public final Paint getPaint() {
         return mBitmapState.mPaint;
     }
-    
+
+    /**
+     * Returns the bitmap used by this drawable to render. May be null.
+     */
     public final Bitmap getBitmap() {
         return mBitmap;
     }
@@ -249,6 +258,12 @@
         }
     }
 
+    /**
+     * Enables or disables anti-aliasing for this drawable. Anti-aliasing affects
+     * the edges of the bitmap only so it applies only when the drawable is rotated.
+     * 
+     * @param aa True if the bitmap should be anti-aliased, false otherwise.
+     */
     public void setAntiAlias(boolean aa) {
         mBitmapState.mPaint.setAntiAlias(aa);
         invalidateSelf();
@@ -266,26 +281,71 @@
         invalidateSelf();
     }
 
+    /**
+     * Indicates the repeat behavior of this drawable on the X axis.
+     * 
+     * @return {@link Shader.TileMode#CLAMP} if the bitmap does not repeat,
+     *         {@link Shader.TileMode#REPEAT} or {@link Shader.TileMode#MIRROR} otherwise.
+     */
     public Shader.TileMode getTileModeX() {
         return mBitmapState.mTileModeX;
     }
 
+    /**
+     * Indicates the repeat behavior of this drawable on the Y axis.
+     * 
+     * @return {@link Shader.TileMode#CLAMP} if the bitmap does not repeat,
+     *         {@link Shader.TileMode#REPEAT} or {@link Shader.TileMode#MIRROR} otherwise.
+     */    
     public Shader.TileMode getTileModeY() {
         return mBitmapState.mTileModeY;
     }
 
+    /**
+     * Sets the repeat behavior of this drawable on the X axis. By default, the drawable
+     * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
+     * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
+     * is smaller than this drawable.
+     * 
+     * @param mode The repeat mode for this drawable.
+     * 
+     * @see #setTileModeY(android.graphics.Shader.TileMode) 
+     * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode) 
+     */
     public void setTileModeX(Shader.TileMode mode) {
         setTileModeXY(mode, mBitmapState.mTileModeY);
     }
 
+    /**
+     * Sets the repeat behavior of this drawable on the Y axis. By default, the drawable
+     * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
+     * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
+     * is smaller than this drawable.
+     * 
+     * @param mode The repeat mode for this drawable.
+     * 
+     * @see #setTileModeX(android.graphics.Shader.TileMode) 
+     * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode) 
+     */    
     public final void setTileModeY(Shader.TileMode mode) {
         setTileModeXY(mBitmapState.mTileModeX, mode);
     }
 
+    /**
+     * Sets the repeat behavior of this drawable on both axis. By default, the drawable
+     * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
+     * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
+     * is smaller than this drawable.
+     * 
+     * @param xmode The X repeat mode for this drawable.
+     * @param ymode The Y repeat mode for this drawable.
+     * 
+     * @see #setTileModeX(android.graphics.Shader.TileMode)
+     * @see #setTileModeY(android.graphics.Shader.TileMode) 
+     */
     public void setTileModeXY(Shader.TileMode xmode, Shader.TileMode ymode) {
         final BitmapState state = mBitmapState;
-        if (state.mPaint.getShader() == null ||
-                state.mTileModeX != xmode || state.mTileModeY != ymode) {
+        if (state.mTileModeX != xmode || state.mTileModeY != ymode) {
             state.mTileModeX = xmode;
             state.mTileModeY = ymode;
             mRebuildShader = true;
@@ -316,10 +376,9 @@
                 if (tmx == null && tmy == null) {
                     state.mPaint.setShader(null);
                 } else {
-                    Shader s = new BitmapShader(bitmap,
+                    state.mPaint.setShader(new BitmapShader(bitmap,
                             tmx == null ? Shader.TileMode.CLAMP : tmx,
-                            tmy == null ? Shader.TileMode.CLAMP : tmy);
-                    state.mPaint.setShader(s);
+                            tmy == null ? Shader.TileMode.CLAMP : tmy));
                 }
                 mRebuildShader = false;
                 copyBounds(mDstRect);
@@ -335,7 +394,7 @@
                 canvas.drawBitmap(bitmap, null, mDstRect, state.mPaint);
             } else {
                 if (mApplyGravity) {
-                    mDstRect.set(getBounds());
+                    copyBounds(mDstRect);
                     mApplyGravity = false;
                 }
                 canvas.drawRect(mDstRect, state.mPaint);
@@ -365,6 +424,7 @@
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
             mBitmapState = new BitmapState(mBitmapState);
+            mRebuildShader = true;
             mMutated = true;
         }
         return this;
@@ -448,8 +508,8 @@
         int mChangingConfigurations;
         int mGravity = Gravity.FILL;
         Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS);
-        Shader.TileMode mTileModeX;
-        Shader.TileMode mTileModeY;
+        Shader.TileMode mTileModeX = null;
+        Shader.TileMode mTileModeY = null;
         int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
 
         BitmapState(Bitmap bitmap) {
@@ -491,6 +551,6 @@
         } else {
             mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
         }
-        setBitmap(state.mBitmap);
+        setBitmap(state != null ? state.mBitmap : null);
     }
 }
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index 0a6e4fb..972e799 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -291,9 +291,6 @@
     void* reserved_proc[2];
 };
 
-// Backwards compatibility...  please switch to ANativeWindow.
-typedef struct ANativeWindow android_native_window_t;
-
 /*
  *  native_window_set_usage(..., usage)
  *  Sets the intended usage flags for the next buffers
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 14471bc..f74238e 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -26,7 +26,7 @@
 // Turn on to enable memory usage summary on each frame
 #define DEBUG_MEMORY_USAGE 0
 
-// Turn on to enable layers debugging when renderered as regions
+// Turn on to enable layers debugging when rendered as regions
 #define DEBUG_LAYERS_AS_REGIONS 0
 
 // Turn on to display debug info about vertex/fragment shaders
@@ -35,7 +35,7 @@
 // Turn on to display info about layers
 #define DEBUG_LAYERS 0
 
-// Turn on to display debug infor about 9patch objects
+// Turn on to display debug info about 9patch objects
 #define DEBUG_PATCHES 0
 // Turn on to display vertex and tex coords data about 9patch objects
 // This flag requires DEBUG_PATCHES to be turned on
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index bf1182c..c7459d1 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -93,7 +93,9 @@
     mPaints.clear();
 
     for (size_t i = 0; i < mPaths.size(); i++) {
-        delete mPaths.itemAt(i);
+        SkPath* path = mPaths.itemAt(i);
+        caches.pathCache.remove(path);
+        delete path;
     }
     mPaths.clear();
 
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 3a7aa96..f685d5f 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -42,7 +42,7 @@
 class Font {
 public:
     enum Style {
-        kFakeBold
+        kFakeBold = 1
     };
 
     ~Font();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6c454a4..6fabbef 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -647,6 +647,9 @@
 void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
 #if RENDER_LAYERS_AS_REGIONS
     if (layer->region.isRect()) {
+        const android::Rect& bounds = layer->region.getBounds();
+        layer->regionRect.set(bounds.leftTop().x, bounds.leftTop().y,
+                bounds.rightBottom().x, bounds.rightBottom().y);
         composeLayerRect(layer, layer->regionRect);
         layer->region.clear();
         return;
@@ -1099,7 +1102,9 @@
 
     setupDraw();
     setupDrawWithTexture(true);
-    setupDrawAlpha8Color(paint->getColor(), alpha);
+    if (paint) {
+        setupDrawAlpha8Color(paint->getColor(), alpha);
+    }
     setupDrawColorFilter();
     setupDrawShader();
     setupDrawBlending(true, mode);
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 2562306..f0bc36b 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -42,7 +42,7 @@
 const char* gVS_Header_Uniforms =
         "uniform mat4 transform;\n";
 const char* gVS_Header_Uniforms_IsPoint =
-        "uniform float pointSize;\n";
+        "uniform mediump float pointSize;\n";
 const char* gVS_Header_Uniforms_HasGradient[3] = {
         // Linear
         "uniform mat4 screenSpace;\n",
@@ -53,7 +53,7 @@
 };
 const char* gVS_Header_Uniforms_HasBitmap =
         "uniform mat4 textureTransform;\n"
-        "uniform vec2 textureDimension;\n";
+        "uniform mediump vec2 textureDimension;\n";
 const char* gVS_Header_Varyings_HasTexture =
         "varying vec2 outTexCoords;\n";
 const char* gVS_Header_Varyings_HasBitmap =
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
index 859e503..b5cc29c 100644
--- a/libs/hwui/ShapeCache.h
+++ b/libs/hwui/ShapeCache.h
@@ -89,8 +89,11 @@
         join = SkPaint::kDefault_Join;
         cap = SkPaint::kDefault_Cap;
         style = SkPaint::kFill_Style;
-        miter = 4.0f;
-        strokeWidth = 1.0f;
+        float v = 4.0f;
+        miter = *(uint32_t*) &v;
+        v = 1.0f;
+        strokeWidth = *(uint32_t*) &v;
+        pathEffect = NULL;
     }
 
     ShapeCacheEntry(const ShapeCacheEntry& entry):
diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
index 6e4edce..2038a4c 100644
--- a/libs/rs/driver/rsdBcc.cpp
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -522,7 +522,7 @@
     if (drv->mFieldAddress) {
         for (size_t ct=0; ct < drv->mFieldCount; ct++) {
             if (drv->mFieldIsObject[ct]) {
-                rsiClearObject((ObjectBase **)drv->mFieldAddress[ct]);
+                rsiClearObject((ObjectBase **)&drv->mFieldAddress[ct]);
             }
         }
         delete [] drv->mFieldAddress;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 7fdb1a1..b893695 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define DEBUG_HDCP
+
 //#define LOG_NDEBUG 0
 #define LOG_TAG "AwesomePlayer"
 #include <utils/Log.h>
@@ -50,6 +52,8 @@
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 
+#include <cutils/properties.h>
+
 #define USE_SURFACE_ALLOC 1
 #define FRAME_DROP_FREQ 0
 
@@ -1202,9 +1206,42 @@
     //   (USE_SURFACE_ALLOC && (mSurface != 0) &&
     //   (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp))
     // will be true, but that part is already handled by SurfaceFlinger.
+
+#ifdef DEBUG_HDCP
+    // For debugging, we allow a system property to control the protected usage.
+    // In case of uninitialized or unexpected property, we default to "DRM only".
+    bool setProtectionBit = false;
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("persist.sys.hdcp_checking", value, NULL)) {
+        if (!strcmp(value, "never")) {
+            // nop
+        } else if (!strcmp(value, "always")) {
+            setProtectionBit = true;
+        } else if (!strcmp(value, "drm-only")) {
+            if (mDecryptHandle != NULL) {
+                setProtectionBit = true;
+            }
+        // property value is empty, or unexpected value
+        } else {
+            if (mDecryptHandle != NULL) {
+                setProtectionBit = true;
+            }
+        }
+    // can' read property value
+    } else {
+        if (mDecryptHandle != NULL) {
+            setProtectionBit = true;
+        }
+    }
+    // note that usage bit is already cleared, so no need to clear it in the "else" case
+    if (setProtectionBit) {
+        flags |= OMXCodec::kEnableGrallocUsageProtected;
+    }
+#else
     if (mDecryptHandle != NULL) {
         flags |= OMXCodec::kEnableGrallocUsageProtected;
     }
+#endif
     LOGV("initVideoDecoder flags=0x%x", flags);
     mVideoSource = OMXCodec::Create(
             mClient.interface(), mVideoTrack->getFormat(),
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/VideoEditorStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/VideoEditorStressTest.java
index 432fb43..94ffb8e 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/VideoEditorStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/VideoEditorStressTest.java
@@ -51,10 +51,11 @@
 
 import android.os.Debug;
 import android.util.Log;
-
+import com.android.mediaframeworktest.MediaFrameworkPerfTestRunner;
 import com.android.mediaframeworktest.MediaFrameworkTest;
 import android.test.suitebuilder.annotation.LargeTest;
 import com.android.mediaframeworktest.VideoEditorHelper;
+import com.android.mediaframeworktest.MediaTestUtil;
 
 /**
  * Junit / Instrumentation - performance measurement for media player and
@@ -63,7 +64,7 @@
 public class VideoEditorStressTest
         extends ActivityInstrumentationTestCase<MediaFrameworkTest> {
 
-    private final String TAG = "VideoEditorPerformance";
+    private final String TAG = "VideoEditorStressTest";
 
     private final String PROJECT_LOCATION = VideoEditorHelper.PROJECT_LOCATION_COMMON;
 
@@ -86,12 +87,17 @@
     private final String PROJECT_CLASS_NAME =
         "android.media.videoeditor.VideoEditorImpl";
     private VideoEditor mVideoEditor;
+    private MediaTestUtil mMediaTestUtil;
     private VideoEditorHelper mVideoEditorHelper;
 
     @Override
     protected void setUp() throws Exception {
         // setup for each test case.
         super.setUp();
+        getActivity();
+        mMediaTestUtil = new MediaTestUtil(
+            "/sdcard/VideoEditorMediaServerMemoryLog.txt",
+             this.getName(), "mediaserver");
         mVideoEditorHelper = new VideoEditorHelper();
         // Create a random String which will be used as project path, where all
         // project related files will be stored.
@@ -102,6 +108,12 @@
 
     @Override
     protected void tearDown() throws Exception {
+        final String[] loggingInfo = new String[1];
+        mMediaTestUtil.getMemorySummary();
+        loggingInfo[0] = "\n" +this.getName();
+        writeTimingInfo(loggingInfo);
+        loggingInfo[0] = " diff :  " + (AfterNativeMemory - BeginNativeMemory);
+        writeTimingInfo(loggingInfo);
         mVideoEditorHelper.destroyVideoEditor(mVideoEditor);
         // Clean the directory created as project path
         mVideoEditorHelper.deleteProject(new File(mVideoEditor.getPath()));
@@ -131,6 +143,7 @@
         System.gc();
         Thread.sleep(2500);
         BeginNativeMemory = Debug.getNativeHeapAllocatedSize();
+        mMediaTestUtil.getStartMemoryLog();
     }
     private void getAfterMemory_updateLog(String[] loggingInfo, boolean when,
         int iteration)
@@ -146,6 +159,7 @@
                 "\t " + (AfterNativeMemory - BeginNativeMemory);
         }
         writeTimingInfo(loggingInfo);
+        mMediaTestUtil.getMemoryLog();
     }
 
     /**
@@ -170,7 +184,6 @@
         writeTestCaseHeader("testStressAddRemoveVideoItem");
         int i = 0;
         getBeginMemory();
-
         for ( i = 0; i < 50; i++) {
             if (i % 4 == 0) {
                 final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
@@ -203,7 +216,6 @@
         getAfterMemory_updateLog(loggingInfo, false, i);
 
         /** Remove items and check for memory leak if any */
-        getBeginMemory();
         for ( i = 0; i < 50; i++) {
             if (i % 4 == 0) {
                 mVideoEditor.removeMediaItem("m1" + i);
@@ -273,7 +285,6 @@
         getAfterMemory_updateLog(loggingInfo, false, i);
 
         /** Remove items and check for memory leak if any */
-        getBeginMemory();
         for ( i = 0; i < 50; i++) {
             if (i % 4 == 0) {
                 mVideoEditor.removeMediaItem("m1"+i);
@@ -387,7 +398,6 @@
         getAfterMemory_updateLog(loggingInfo, false, i);
 
         /** Remove items and check for memory leak if any */
-        getBeginMemory();
         for ( i = 0; i < 50; i++) {
             if (i % 4 == 0) {
                 mVideoEditor.removeTransition("transCF" + i);
@@ -551,7 +561,6 @@
         getAfterMemory_updateLog(loggingInfo, false, i);
 
         /** Remove items and check for memory leak if any */
-        getBeginMemory();
         for ( i = 0; i < 50; i++) {
             if (i % 5 == 0) {
                 mediaItem1.removeEffect("effect1"+i);
@@ -773,15 +782,14 @@
         getAfterMemory_updateLog(loggingInfo, false, i);
 
         /** Remove items and check for memory leak if any */
-        getBeginMemory();
         for ( i = 0; i < 50; i++) {
             mVideoEditor.removeMediaItem("m3" + i);
             if (i % 10 == 0) {
                 getAfterMemory_updateLog(loggingInfo, true, i);
             }
         }
-            mVideoEditor.removeMediaItem("m2");
-            mVideoEditor.removeMediaItem("m1");
+        mVideoEditor.removeMediaItem("m2");
+        mVideoEditor.removeMediaItem("m1");
         getAfterMemory_updateLog(loggingInfo, true, i);
     }
 
@@ -879,7 +887,6 @@
         getAfterMemory_updateLog(loggingInfo, false, i);
 
         /** Remove items and check for memory leak if any */
-        getBeginMemory();
         for( i=0; i<10; i++){
             final VideoEditor mVideoEditor1b =
                 VideoEditorFactory.load(projectPath[i], true);
@@ -986,7 +993,6 @@
         getAfterMemory_updateLog(loggingInfo, false, i);
 
         /** Remove items and check for memory leak if any */
-        getBeginMemory();
         mVideoEditor.removeMediaItem("m2");
         mVideoEditor.removeMediaItem("m1");
 
@@ -1063,7 +1069,6 @@
         getAfterMemory_updateLog(loggingInfo, false, i);
 
         /** Remove items and check for memory leak if any */
-        getBeginMemory();
         for ( i = 0; i < 10; i++) {
             MediaImageItem m2 = (MediaImageItem)mVideoEditor.getMediaItem("m2"+i);
             MediaVideoItem m1 = (MediaVideoItem)mVideoEditor.getMediaItem("m1"+i);
@@ -1129,7 +1134,6 @@
         getAfterMemory_updateLog(loggingInfo, false, i);
 
         /** Remove items and check for memory leak if any */
-        getBeginMemory();
         mVideoEditor.removeMediaItem("mediaItem1");
 
         getAfterMemory_updateLog(loggingInfo, true, i);
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 75f7078..e0a7662 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -195,6 +195,7 @@
     
     egl_display_t() : magic('_dpy'), numTotalConfigs(0), configs(0) { }
     ~egl_display_t() { magic = 0; }
+    inline bool isReady() const { return (refs > 0); }
     inline bool isValid() const { return magic == '_dpy'; }
     inline bool isAlive() const { return isValid(); }
 };
@@ -609,12 +610,22 @@
     return egl_to_native_cast<egl_sync_t>(sync);
 }
 
+static inline
+egl_display_t* validate_display(EGLDisplay dpy)
+{
+    egl_display_t * const dp = get_display(dpy);
+    if (!dp) return setError(EGL_BAD_DISPLAY, (egl_display_t*)NULL);
+    if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, (egl_display_t*)NULL);
+
+    return dp;
+}
+
 static egl_connection_t* validate_display_config(
         EGLDisplay dpy, EGLConfig config,
         egl_display_t const*& dp)
 {
-    dp = get_display(dpy);
-    if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
+    dp = validate_display(dpy);
+    if (!dp) return (egl_connection_t*) NULL;
 
     if (intptr_t(config) >= dp->numTotalConfigs) {
         return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
@@ -628,9 +639,9 @@
 
 static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
 {
-    if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    if (!get_display(dpy)->isAlive())
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+    if (!dp->isAlive())
         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
     if (!get_context(ctx)->isAlive())
         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
@@ -639,9 +650,9 @@
 
 static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
 {
-    if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    if (!get_display(dpy)->isAlive())
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+    if (!dp->isAlive())
         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
     if (!get_surface(surface)->isAlive())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
@@ -961,8 +972,8 @@
 {
     clearError();
 
-    egl_display_t const * const dp = get_display(dpy);
-    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
 
     GLint numConfigs = dp->numTotalConfigs;
     if (!configs) {
@@ -987,8 +998,8 @@
 {
     clearError();
 
-    egl_display_t const * const dp = get_display(dpy);
-    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
 
     if (num_config==0) {
         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
@@ -1206,12 +1217,14 @@
 {
     clearError();
 
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
     SurfaceRef _s(surface);
     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     if (!validate_display_surface(dpy, surface))
         return EGL_FALSE;    
-    egl_display_t const * const dp = get_display(dpy);
 
     egl_surface_t * const s = get_surface(surface);
     EGLBoolean result = s->cnx->egl.eglDestroySurface(
@@ -1230,12 +1243,14 @@
 {
     clearError();
 
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
     SurfaceRef _s(surface);
     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     if (!validate_display_surface(dpy, surface))
         return EGL_FALSE;    
-    egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(surface);
 
     EGLBoolean result(EGL_TRUE);
@@ -1298,12 +1313,14 @@
 {
     clearError();
 
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
     ContextRef _c(ctx);
     if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
     
     if (!validate_display_context(dpy, ctx))
         return EGL_FALSE;
-    egl_display_t const * const dp = get_display(dpy);
     egl_context_t * const c = get_context(ctx);
     EGLBoolean result = c->cnx->egl.eglDestroyContext(
             dp->disp[c->impl].dpy, c->context);
@@ -1339,14 +1356,23 @@
 {
     clearError();
 
+    egl_display_t const * const dp = get_display(dpy);
+    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+    /* If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
+       EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
+       a valid but uninitialized display. */
+    if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
+         (draw != EGL_NO_SURFACE) ) {
+        if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+    }
+
     // get a reference to the object passed in
     ContextRef _c(ctx);
     SurfaceRef _d(draw);
     SurfaceRef _r(read);
 
-    // validate the display and the context (if not EGL_NO_CONTEXT)
-    egl_display_t const * const dp = get_display(dpy);
-    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    // validate the context (if not EGL_NO_CONTEXT)
     if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
         // EGL_NO_CONTEXT is valid
         return EGL_FALSE;
@@ -1439,13 +1465,15 @@
 {
     clearError();
 
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
     ContextRef _c(ctx);
     if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
 
     if (!validate_display_context(dpy, ctx))
         return EGL_FALSE;    
     
-    egl_display_t const * const dp = get_display(dpy);
     egl_context_t * const c = get_context(ctx);
 
     EGLBoolean result(EGL_TRUE);
@@ -1681,12 +1709,14 @@
 
     clearError();
 
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
     SurfaceRef _s(draw);
     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     if (!validate_display_surface(dpy, draw))
         return EGL_FALSE;    
-    egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(draw);
     return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
 }
@@ -1696,12 +1726,14 @@
 {
     clearError();
 
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
     SurfaceRef _s(surface);
     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     if (!validate_display_surface(dpy, surface))
         return EGL_FALSE;    
-    egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(surface);
     return s->cnx->egl.eglCopyBuffers(
             dp->disp[s->impl].dpy, s->surface, target);
@@ -1711,7 +1743,9 @@
 {
     clearError();
 
-    egl_display_t const * const dp = get_display(dpy);
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return (const char *) NULL;
+
     switch (name) {
         case EGL_VENDOR:
             return gVendorString;
@@ -1735,12 +1769,14 @@
 {
     clearError();
 
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
     SurfaceRef _s(surface);
     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     if (!validate_display_surface(dpy, surface))
         return EGL_FALSE;    
-    egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(surface);
     if (s->cnx->egl.eglSurfaceAttrib) {
         return s->cnx->egl.eglSurfaceAttrib(
@@ -1754,12 +1790,14 @@
 {
     clearError();
 
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
     SurfaceRef _s(surface);
     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     if (!validate_display_surface(dpy, surface))
         return EGL_FALSE;    
-    egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(surface);
     if (s->cnx->egl.eglBindTexImage) {
         return s->cnx->egl.eglBindTexImage(
@@ -1773,12 +1811,14 @@
 {
     clearError();
 
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
     SurfaceRef _s(surface);
     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     if (!validate_display_surface(dpy, surface))
         return EGL_FALSE;    
-    egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(surface);
     if (s->cnx->egl.eglReleaseTexImage) {
         return s->cnx->egl.eglReleaseTexImage(
@@ -1791,8 +1831,8 @@
 {
     clearError();
 
-    egl_display_t * const dp = get_display(dpy);
-    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
 
     EGLBoolean res = EGL_TRUE;
     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
@@ -1930,13 +1970,15 @@
 {
     clearError();
 
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
     SurfaceRef _s(surface);
     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     if (!validate_display_surface(dpy, surface))
         return EGL_FALSE;
 
-    egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(surface);
 
     if (s->cnx->egl.eglLockSurfaceKHR) {
@@ -1950,13 +1992,15 @@
 {
     clearError();
 
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
     SurfaceRef _s(surface);
     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     if (!validate_display_surface(dpy, surface))
         return EGL_FALSE;
 
-    egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(surface);
 
     if (s->cnx->egl.eglUnlockSurfaceKHR) {
@@ -1971,12 +2015,14 @@
 {
     clearError();
 
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_NO_IMAGE_KHR;
+
     if (ctx != EGL_NO_CONTEXT) {
         ContextRef _c(ctx);
         if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
         if (!validate_display_context(dpy, ctx))
             return EGL_NO_IMAGE_KHR;
-        egl_display_t const * const dp = get_display(dpy);
         egl_context_t * const c = get_context(ctx);
         // since we have an EGLContext, we know which implementation to use
         EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
@@ -1989,10 +2035,6 @@
         return (EGLImageKHR)result;
     } else {
         // EGL_NO_CONTEXT is a valid parameter
-        egl_display_t const * const dp = get_display(dpy);
-        if (dp == 0) {
-            return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
-        }
 
         /* Since we don't have a way to know which implementation to call,
          * we're calling all of them. If at least one of the implementation
@@ -2044,35 +2086,33 @@
 {
     clearError();
 
-    egl_display_t const * const dp = get_display(dpy);
-     if (dp == 0) {
-         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-     }
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
 
-     ImageRef _i(img);
-     if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+    ImageRef _i(img);
+    if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
 
-     egl_image_t* image = get_image(img);
-     bool success = false;
-     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
-         egl_connection_t* const cnx = &gEGLImpl[i];
-         if (image->images[i] != EGL_NO_IMAGE_KHR) {
-             if (cnx->dso) {
-                 if (cnx->egl.eglDestroyImageKHR) {
-                     if (cnx->egl.eglDestroyImageKHR(
-                             dp->disp[i].dpy, image->images[i])) {
-                         success = true;
-                     }
-                 }
-             }
-         }
-     }
-     if (!success)
-         return EGL_FALSE;
+    egl_image_t* image = get_image(img);
+    bool success = false;
+    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+        egl_connection_t* const cnx = &gEGLImpl[i];
+        if (image->images[i] != EGL_NO_IMAGE_KHR) {
+            if (cnx->dso) {
+                if (cnx->egl.eglDestroyImageKHR) {
+                    if (cnx->egl.eglDestroyImageKHR(
+                            dp->disp[i].dpy, image->images[i])) {
+                        success = true;
+                    }
+                }
+            }
+        }
+    }
+    if (!success)
+        return EGL_FALSE;
 
-     _i.terminate();
+    _i.terminate();
 
-     return EGL_TRUE;
+    return EGL_TRUE;
 }
 
 // ----------------------------------------------------------------------------
@@ -2084,12 +2124,14 @@
 {
     clearError();
 
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_NO_SYNC_KHR;
+
     EGLContext ctx = eglGetCurrentContext();
     ContextRef _c(ctx);
     if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
     if (!validate_display_context(dpy, ctx))
         return EGL_NO_SYNC_KHR;
-    egl_display_t const * const dp = get_display(dpy);
     egl_context_t * const c = get_context(ctx);
     EGLSyncKHR result = EGL_NO_SYNC_KHR;
     if (c->cnx->egl.eglCreateSyncKHR) {
@@ -2106,10 +2148,8 @@
 {
     clearError();
 
-    egl_display_t const * const dp = get_display(dpy);
-    if (dp == 0) {
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    }
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
 
     SyncRef _s(sync);
     if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
@@ -2136,10 +2176,8 @@
 {
     clearError();
 
-    egl_display_t const * const dp = get_display(dpy);
-    if (dp == 0) {
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    }
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
 
     SyncRef _s(sync);
     if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
@@ -2165,10 +2203,8 @@
 {
     clearError();
 
-    egl_display_t const * const dp = get_display(dpy);
-    if (dp == 0) {
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    }
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
 
     SyncRef _s(sync);
     if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
@@ -2199,12 +2235,14 @@
 {
     clearError();
 
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
     SurfaceRef _s(draw);
     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     if (!validate_display_surface(dpy, draw))
         return EGL_FALSE;    
-    egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(draw);
     if (s->cnx->egl.eglSetSwapRectangleANDROID) {
         return s->cnx->egl.eglSetSwapRectangleANDROID(
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 1ab22c0..12ac052 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1409,10 +1409,13 @@
         if (TextUtils.isEmpty(interfaceName)) return;
         for (InetAddress gateway : p.getGateways()) {
 
-            if (!NetworkUtils.addDefaultRoute(interfaceName, gateway) && DBG) {
-                NetworkInfo networkInfo = nt.getNetworkInfo();
-                log("addDefaultRoute for " + networkInfo.getTypeName() +
-                        " (" + interfaceName + "), GatewayAddr=" + gateway.getHostAddress());
+            if (NetworkUtils.addHostRoute(interfaceName, gateway, null) &&
+                    NetworkUtils.addDefaultRoute(interfaceName, gateway)) {
+                if (DBG) {
+                    NetworkInfo networkInfo = nt.getNetworkInfo();
+                    log("addDefaultRoute for " + networkInfo.getTypeName() +
+                            " (" + interfaceName + "), GatewayAddr=" + gateway.getHostAddress());
+                }
             }
         }
     }
@@ -1424,10 +1427,12 @@
         String interfaceName = p.getInterfaceName();
 
         if (interfaceName != null) {
-            if ((NetworkUtils.removeDefaultRoute(interfaceName) >= 0) && DBG) {
-                NetworkInfo networkInfo = nt.getNetworkInfo();
-                log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
-                        interfaceName + ")");
+            if (NetworkUtils.removeDefaultRoute(interfaceName) >= 0) {
+                if (DBG) {
+                    NetworkInfo networkInfo = nt.getNetworkInfo();
+                    log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
+                            interfaceName + ")");
+                }
             }
         }
     }
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 1f5fc05..b5578c3 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -219,6 +219,7 @@
     protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
 
     //***** Member Variables
+    protected ApnSetting mApn;
     protected int mTag;
     protected PhoneBase phone;
     protected int cid;
@@ -429,11 +430,12 @@
     protected void clearSettings() {
         if (DBG) log("clearSettings");
 
-        this.createTime = -1;
-        this.lastFailTime = -1;
-        this.lastFailCause = FailCause.NONE;
+        createTime = -1;
+        lastFailTime = -1;
+        lastFailCause = FailCause.NONE;
 
         mLinkProperties = new LinkProperties();
+        mApn = null;
     }
 
     /**
@@ -1087,4 +1089,11 @@
     public FailCause getLastFailCause() {
         return lastFailCause;
     }
+
+    /**
+     * @return the current ApnSetting
+     */
+    public ApnSetting getApn() {
+        return mApn;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 7f0c7c7d8..d4a3c0a 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -441,7 +441,6 @@
     protected abstract void onRadioOffOrNotAvailable();
     protected abstract void onDataSetupComplete(AsyncResult ar);
     protected abstract void onDisconnectDone(int connId, AsyncResult ar);
-    protected abstract void onResetDone(AsyncResult ar);
     protected abstract void onVoiceCallStarted();
     protected abstract void onVoiceCallEnded();
     protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
@@ -514,9 +513,10 @@
                 onSetInternalDataEnabled(enabled);
                 break;
             }
-            case EVENT_RESET_DONE:
+            case EVENT_RESET_DONE: {
                 onResetDone((AsyncResult) msg.obj);
                 break;
+            }
             case CMD_SET_DATA_ENABLE: {
                 log("CMD_SET_DATA_ENABLE msg=" + msg);
                 boolean enabled = (msg.arg1 == ENABLED) ? true : false;
@@ -602,6 +602,8 @@
 
     protected abstract void setState(State s);
 
+    protected abstract void gotoIdleAndNotifyDataConnection(String reason);
+
     protected LinkProperties getLinkProperties(String apnType) {
         int id = apnTypeToId(apnType);
         if (isApnIdEnabled(id)) {
@@ -873,6 +875,22 @@
     }
 
     /**
+     * Called when EVENT_RESET_DONE is received so goto
+     * IDLE state and send notifications to those interested.
+     *
+     * TODO - currently unused.  Needs to be hooked into DataConnection cleanup
+     * TODO - needs to pass some notion of which connection is reset..
+     */
+    protected void onResetDone(AsyncResult ar) {
+        if (DBG) log("EVENT_RESET_DONE");
+        String reason = null;
+        if (ar.userObj instanceof String) {
+            reason = (String) ar.userObj;
+        }
+        gotoIdleAndNotifyDataConnection(reason);
+    }
+
+    /**
      * Prevent mobile data connections from being established, or once again
      * allow mobile data connections. If the state toggles, then either tear
      * down or set up data, as appropriate to match the new state.
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 88aed28..1d47405 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -207,9 +207,8 @@
  */
 public final class RIL extends BaseCommands implements CommandsInterface {
     static final String LOG_TAG = "RILJ";
-    private static final boolean DBG = false;
-    static final boolean RILJ_LOGD = Config.LOGD;
-    static final boolean RILJ_LOGV = DBG ? Config.LOGD : Config.LOGV;
+    static final boolean RILJ_LOGD = true;
+    static final boolean RILJ_LOGV = false; // STOP SHIP if true
 
     /**
      * Wake lock timeout should be longer than the longest timeout in
@@ -2069,7 +2068,7 @@
                 if (RILJ_LOGD) Log.d(LOG_TAG, "Radio ON @ init; reset to OFF");
                 setRadioPower(false, null);
             } else {
-                if (DBG) Log.d(LOG_TAG, "Radio OFF @ init");
+                if (RILJ_LOGD) Log.d(LOG_TAG, "Radio OFF @ init");
                 setRadioState(newState);
                 setPreferredNetworkType(mNetworkMode, null);
             }
@@ -2366,7 +2365,10 @@
             case RIL_REQUEST_GET_IMSI:
             case RIL_REQUEST_GET_IMEI:
             case RIL_REQUEST_GET_IMEISV:
-                return "";
+                if (!RILJ_LOGV) {
+                    // If not versbose logging just return and don't display IMSI and IMEI, IMEISV
+                    return "";
+                }
         }
 
         StringBuilder sb;
diff --git a/telephony/java/com/android/internal/telephony/cat/CatService.java b/telephony/java/com/android/internal/telephony/cat/CatService.java
index 36059ad..a6c7777 100644
--- a/telephony/java/com/android/internal/telephony/cat/CatService.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatService.java
@@ -375,25 +375,30 @@
 
     private void encodeOptionalTags(CommandDetails cmdDet,
             ResultCode resultCode, Input cmdInput, ByteArrayOutputStream buf) {
-        switch (AppInterface.CommandType.fromInt(cmdDet.typeOfCommand)) {
-            case GET_INKEY:
-                // ETSI TS 102 384,27.22.4.2.8.4.2.
-                // If it is a response for GET_INKEY command and the response timeout
-                // occured, then add DURATION TLV for variable timeout case.
-                if ((resultCode.value() == ResultCode.NO_RESPONSE_FROM_USER.value()) &&
-                    (cmdInput != null) && (cmdInput.duration != null)) {
-                    getInKeyResponse(buf, cmdInput);
-                }
-                break;
-            case PROVIDE_LOCAL_INFORMATION:
-                if ((cmdDet.commandQualifier == CommandParamsFactory.LANGUAGE_SETTING) &&
-                    (resultCode.value() == ResultCode.OK.value())) {
-                    getPliResponse(buf);
-                }
-                break;
-            default:
-                CatLog.d(this, "encodeOptionalTags() Unsupported Cmd:" + cmdDet.typeOfCommand);
-                break;
+        CommandType cmdType = AppInterface.CommandType.fromInt(cmdDet.typeOfCommand);
+        if (cmdType != null) {
+            switch (cmdType) {
+                case GET_INKEY:
+                    // ETSI TS 102 384,27.22.4.2.8.4.2.
+                    // If it is a response for GET_INKEY command and the response timeout
+                    // occured, then add DURATION TLV for variable timeout case.
+                    if ((resultCode.value() == ResultCode.NO_RESPONSE_FROM_USER.value()) &&
+                        (cmdInput != null) && (cmdInput.duration != null)) {
+                        getInKeyResponse(buf, cmdInput);
+                    }
+                    break;
+                case PROVIDE_LOCAL_INFORMATION:
+                    if ((cmdDet.commandQualifier == CommandParamsFactory.LANGUAGE_SETTING) &&
+                        (resultCode.value() == ResultCode.OK.value())) {
+                        getPliResponse(buf);
+                    }
+                    break;
+                default:
+                    CatLog.d(this, "encodeOptionalTags() Unsupported Cmd:" + cmdDet.typeOfCommand);
+                    break;
+            }
+        } else {
+            CatLog.d(this, "encodeOptionalTags() bad Cmd:" + cmdDet.typeOfCommand);
         }
     }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index 4f27e7f..cccc053 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -67,6 +67,7 @@
     protected void onConnect(ConnectionParams cp) {
         if (DBG) log("CdmaDataConnection Connecting...");
 
+        mApn = cp.apn;
         createTime = -1;
         lastFailTime = -1;
         lastFailCause = FailCause.NONE;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 345d0d9..b244945 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -508,7 +508,7 @@
         notifyDataAvailability(null);
     }
 
-    private void gotoIdleAndNotifyDataConnection(String reason) {
+    protected void gotoIdleAndNotifyDataConnection(String reason) {
         if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason);
         setState(State.IDLE);
         notifyDataConnection(reason);
@@ -668,20 +668,6 @@
     }
 
     /**
-     * Called when EVENT_RESET_DONE is received so goto
-     * IDLE state and send notifications to those interested.
-     */
-    @Override
-    protected void onResetDone(AsyncResult ar) {
-      if (DBG) log("EVENT_RESET_DONE");
-      String reason = null;
-      if (ar.userObj instanceof String) {
-          reason = (String) ar.userObj;
-      }
-      gotoIdleAndNotifyDataConnection(reason);
-    }
-
-    /**
      * @override com.android.internal.telephony.DataConnectionTracker
      */
     @Override
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index 344486a..b0b2ac5 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -36,8 +36,6 @@
     private static final String LOG_TAG = "GSM";
 
     //***** Instance Variables
-    private ApnSetting apn;
-
     protected int mProfileId = RILConstants.DATA_PROFILE_DEFAULT;
     protected String mActiveApnType = Phone.APN_TYPE_DEFAULT;
     //***** Constructor
@@ -74,13 +72,13 @@
     @Override
     protected
     void onConnect(ConnectionParams cp) {
-        apn = cp.apn;
+        mApn = cp.apn;
 
-        if (DBG) log("Connecting to carrier: '" + apn.carrier
-                + "' APN: '" + apn.apn
-                + "' proxy: '" + apn.proxy + "' port: '" + apn.port);
+        if (DBG) log("Connecting to carrier: '" + mApn.carrier
+                + "' APN: '" + mApn.apn
+                + "' proxy: '" + mApn.proxy + "' port: '" + mApn.port);
 
-        setHttpProxy (apn.proxy, apn.port);
+        setHttpProxy (mApn.proxy, mApn.port);
 
         createTime = -1;
         lastFailTime = -1;
@@ -90,23 +88,23 @@
         Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
         msg.obj = cp;
 
-        int authType = apn.authType;
+        int authType = mApn.authType;
         if (authType == -1) {
-            authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
+            authType = (mApn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
                 RILConstants.SETUP_DATA_AUTH_NONE;
         }
 
         String protocol;
         if (phone.getServiceState().getRoaming()) {
-            protocol = apn.roamingProtocol;
+            protocol = mApn.roamingProtocol;
         } else {
-            protocol = apn.protocol;
+            protocol = mApn.protocol;
         }
 
         phone.mCM.setupDataCall(
                 Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),
                 Integer.toString(mProfileId),
-                apn.apn, apn.user, apn.password,
+                mApn.apn, mApn.user, mApn.password,
                 Integer.toString(authType),
                 protocol, msg);
     }
@@ -129,14 +127,8 @@
     }
 
     @Override
-    protected void clearSettings() {
-        super.clearSettings();
-        apn = null;
-    }
-
-    @Override
     public String toString() {
-        return "State=" + getCurrentState().getName() + " Apn=" + apn +
+        return "State=" + getCurrentState().getName() + " Apn=" + mApn +
                " create=" + createTime + " lastFail=" + lastFailTime +
                " lastFailCause=" + lastFailCause;
     }
@@ -150,11 +142,12 @@
             // Do not apply the race condition workaround for MMS APN
             // if Proxy is an IP-address.
             // Otherwise, the default APN will not be restored anymore.
-            if (!apn.types[0].equals(Phone.APN_TYPE_MMS)
-                || !isIpAddress(apn.mmsProxy)) {
+            if (!mApn.types[0].equals(Phone.APN_TYPE_MMS)
+                || !isIpAddress(mApn.mmsProxy)) {
                 log(String.format(
                         "isDnsOk: return false apn.types[0]=%s APN_TYPE_MMS=%s isIpAddress(%s)=%s",
-                        apn.types[0], Phone.APN_TYPE_MMS, apn.mmsProxy, isIpAddress(apn.mmsProxy)));
+                        mApn.types[0], Phone.APN_TYPE_MMS, mApn.mmsProxy,
+                        isIpAddress(mApn.mmsProxy)));
                 return false;
             }
         }
@@ -166,15 +159,11 @@
         Log.d(LOG_TAG, "[" + getName() + "] " + s);
     }
 
-    public ApnSetting getApn() {
-        return this.apn;
-    }
-
     private void setHttpProxy(String httpProxy, String httpPort) {
 
         if (DBG) log("set http proxy for"
                 + "' APN: '" + mActiveApnType
-                + "' proxy: '" + apn.proxy + "' port: '" + apn.port);
+                + "' proxy: '" + mApn.proxy + "' port: '" + mApn.port);
         if(TextUtils.equals(mActiveApnType, Phone.APN_TYPE_DEFAULT)) {
             if (httpProxy == null || httpProxy.length() == 0) {
                 phone.setSystemProperty("net.gprs.http-proxy", null);
@@ -205,6 +194,6 @@
     private boolean isIpAddress(String address) {
         if (address == null) return false;
 
-        return Patterns.IP_ADDRESS.matcher(apn.mmsProxy).matches();
+        return Patterns.IP_ADDRESS.matcher(address).matches();
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 0f62907..d602c38 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -757,20 +757,19 @@
             return;
         }
 
-        GsmDataConnection pdp = apnContext.getDataConnection();
-        if (tearDown && pdp!=null) {
+        GsmDataConnection conn = apnContext.getDataConnection();
+        if (conn != null) {
             apnContext.setState(State.DISCONNECTING);
-            Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
-            pdp.disconnect(msg);
-            return;
-        } else if (pdp != null) {
-            pdp.clearSettings();
+            if (tearDown ) {
+                Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
+                conn.disconnect(msg);
+            } else {
+                conn.resetSynchronously();
+                apnContext.setState(State.IDLE);
+                mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+            }
         }
 
-        if (!tearDown) {
-            apnContext.setState(State.IDLE);
-            mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
-        }
         if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
            mApnContexts.remove(apnContext.getApnType());
         }
@@ -1036,7 +1035,7 @@
     }
 
     // TODO: For multiple Active APNs not exactly sure how to do this.
-    private void gotoIdleAndNotifyDataConnection(String reason) {
+    protected void gotoIdleAndNotifyDataConnection(String reason) {
         if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason);
         notifyDataConnection(reason);
         mActiveApn = null;
@@ -1528,19 +1527,6 @@
         }
     }
 
-    /**
-     * Called when EVENT_RESET_DONE is received.
-     */
-    @Override
-    protected void onResetDone(AsyncResult ar) {
-        if (DBG) log("EVENT_RESET_DONE");
-        String reason = null;
-        if (ar.userObj instanceof String) {
-            reason = (String) ar.userObj;
-        }
-        gotoIdleAndNotifyDataConnection(reason);
-    }
-
     protected void onPollPdp() {
         if (getOverallState() == State.CONNECTED) {
             // only poll when connected
diff --git a/tests/BiDiTests/Android.mk b/tests/BiDiTests/Android.mk
new file mode 100644
index 0000000..ae29fc2
--- /dev/null
+++ b/tests/BiDiTests/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := BiDiTests
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/tests/BiDiTests/AndroidManifest.xml b/tests/BiDiTests/AndroidManifest.xml
new file mode 100644
index 0000000..346ace8
--- /dev/null
+++ b/tests/BiDiTests/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Declare the contents of this Android application.  The namespace
+     attribute brings in the Android platform namespace, and the package
+     supplies a unique name for the application.  When writing your
+     own application, the package name must be changed from "com.example.*"
+     to come from a domain that you own or have control over. -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.bidi"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <application android:label="BiDiTests">
+        <activity android:name="BiDiTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/tests/BiDiTests/proguard.flags b/tests/BiDiTests/proguard.flags
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/BiDiTests/proguard.flags
diff --git a/tests/BiDiTests/res/layout/biditest_main.xml b/tests/BiDiTests/res/layout/biditest_main.xml
new file mode 100644
index 0000000..9f77ad2
--- /dev/null
+++ b/tests/BiDiTests/res/layout/biditest_main.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+       <Button android:id="@+id/button"
+               android:layout_height="wrap_content"
+               android:layout_width="wrap_content"
+               android:onClick="onButtonClick"
+               android:text="@string/button_text"
+               android:textSize="32dip"
+        />
+
+        <TextView android:id="@+id/textview"
+                  android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="32dip"
+                  android:text="@string/textview_text"
+        />
+
+        <EditText android:id="@+id/textview"
+                  android:layout_height="wrap_content"
+                  android:layout_width="match_parent"
+                  android:textSize="32dip"
+                  android:text="@string/edittext_text"
+        />
+
+    </LinearLayout>
+
+    <view class="com.android.bidi.BiDiTestView"
+        android:id="@+id/main"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="#FF0000"
+    />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
new file mode 100644
index 0000000..ecff76e
--- /dev/null
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -0,0 +1,26 @@
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <string name="button_text">Button</string>
+    <string name="textview_text">This is a text for a TextView</string>
+    <string name="edittext_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
+    <string name="normal_text">Normal String</string>
+    <string name="normal_long_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
+    <string name="arabic_text">&#x0644;&#x0627;</string>
+    <string name="chinese_text">利比亚局势或影响美俄关系发展</string>
+    <string name="italic_text">Italic String</string>
+    <string name="bold_text">Bold String</string>
+    <string name="bold_italic_text">Bold Italic String</string>
+</resources>
\ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
new file mode 100644
index 0000000..3d7dd81
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+
+public class BiDiTestActivity extends Activity {
+
+    static final String TAG = "BiDiTestActivity";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.biditest_main);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    public void onButtonClick(View v) {
+        Log.v(TAG, "onButtonClick");
+    }
+}
\ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
new file mode 100644
index 0000000..e9b6fa6
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+public class BiDiTestView extends View {
+
+    private static final String TAG = "BiDiTestView";
+
+    private static final int BORDER_PADDING = 4;
+    private static final int TEXT_PADDING = 16;
+    private static final int TEXT_SIZE = 32;
+    private static final int ORIGIN = 48;
+    private static final int DELTA_Y = TEXT_SIZE;
+
+    private static final float DEFAULT_ITALIC_SKEW_X = -0.25f;
+
+    private Paint paint = new Paint();
+    private Rect rect = new Rect();
+
+    private String NORMAL_TEXT;
+    private String NORMAL_LONG_TEXT;
+    private String ITALIC_TEXT;
+    private String BOLD_TEXT;
+    private String BOLD_ITALIC_TEXT;
+    private String ARABIC_TEXT;
+    private String CHINESE_TEXT;
+
+    private Typeface typeface;
+
+    public BiDiTestView(Context context) {
+        super(context);
+        init(context);
+    }
+
+    public BiDiTestView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    public BiDiTestView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init(context);
+    }
+
+    private void init(Context context) {
+        NORMAL_TEXT = context.getString(R.string.normal_text);
+        NORMAL_LONG_TEXT = context.getString(R.string.normal_long_text);
+        ITALIC_TEXT = context.getString(R.string.italic_text);
+        BOLD_TEXT = context.getString(R.string.bold_text);
+        BOLD_ITALIC_TEXT = context.getString(R.string.bold_italic_text);
+        ARABIC_TEXT = context.getString(R.string.arabic_text);
+        CHINESE_TEXT = context.getString(R.string.chinese_text);
+
+        typeface = paint.getTypeface();
+        paint.setAntiAlias(true);
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        drawInsideRect(canvas, Color.BLACK);
+
+        int deltaX = testString(canvas, NORMAL_TEXT, ORIGIN, ORIGIN, paint, typeface,
+                false, false,  Paint.DIRECTION_LTR);
+        deltaX += testString(canvas, ITALIC_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface,
+                true, false,  Paint.DIRECTION_LTR);
+        deltaX += testString(canvas, BOLD_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface,
+                false, true,  Paint.DIRECTION_LTR);
+        deltaX += testString(canvas, BOLD_ITALIC_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface,
+                true, true,  Paint.DIRECTION_LTR);
+
+        // Test with a long string
+        deltaX = testString(canvas, NORMAL_LONG_TEXT, ORIGIN, ORIGIN + 2 * DELTA_Y, paint, typeface,
+                false, false,  Paint.DIRECTION_LTR);
+
+        // Test Arabic ligature
+        deltaX = testString(canvas, ARABIC_TEXT, ORIGIN, ORIGIN + 4 * DELTA_Y, paint, typeface,
+                false, false,  Paint.DIRECTION_RTL);
+
+        // Test Chinese
+        deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 6 * DELTA_Y, paint, typeface,
+                false, false,  Paint.DIRECTION_LTR);
+    }
+
+    private int testString(Canvas canvas, String text, int x, int y, Paint paint, Typeface typeface,
+            boolean isItalic, boolean isBold, int dir) {
+        paint.setTypeface(typeface);
+
+        // Set paint properties
+        boolean oldFakeBold = paint.isFakeBoldText();
+        paint.setFakeBoldText(isBold);
+
+        float oldTextSkewX = paint.getTextSkewX();
+        if (isItalic) {
+            paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X);
+        }
+
+        drawTextWithCanvasDrawText(text, canvas, x, y, TEXT_SIZE, Color.WHITE);
+
+        int length = text.length();
+        float[] advances = new float[length];
+        float textWidth = paint.getTextRunAdvances(text, 0, length, 0, length, 0, advances, 0);
+
+        logAdvances(text, textWidth, advances);
+        drawBoxAroundText(canvas, x, y, textWidth, TEXT_SIZE, Color.RED);
+
+        paint.setColor(Color.WHITE);
+        char[] glyphs = new char[2*length];
+        int count = getGlyphs(text, glyphs, dir);
+
+        logGlypths(glyphs, count);
+        drawTextWithDrawGlyph(canvas, glyphs, count, x, y + DELTA_Y);
+
+        // Restore old paint properties
+        paint.setFakeBoldText(oldFakeBold);
+        paint.setTextSkewX(oldTextSkewX);
+
+        return (int) Math.ceil(textWidth) + TEXT_PADDING;
+    }
+
+    private void drawTextWithDrawGlyph(Canvas canvas, char[] glyphs, int count, int x, int y) {
+        canvas.drawGlyphs(glyphs, 0, count, x, y, paint);
+    }
+
+    private void logGlypths(char[] glyphs, int count) {
+        Log.v(TAG, "GlyphIds - count=" + count);
+        for (int n = 0; n < count; n++) {
+            Log.v(TAG, "GlyphIds - Id[" + n + "]="+ (int)glyphs[n]);
+        }
+    }
+
+    private int getGlyphs(String text, char[] glyphs, int dir) {
+//        int dir = 1; // Paint.DIRECTION_LTR;
+        return paint.getTextGlypths(text, 0, text.length(), 0, text.length(), dir, glyphs);
+    }
+
+    private void drawInsideRect(Canvas canvas, int color) {
+        paint.setColor(color);
+        int width = getWidth();
+        int height = getHeight();
+        rect.set(BORDER_PADDING, BORDER_PADDING, width - BORDER_PADDING, height - BORDER_PADDING);
+        canvas.drawRect(rect, paint);
+    }
+
+    private void drawTextWithCanvasDrawText(String text, Canvas canvas,
+            float x, float y, float textSize, int color) {
+        paint.setColor(color);
+        paint.setTextSize(textSize);
+        canvas.drawText(text, x, y, paint);
+    }
+
+    private void drawBoxAroundText(Canvas canvas, int x, int y, float textWidth, int textSize,
+            int color) {
+        paint.setColor(color);
+        canvas.drawLine(x, y - textSize, x, y + 8, paint);
+        canvas.drawLine(x, y + 8, x + textWidth, y + 8, paint);
+        canvas.drawLine(x + textWidth, y - textSize, x + textWidth, y + 8, paint);
+    }
+
+    private void logAdvances(String text, float textWidth, float[] advances) {
+        Log.v(TAG, "Advances for text: " + text + " total=" + textWidth);
+        int length = advances.length;
+        for(int n=0; n<length; n++){
+            Log.v(TAG, "adv[" + n + "]=" + advances[n]);
+        }
+    }
+}