Merge "Removing unused INITING state."
diff --git a/api/current.txt b/api/current.txt
index e6e0560..f06d99f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2684,6 +2684,7 @@
     method public final boolean isChild();
     method public boolean isDestroyed();
     method public boolean isFinishing();
+    method public boolean isImmersive();
     method public boolean isTaskRoot();
     method public final deprecated android.database.Cursor managedQuery(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
     method public boolean moveTaskToBack(boolean);
@@ -2771,6 +2772,7 @@
     method public final void setFeatureDrawableResource(int, int);
     method public final void setFeatureDrawableUri(int, android.net.Uri);
     method public void setFinishOnTouchOutside(boolean);
+    method public void setImmersive(boolean);
     method public void setIntent(android.content.Intent);
     method public final void setProgress(int);
     method public final void setProgressBarIndeterminate(boolean);
@@ -6331,6 +6333,7 @@
     field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100
     field public static final int FLAG_FINISH_ON_TASK_LAUNCH = 2; // 0x2
     field public static final int FLAG_HARDWARE_ACCELERATED = 512; // 0x200
+    field public static final int FLAG_IMMERSIVE = 2048; // 0x800
     field public static final int FLAG_MULTIPROCESS = 1; // 0x1
     field public static final int FLAG_NO_HISTORY = 128; // 0x80
     field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
@@ -12554,7 +12557,7 @@
     method public int stopUsingNetworkFeature(int, java.lang.String);
     field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
     field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
-    field public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
+    field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
     field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
     field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover";
     field public static final deprecated java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
@@ -13560,6 +13563,7 @@
     ctor public WifiP2pDeviceList();
     ctor public WifiP2pDeviceList(android.net.wifi.p2p.WifiP2pDeviceList);
     method public int describeContents();
+    method public android.net.wifi.p2p.WifiP2pDevice get(java.lang.String);
     method public java.util.Collection<android.net.wifi.p2p.WifiP2pDevice> getDeviceList();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
@@ -13615,7 +13619,9 @@
     field public static final int ERROR = 0; // 0x0
     field public static final java.lang.String EXTRA_DISCOVERY_STATE = "discoveryState";
     field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
+    field public static final java.lang.String EXTRA_P2P_DEVICE_LIST = "wifiP2pDeviceList";
     field public static final java.lang.String EXTRA_WIFI_P2P_DEVICE = "wifiP2pDevice";
+    field public static final java.lang.String EXTRA_WIFI_P2P_GROUP = "p2pGroupInfo";
     field public static final java.lang.String EXTRA_WIFI_P2P_INFO = "wifiP2pInfo";
     field public static final java.lang.String EXTRA_WIFI_STATE = "wifi_p2p_state";
     field public static final int NO_SERVICE_REQUESTS = 3; // 0x3
@@ -41391,8 +41397,8 @@
 
   public class ZipFile {
     ctor public ZipFile(java.io.File) throws java.io.IOException, java.util.zip.ZipException;
-    ctor public ZipFile(java.io.File, int) throws java.io.IOException;
     ctor public ZipFile(java.lang.String) throws java.io.IOException;
+    ctor public ZipFile(java.io.File, int) throws java.io.IOException;
     method public void close() throws java.io.IOException;
     method public java.util.Enumeration<? extends java.util.zip.ZipEntry> entries();
     method public java.util.zip.ZipEntry getEntry(java.lang.String);
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index ecf3b19..7efe189 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -557,7 +557,7 @@
         public IAccessibilityServiceClientWrapper(Context context, Looper looper,
                 Callbacks callback) {
             mCallback = callback;
-            mCaller = new HandlerCaller(context, looper, this);
+            mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/);
         }
 
         public void setConnection(IAccessibilityServiceConnection connection, int connectionId) {
diff --git a/core/java/android/accounts/AccountAuthenticatorResponse.java b/core/java/android/accounts/AccountAuthenticatorResponse.java
index 614e139..41f26ac 100644
--- a/core/java/android/accounts/AccountAuthenticatorResponse.java
+++ b/core/java/android/accounts/AccountAuthenticatorResponse.java
@@ -33,7 +33,7 @@
     /**
      * @hide
      */
-    /* package private */ AccountAuthenticatorResponse(IAccountAuthenticatorResponse response) {
+    public AccountAuthenticatorResponse(IAccountAuthenticatorResponse response) {
         mAccountAuthenticatorResponse = response;
     }
 
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 5dc9da2..cbeffc1 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2544,7 +2544,7 @@
                 // Put event logging here so it gets called even if subclass
                 // doesn't call through to superclass's implmeentation of each
                 // of these methods below
-                EventLog.writeEvent(50000, 0, item.getTitleCondensed());
+                EventLog.writeEvent(50000, 0, item.getTitleCondensed().toString());
                 if (onOptionsItemSelected(item)) {
                     return true;
                 }
@@ -2562,7 +2562,7 @@
                 return false;
                 
             case Window.FEATURE_CONTEXT_MENU:
-                EventLog.writeEvent(50000, 1, item.getTitleCondensed());
+                EventLog.writeEvent(50000, 1, item.getTitleCondensed().toString());
                 if (onContextItemSelected(item)) {
                     return true;
                 }
@@ -4818,8 +4818,8 @@
      * <code>android:immersive</code> but may be changed at runtime by
      * {@link #setImmersive}.
      *
+     * @see #setImmersive(boolean)
      * @see android.content.pm.ActivityInfo#FLAG_IMMERSIVE
-     * @hide
      */
     public boolean isImmersive() {
         try {
@@ -4831,7 +4831,7 @@
 
     /**
      * Adjust the current immersive mode setting.
-     * 
+     *
      * Note that changing this value will have no effect on the activity's
      * {@link android.content.pm.ActivityInfo} structure; that is, if
      * <code>android:immersive</code> is set to <code>true</code>
@@ -4840,9 +4840,8 @@
      * always have its {@link android.content.pm.ActivityInfo#FLAG_IMMERSIVE
      * FLAG_IMMERSIVE} bit set.
      *
-     * @see #isImmersive
+     * @see #isImmersive()
      * @see android.content.pm.ActivityInfo#FLAG_IMMERSIVE
-     * @hide
      */
     public void setImmersive(boolean i) {
         try {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8f8df0a..3f8e16c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -322,7 +322,7 @@
     /**
      * Bit to be bitwise-ored into the {@link #flags} field that should be
      * set if the notification should be canceled when it is clicked by the
-     * user.  On tablets, the
+     * user.
 
      */
     public static final int FLAG_AUTO_CANCEL        = 0x00000010;
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index b20cf88..e34c827 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -116,6 +116,10 @@
      */
     public static final String SYNC_EXTRAS_INITIALIZE = "initialize";
 
+    /** @hide */
+    public static final Intent ACTION_SYNC_CONN_STATUS_CHANGED =
+            new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
+
     public static final String SCHEME_CONTENT = "content";
     public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
     public static final String SCHEME_FILE = "file";
@@ -181,7 +185,7 @@
     };
 
     /** @hide */
-    static String syncErrorToString(int error) {
+    public static String syncErrorToString(int error) {
         if (error < 1 || error > SYNC_ERROR_NAMES.length) {
             return String.valueOf(error);
         }
diff --git a/core/java/android/content/PeriodicSync.java b/core/java/android/content/PeriodicSync.java
index 17813ec..513a556 100644
--- a/core/java/android/content/PeriodicSync.java
+++ b/core/java/android/content/PeriodicSync.java
@@ -79,6 +79,25 @@
         return account.equals(other.account)
                 && authority.equals(other.authority)
                 && period == other.period
-                && SyncStorageEngine.equals(extras, other.extras);
+                && syncExtrasEquals(extras, other.extras);
+    }
+
+    /** {@hide} */
+    public static boolean syncExtrasEquals(Bundle b1, Bundle b2) {
+        if (b1.size() != b2.size()) {
+            return false;
+        }
+        if (b1.isEmpty()) {
+            return true;
+        }
+        for (String key : b1.keySet()) {
+            if (!b2.containsKey(key)) {
+                return false;
+            }
+            if (!b1.get(key).equals(b2.get(key))) {
+                return false;
+            }
+        }
+        return true;
     }
 }
diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java
index 7b643a0..8bb3ee7 100644
--- a/core/java/android/content/SyncAdaptersCache.java
+++ b/core/java/android/content/SyncAdaptersCache.java
@@ -31,7 +31,7 @@
  * A cache of services that export the {@link android.content.ISyncAdapter} interface.
  * @hide
  */
-/* package private */ class SyncAdaptersCache extends RegisteredServicesCache<SyncAdapterType> {
+public class SyncAdaptersCache extends RegisteredServicesCache<SyncAdapterType> {
     private static final String TAG = "Account";
 
     private static final String SERVICE_INTERFACE = "android.content.SyncAdapter";
@@ -39,7 +39,7 @@
     private static final String ATTRIBUTES_NAME = "sync-adapter";
     private static final MySerializer sSerializer = new MySerializer();
 
-    SyncAdaptersCache(Context context) {
+    public SyncAdaptersCache(Context context) {
         super(context, SERVICE_INTERFACE, SERVICE_META_DATA, ATTRIBUTES_NAME, sSerializer);
     }
 
diff --git a/core/java/android/content/SyncInfo.java b/core/java/android/content/SyncInfo.java
index abfe964..0284882 100644
--- a/core/java/android/content/SyncInfo.java
+++ b/core/java/android/content/SyncInfo.java
@@ -46,7 +46,7 @@
     public final long startTime;
 
     /** @hide */
-    SyncInfo(int authorityId, Account account, String authority,
+    public SyncInfo(int authorityId, Account account, String authority,
             long startTime) {
         this.authorityId = authorityId;
         this.account = account;
diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java
index bb2b2da..49e3e35 100644
--- a/core/java/android/content/SyncStatusInfo.java
+++ b/core/java/android/content/SyncStatusInfo.java
@@ -46,7 +46,7 @@
 
     private static final String TAG = "Sync";
 
-    SyncStatusInfo(int authorityId) {
+    public SyncStatusInfo(int authorityId) {
         this.authorityId = authorityId;
     }
 
@@ -92,7 +92,7 @@
         }
     }
 
-    SyncStatusInfo(Parcel parcel) {
+    public SyncStatusInfo(Parcel parcel) {
         int version = parcel.readInt();
         if (version != VERSION && version != 1) {
             Log.w("SyncStatusInfo", "Unknown version: " + version);
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index e2ca1dd..8f3b62d 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -161,7 +161,6 @@
      */
     public static final int FLAG_SHOW_ON_LOCK_SCREEN = 0x0400;
     /**
-     * @hide
      * Bit in {@link #flags} corresponding to an immersive activity
      * that wishes not to be interrupted by notifications.
      * Applications that hide the system notification bar with
@@ -174,7 +173,14 @@
      * {@link #FLAG_IMMERSIVE} set, however, will not be interrupted; the
      * notification may be shown in some other way (such as a small floating
      * "toast" window).
-     * {@see android.app.Notification#FLAG_HIGH_PRIORITY}
+     *
+     * Note that this flag will always reflect the Activity's
+     * <code>android:immersive</code> manifest definition, even if the Activity's
+     * immersive state is changed at runtime via
+     * {@link android.app.Activity#setImmersive(boolean)}.
+     *
+     * @see android.app.Notification#FLAG_HIGH_PRIORITY
+     * @see android.app.Activity#setImmersive(boolean)
      */
     public static final int FLAG_IMMERSIVE = 0x0800;
     /**
diff --git a/core/java/android/hardware/SerialPort.java b/core/java/android/hardware/SerialPort.java
index 5ef122b..f50cdef 100644
--- a/core/java/android/hardware/SerialPort.java
+++ b/core/java/android/hardware/SerialPort.java
@@ -82,7 +82,9 @@
     }
 
     /**
-     * Reads data into the provided buffer
+     * Reads data into the provided buffer.
+     * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
+     * unchanged after a call to this method.
      *
      * @param buffer to read into
      * @return number of bytes read
@@ -98,7 +100,9 @@
     }
 
     /**
-     * Writes data from provided buffer
+     * Writes data from provided buffer.
+     * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
+     * unchanged after a call to this method.
      *
      * @param buffer to write
      * @param length number of bytes to write
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index 5324f81..d78262b 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -70,7 +70,8 @@
     
     public IInputMethodSessionWrapper(Context context,
             InputMethodSession inputMethodSession) {
-        mCaller = new HandlerCaller(context, this);
+        mCaller = new HandlerCaller(context, null,
+                this, true /*asyncHandler*/);
         mInputMethodSession = inputMethodSession;
     }
 
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 5275314..2d67875 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -102,7 +102,8 @@
     public IInputMethodWrapper(AbstractInputMethodService context,
             InputMethod inputMethod) {
         mTarget = new WeakReference<AbstractInputMethodService>(context);
-        mCaller = new HandlerCaller(context.getApplicationContext(), this);
+        mCaller = new HandlerCaller(context.getApplicationContext(), null,
+                this, true /*asyncHandler*/);
         mInputMethod = new WeakReference<InputMethod>(inputMethod);
         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
     }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 6ff1a33..a8a68d0 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -328,6 +328,18 @@
     /** {@hide} */
     public static final int MAX_NETWORK_TYPE = TYPE_WIFI_P2P;
 
+    /**
+     * If you want to set the default network preference,you can directly
+     * change the networkAttributes array in framework's config.xml.
+     *
+     * @deprecated Since we support so many more networks now, the single
+     *             network default network preference can't really express
+     *             the heirarchy.  Instead, the default is defined by the
+     *             networkAttributes in config.xml.  You can determine
+     *             the current value by calling {@link #getNetworkPreference()}
+     *             from an App.
+     */
+    @Deprecated
     public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
 
     /**
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index 5b98b8f..8947162 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -74,7 +74,7 @@
         }
 
         public void interfaceLinkStateChanged(String iface, boolean up) {
-            if (mIface.equals(iface) && mLinkUp != up) {
+            if (mIface.equals(iface)) {
                 Log.d(TAG, "Interface " + iface + " link " + (up ? "up" : "down"));
                 mLinkUp = up;
                 mTracker.mNetworkInfo.setIsAvailable(up);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index dc089bd..4dbc4b4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4296,6 +4296,13 @@
         public static final String POWER_SOUNDS_ENABLED = "power_sounds_enabled";
 
         /**
+         * URI for the "wireless charging started" sound.
+         * @hide
+         */
+        public static final String WIRELESS_CHARGING_STARTED_SOUND =
+                "wireless_charging_started_sound";
+
+        /**
          * Whether we keep the device on while the device is plugged in.
          * Supported values are:
          * <ul>
diff --git a/core/java/android/server/package.html b/core/java/android/server/package.html
deleted file mode 100644
index c9f96a6..0000000
--- a/core/java/android/server/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<body>
-
-{@hide}
-
-</body>
diff --git a/core/java/android/server/search/package.html b/core/java/android/server/search/package.html
deleted file mode 100644
index c9f96a6..0000000
--- a/core/java/android/server/search/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<body>
-
-{@hide}
-
-</body>
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 500bb2c..9dc77b9 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -960,7 +960,7 @@
         IWallpaperEngineWrapper(WallpaperService context,
                 IWallpaperConnection conn, IBinder windowToken,
                 int windowType, boolean isPreview, int reqWidth, int reqHeight) {
-            mCaller = new HandlerCaller(context, context.getMainLooper(), this);
+            mCaller = new HandlerCaller(context, context.getMainLooper(), this, true);
             mConnection = conn;
             mWindowToken = windowToken;
             mWindowType = windowType;
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 0f175db..157c321 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -1325,17 +1325,11 @@
                 }
             }
 
-            if ((status & DisplayList.STATUS_INVOKE) != 0) {
-                scheduleFunctors(attachInfo, true);
-            }
-        }
-
-        private void scheduleFunctors(View.AttachInfo attachInfo, boolean delayed) {
-            mFunctorsRunnable.attachInfo = attachInfo;
-            if (!attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
-                // delay the functor callback by a few ms so it isn't polled constantly
-                attachInfo.mHandler.postDelayed(mFunctorsRunnable,
-                                                delayed ? FUNCTOR_PROCESS_DELAY : 0);
+            if ((status & DisplayList.STATUS_INVOKE) != 0 ||
+                    attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
+                attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
+                mFunctorsRunnable.attachInfo = attachInfo;
+                attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
             }
         }
 
@@ -1350,7 +1344,9 @@
         boolean attachFunctor(View.AttachInfo attachInfo, int functor) {
             if (mCanvas != null) {
                 mCanvas.attachFunctor(functor);
-                scheduleFunctors(attachInfo, false);
+                mFunctorsRunnable.attachInfo = attachInfo;
+                attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
+                attachInfo.mHandler.postDelayed(mFunctorsRunnable,  0);
                 return true;
             }
             return false;
diff --git a/core/java/android/view/SimulatedTrackball.java b/core/java/android/view/SimulatedTrackball.java
index b917371..0eb197e 100644
--- a/core/java/android/view/SimulatedTrackball.java
+++ b/core/java/android/view/SimulatedTrackball.java
@@ -40,7 +40,7 @@
     private static final int MAX_TAP_TIME = 250;
     // Where the cutoff is for determining an edge swipe
     private static final float EDGE_SWIPE_THRESHOLD = 0.9f;
-    private static final int FLICK_MSG_ID = 313;
+    private static final int MSG_FLICK = 313;
     // TODO: Pass touch slop from the input device
     private static final int TOUCH_SLOP = 30;
 
@@ -75,8 +75,11 @@
     // Has the TouchSlop constraint been invalidated
     private boolean mAlwaysInTapRegion = true;
 
-    // Most recent event. Used to determine what device sent the event.
-    private MotionEvent mRecentEvent;
+    // Information from the most recent event.
+    // Used to determine what device sent the event during a fling.
+    private int mLastSource;
+    private int mLastMetaState;
+    private int mLastDeviceId;
 
     // TODO: Currently using screen dimensions tuned to a Galaxy Nexus, need to
     // read this from a config file instead
@@ -101,33 +104,34 @@
         mTouchSlopSquared = mTouchSlop * mTouchSlop;
     }
 
-    private final Handler mHandler = new Handler(new Callback() {
+    private final Handler mHandler = new Handler(true /*async*/) {
             @Override
-        public boolean handleMessage(Message msg) {
-            if (msg.what != FLICK_MSG_ID)
-                return false;
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_FLICK: {
+                    final long time = SystemClock.uptimeMillis();
+                    ViewRootImpl viewroot = (ViewRootImpl) msg.obj;
+                    // Send the key
+                    viewroot.enqueueInputEvent(new KeyEvent(time, time,
+                            KeyEvent.ACTION_DOWN, msg.arg2, 0, mLastMetaState,
+                            mLastDeviceId, 0, KeyEvent.FLAG_FALLBACK, mLastSource));
+                    viewroot.enqueueInputEvent(new KeyEvent(time, time,
+                            KeyEvent.ACTION_UP, msg.arg2, 0, mLastMetaState,
+                            mLastDeviceId, 0, KeyEvent.FLAG_FALLBACK, mLastSource));
 
-            final long time = SystemClock.uptimeMillis();
-            ViewRootImpl viewroot = (ViewRootImpl) msg.obj;
-            // Send the key
-            viewroot.enqueueInputEvent(new KeyEvent(time, time,
-                    KeyEvent.ACTION_DOWN, msg.arg2, 0, mRecentEvent.getMetaState(),
-                    mRecentEvent.getDeviceId(), 0,
-                    KeyEvent.FLAG_FALLBACK, mRecentEvent.getSource()));
-            viewroot.enqueueInputEvent(new KeyEvent(time, time,
-                    KeyEvent.ACTION_UP, msg.arg2, 0, mRecentEvent.getMetaState(),
-                    mRecentEvent.getDeviceId(), 0,
-                    KeyEvent.FLAG_FALLBACK, mRecentEvent.getSource()));
-            Message msgCopy = Message.obtain(msg);
-            // Increase the delay by the decay factor
-            msgCopy.arg1 = (int) Math.ceil(mFlickDecay * msgCopy.arg1);
-            if (msgCopy.arg1 <= mMaxRepeatDelay) {
-                // Send the key again in arg1 milliseconds
-                mHandler.sendMessageDelayed(msgCopy, msgCopy.arg1);
+                    // Increase the delay by the decay factor and resend
+                    final int delay = (int) Math.ceil(mFlickDecay * msg.arg1);
+                    if (delay <= mMaxRepeatDelay) {
+                        Message msgCopy = Message.obtain(msg);
+                        msgCopy.arg1 = delay;
+                        msgCopy.setAsynchronous(true);
+                        mHandler.sendMessageDelayed(msgCopy, delay);
+                    }
+                    break;
+                }
             }
-            return false;
         }
-    });
+    };
 
     public void updateTrackballDirection(ViewRootImpl viewroot, MotionEvent event) {
         // Store what time the touchpad event occurred
@@ -148,7 +152,7 @@
                     mEdgeSwipePossible = true;
                 }
                 // Clear any flings
-                mHandler.removeMessages(FLICK_MSG_ID);
+                mHandler.removeMessages(MSG_FLICK);
 
                 break;
             case MotionEvent.ACTION_MOVE:
@@ -245,15 +249,20 @@
                     if (mMinFlickDistanceSquared <= xMoveSquared + yMoveSquared &&
                             time - mLastTouchPadEventTimeMs <= MAX_TAP_TIME &&
                             mKeySendRateMs <= mMaxRepeatDelay && mKeySendRateMs > 0) {
-                        Message message = Message.obtain(mHandler, FLICK_MSG_ID,
+                        mLastDeviceId = event.getDeviceId();
+                        mLastSource = event.getSource();
+                        mLastMetaState = event.getMetaState();
+
+                        Message message = Message.obtain(mHandler, MSG_FLICK,
                                 mKeySendRateMs, mLastKeySent, viewroot);
-                        mRecentEvent = event;
+                        message.setAsynchronous(true);
                         mHandler.sendMessageDelayed(message, mKeySendRateMs);
                     }
                 }
                 mEdgeSwipePossible = false;
                 break;
         }
+
         // Store touch event position and time
         mLastTouchPadEventTimeMs = time;
         mLastTouchpadXPosition = event.getX();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f9bb05b..080e7c0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -40,6 +40,7 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManagerGlobal;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -688,6 +689,8 @@
      */
     public static final int NO_ID = -1;
 
+    private static boolean sUseBrokenMakeMeasureSpec = false;
+
     /**
      * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
      * calling setFlags.
@@ -3234,6 +3237,12 @@
         setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
         mUserPaddingStart = UNDEFINED_PADDING;
         mUserPaddingEnd = UNDEFINED_PADDING;
+
+        if (!sUseBrokenMakeMeasureSpec && context.getApplicationInfo().targetSdkVersion <=
+                Build.VERSION_CODES.JELLY_BEAN_MR1 ) {
+            // Older apps may need this compatibility hack for measurement.
+            sUseBrokenMakeMeasureSpec = true;
+        }
     }
 
     /**
@@ -17323,12 +17332,23 @@
          *  <li>{@link android.view.View.MeasureSpec#AT_MOST}</li>
          * </ul>
          *
+         * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's
+         * implementation was such that the order of arguments did not matter
+         * and overflow in either value could impact the resulting MeasureSpec.
+         * {@link android.widget.RelativeLayout} was affected by this bug.
+         * Apps targeting API levels greater than 17 will get the fixed, more strict
+         * behavior.</p>
+         *
          * @param size the size of the measure specification
          * @param mode the mode of the measure specification
          * @return the measure specification based on size and mode
          */
         public static int makeMeasureSpec(int size, int mode) {
-            return (size & ~MODE_MASK) | (mode & MODE_MASK);
+            if (sUseBrokenMakeMeasureSpec) {
+                return size + mode;
+            } else {
+                return (size & ~MODE_MASK) | (mode & MODE_MASK);
+            }
         }
 
         /**
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index d7c7f46..6251c45 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -218,12 +218,14 @@
 
     private static class WarningDialogReceiver extends BroadcastReceiver
             implements DialogInterface.OnDismissListener {
-        private Context mContext;
-        private Dialog mDialog;
+        private final Context mContext;
+        private final Dialog mDialog;
+        private final VolumePanel mVolumePanel;
 
-        WarningDialogReceiver(Context context, Dialog dialog) {
+        WarningDialogReceiver(Context context, Dialog dialog, VolumePanel volumePanel) {
             mContext = context;
             mDialog = dialog;
+            mVolumePanel = volumePanel;
             IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
             context.registerReceiver(this, filter);
         }
@@ -231,16 +233,20 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             mDialog.cancel();
-            synchronized (sConfirmSafeVolumeLock) {
-                sConfirmSafeVolumeDialog = null;
-            }
+            cleanUp();
         }
 
         public void onDismiss(DialogInterface unused) {
             mContext.unregisterReceiver(this);
+            cleanUp();
+        }
+
+        private void cleanUp() {
             synchronized (sConfirmSafeVolumeLock) {
                 sConfirmSafeVolumeDialog = null;
             }
+            mVolumePanel.forceTimeout();
+            mVolumePanel.updateStates();
         }
     }
 
@@ -276,7 +282,8 @@
 
         mDialog = new Dialog(context, R.style.Theme_Panel_Volume) {
             public boolean onTouchEvent(MotionEvent event) {
-                if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+                if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE &&
+                        sConfirmSafeVolumeDialog == null) {
                     forceTimeout();
                     return true;
                 }
@@ -461,7 +468,8 @@
             // never disable touch interactions for remote playback, the muting is not tied to
             // the state of the phone.
             sc.seekbarView.setEnabled(true);
-        } else if (sc.streamType != mAudioManager.getMasterStreamType() && muted) {
+        } else if ((sc.streamType != mAudioManager.getMasterStreamType() && muted) ||
+                        (sConfirmSafeVolumeDialog != null)) {
             sc.seekbarView.setEnabled(false);
         } else {
             sc.seekbarView.setEnabled(true);
@@ -490,7 +498,7 @@
         }
     }
 
-    private void updateStates() {
+    public void updateStates() {
         final int count = mSliderGroup.getChildCount();
         for (int i = 0; i < count; i++) {
             StreamControl sc = (StreamControl) mSliderGroup.getChildAt(i).getTag();
@@ -562,9 +570,9 @@
         postMuteChanged(STREAM_MASTER, flags);
     }
 
-    public void postDisplaySafeVolumeWarning() {
+    public void postDisplaySafeVolumeWarning(int flags) {
         if (hasMessages(MSG_DISPLAY_SAFE_VOLUME_WARNING)) return;
-        obtainMessage(MSG_DISPLAY_SAFE_VOLUME_WARNING, 0, 0).sendToTarget();
+        obtainMessage(MSG_DISPLAY_SAFE_VOLUME_WARNING, flags, 0).sendToTarget();
     }
 
     /**
@@ -598,7 +606,6 @@
 
         removeMessages(MSG_FREE_RESOURCES);
         sendMessageDelayed(obtainMessage(MSG_FREE_RESOURCES), FREE_DELAY);
-
         resetTimeout();
     }
 
@@ -704,7 +711,8 @@
             if (((flags & AudioManager.FLAG_FIXED_VOLUME) != 0) ||
                     (streamType != mAudioManager.getMasterStreamType() &&
                      streamType != AudioService.STREAM_REMOTE_MUSIC &&
-                     isMuted(streamType))) {
+                     isMuted(streamType)) ||
+                     sConfirmSafeVolumeDialog != null) {
                 sc.seekbarView.setEnabled(false);
             } else {
                 sc.seekbarView.setEnabled(true);
@@ -802,7 +810,6 @@
 
         removeMessages(MSG_FREE_RESOURCES);
         sendMessageDelayed(obtainMessage(MSG_FREE_RESOURCES), FREE_DELAY);
-
         resetTimeout();
     }
 
@@ -838,30 +845,34 @@
         }
     }
 
-    protected void onDisplaySafeVolumeWarning() {
-        synchronized (sConfirmSafeVolumeLock) {
-            if (sConfirmSafeVolumeDialog != null) {
-                return;
-            }
-            sConfirmSafeVolumeDialog = new AlertDialog.Builder(mContext)
-                    .setMessage(com.android.internal.R.string.safe_media_volume_warning)
-                    .setPositiveButton(com.android.internal.R.string.yes,
-                                        new DialogInterface.OnClickListener() {
-                        public void onClick(DialogInterface dialog, int which) {
-                            mAudioService.disableSafeMediaVolume();
-                        }
-                    })
-                    .setNegativeButton(com.android.internal.R.string.no, null)
-                    .setIconAttribute(android.R.attr.alertDialogIcon)
-                    .create();
-            final WarningDialogReceiver warning = new WarningDialogReceiver(mContext,
-                    sConfirmSafeVolumeDialog);
+    protected void onDisplaySafeVolumeWarning(int flags) {
+        if ((flags & AudioManager.FLAG_SHOW_UI) != 0 || mDialog.isShowing()) {
+            synchronized (sConfirmSafeVolumeLock) {
+                if (sConfirmSafeVolumeDialog != null) {
+                    return;
+                }
+                sConfirmSafeVolumeDialog = new AlertDialog.Builder(mContext)
+                        .setMessage(com.android.internal.R.string.safe_media_volume_warning)
+                        .setPositiveButton(com.android.internal.R.string.yes,
+                                            new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog, int which) {
+                                mAudioService.disableSafeMediaVolume();
+                            }
+                        })
+                        .setNegativeButton(com.android.internal.R.string.no, null)
+                        .setIconAttribute(android.R.attr.alertDialogIcon)
+                        .create();
+                final WarningDialogReceiver warning = new WarningDialogReceiver(mContext,
+                        sConfirmSafeVolumeDialog, this);
 
-            sConfirmSafeVolumeDialog.setOnDismissListener(warning);
-            sConfirmSafeVolumeDialog.getWindow().setType(
-                                                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-            sConfirmSafeVolumeDialog.show();
+                sConfirmSafeVolumeDialog.setOnDismissListener(warning);
+                sConfirmSafeVolumeDialog.getWindow().setType(
+                                                WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+                sConfirmSafeVolumeDialog.show();
+            }
+            updateStates();
         }
+        resetTimeout();
     }
 
     /**
@@ -957,6 +968,11 @@
                     mDialog.dismiss();
                     mActiveStreamType = -1;
                 }
+                synchronized (sConfirmSafeVolumeLock) {
+                    if (sConfirmSafeVolumeDialog != null) {
+                        sConfirmSafeVolumeDialog.dismiss();
+                    }
+                }
                 break;
             }
             case MSG_RINGER_MODE_CHANGED: {
@@ -980,7 +996,7 @@
                 break;
 
             case MSG_DISPLAY_SAFE_VOLUME_WARNING:
-                onDisplaySafeVolumeWarning();
+                onDisplaySafeVolumeWarning(msg.arg1);
                 break;
         }
     }
diff --git a/core/java/android/webkit/WebCoreThreadWatchdog.java b/core/java/android/webkit/WebCoreThreadWatchdog.java
index a22e6e8..c27bb5f 100644
--- a/core/java/android/webkit/WebCoreThreadWatchdog.java
+++ b/core/java/android/webkit/WebCoreThreadWatchdog.java
@@ -270,7 +270,7 @@
                                             SUBSEQUENT_TIMEOUT_PERIOD);
                                 }
                             })
-                    .setIcon(android.R.drawable.ic_dialog_alert)
+                    .setIconAttribute(android.R.attr.alertDialogIcon)
                     .show();
         }
     }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 33a8531..57bf0d3 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2637,7 +2637,7 @@
 
         if (mTouchModeReset != null) {
             removeCallbacks(mTouchModeReset);
-            mTouchModeReset = null;
+            mTouchModeReset.run();
         }
         mIsAttached = false;
     }
@@ -3416,6 +3416,7 @@
                             mTouchModeReset = new Runnable() {
                                 @Override
                                 public void run() {
+                                    mTouchModeReset = null;
                                     mTouchMode = TOUCH_MODE_REST;
                                     child.setPressed(false);
                                     setPressed(false);
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index f279f8e..a379157 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -375,7 +375,7 @@
         /**
          * Constructor called from {@link #CREATOR}
          */
-        private SavedState(Parcel in) {
+        SavedState(Parcel in) {
             super(in);
             selectedId = in.readLong();
             position = in.readInt();
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index e0c5bbd..c4ef11c 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -891,7 +891,7 @@
             lp = (Gallery.LayoutParams) generateDefaultLayoutParams();
         }
 
-        addViewInLayout(child, fromLeft != mIsRtl ? -1 : 0, lp);
+        addViewInLayout(child, fromLeft != mIsRtl ? -1 : 0, lp, true);
 
         child.setSelected(offset == 0);
 
diff --git a/core/java/android/widget/HeaderViewListAdapter.java b/core/java/android/widget/HeaderViewListAdapter.java
index e2a269e..0685e61 100644
--- a/core/java/android/widget/HeaderViewListAdapter.java
+++ b/core/java/android/widget/HeaderViewListAdapter.java
@@ -79,7 +79,8 @@
     }
 
     public boolean isEmpty() {
-        return mAdapter == null || mAdapter.isEmpty();
+        return (mAdapter == null || mAdapter.isEmpty())
+	        && getFootersCount() + getHeadersCount() == 0;
     }
 
     private boolean areAllListInfosSelectable(ArrayList<ListView.FixedViewInfo> infos) {
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index e3f0960..b40260c 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -30,6 +30,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Build;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -93,6 +94,9 @@
     private int mBaseline = -1;
     private boolean mBaselineAlignBottom = false;
 
+    // AdjustViewBounds behavior will be in compatibility mode for older apps.
+    private boolean mAdjustViewBoundsCompat = false;
+
     private static final ScaleType[] sScaleTypeArray = {
         ScaleType.MATRIX,
         ScaleType.FIT_XY,
@@ -167,6 +171,8 @@
     private void initImageView() {
         mMatrix     = new Matrix();
         mScaleType  = ScaleType.FIT_CENTER;
+        mAdjustViewBoundsCompat = mContext.getApplicationInfo().targetSdkVersion <=
+                Build.VERSION_CODES.JELLY_BEAN_MR1;
     }
 
     @Override
@@ -228,8 +234,15 @@
     /**
      * Set this to true if you want the ImageView to adjust its bounds
      * to preserve the aspect ratio of its drawable.
+     *
+     * <p><strong>Note:</strong> If the application targets API level 17 or lower,
+     * adjustViewBounds will allow the drawable to shrink the view bounds, but not grow
+     * to fill available measured space in all cases. This is for compatibility with
+     * legacy {@link android.view.View.MeasureSpec MeasureSpec} and
+     * {@link android.widget.RelativeLayout RelativeLayout} behavior.</p>
+     *
      * @param adjustViewBounds Whether to adjust the bounds of this view
-     * to presrve the original aspect ratio of the drawable
+     * to preserve the original aspect ratio of the drawable.
      * 
      * @see #getAdjustViewBounds()
      *
@@ -801,7 +814,7 @@
                                 pleft + pright;
 
                         // Allow the width to outgrow its original estimate if height is fixed.
-                        if (!resizeHeight) {
+                        if (!resizeHeight && !mAdjustViewBoundsCompat) {
                             widthSize = resolveAdjustedSize(newWidth, mMaxWidth, widthMeasureSpec);
                         }
 
@@ -817,7 +830,7 @@
                                 ptop + pbottom;
 
                         // Allow the height to outgrow its original estimate if width is fixed.
-                        if (!resizeWidth) {
+                        if (!resizeWidth && !mAdjustViewBoundsCompat) {
                             heightSize = resolveAdjustedSize(newHeight, mMaxHeight,
                                     heightMeasureSpec);
                         }
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index a5eb281..e749e63 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -29,6 +29,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
+import android.os.Build;
 import android.util.AttributeSet;
 import android.util.Pools.SimplePool;
 import android.util.SparseArray;
@@ -53,6 +54,21 @@
  * {@link #ALIGN_PARENT_BOTTOM}.
  * </p>
  *
+ * <p><strong>Note:</strong> In platform version 17 and lower, RelativeLayout was affected by
+ * a measurement bug that could cause child views to be measured with incorrect
+ * {@link android.view.View.MeasureSpec MeasureSpec} values. (See
+ * {@link android.view.View.MeasureSpec#makeMeasureSpec(int, int) MeasureSpec.makeMeasureSpec}
+ * for more details.) This was triggered when a RelativeLayout container was placed in
+ * a scrolling container, such as a ScrollView or HorizontalScrollView. If a custom view
+ * not equipped to properly measure with the MeasureSpec mode
+ * {@link android.view.View.MeasureSpec#UNSPECIFIED UNSPECIFIED} was placed in a RelativeLayout,
+ * this would silently work anyway as RelativeLayout would pass a very large
+ * {@link android.view.View.MeasureSpec#AT_MOST AT_MOST} MeasureSpec instead.</p>
+ *
+ * <p>This behavior has been preserved for apps that set <code>android:targetSdkVersion="17"</code>
+ * or older in their manifest's <code>uses-sdk</code> tag for compatibility. Apps targeting SDK
+ * version 18 or newer will receive the correct behavior</p>
+ *
  * <p>See the <a href="{@docRoot}guide/topics/ui/layout/relative.html">Relative
  * Layout</a> guide.</p>
  *
@@ -199,18 +215,29 @@
     private View[] mSortedVerticalChildren = new View[0];
     private final DependencyGraph mGraph = new DependencyGraph();
 
+    // Compatibility hack. Old versions of the platform had problems
+    // with MeasureSpec value overflow and RelativeLayout was one source of them.
+    // Some apps came to rely on them. :(
+    private boolean mAllowBrokenMeasureSpecs = false;
+
     public RelativeLayout(Context context) {
         super(context);
+        mAllowBrokenMeasureSpecs = context.getApplicationInfo().targetSdkVersion <=
+                Build.VERSION_CODES.JELLY_BEAN_MR1;
     }
 
     public RelativeLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
         initFromAttributes(context, attrs);
+        mAllowBrokenMeasureSpecs = context.getApplicationInfo().targetSdkVersion <=
+                Build.VERSION_CODES.JELLY_BEAN_MR1;
     }
 
     public RelativeLayout(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         initFromAttributes(context, attrs);
+        mAllowBrokenMeasureSpecs = context.getApplicationInfo().targetSdkVersion <=
+                Build.VERSION_CODES.JELLY_BEAN_MR1;
     }
 
     private void initFromAttributes(Context context, AttributeSet attrs) {
@@ -416,7 +443,7 @@
 
         // We need to know our size for doing the correct computation of positioning in RTL mode
         if (isLayoutRtl() && (myWidth == -1 || isWrapContentWidth)) {
-            myWidth = getPaddingStart() + getPaddingEnd();
+            int w = getPaddingStart() + getPaddingEnd();
             final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
             for (int i = 0; i < count; i++) {
                 View child = views[i];
@@ -433,8 +460,18 @@
                     }
                     child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
 
-                    myWidth += child.getMeasuredWidth();
-                    myWidth += params.leftMargin + params.rightMargin;
+                    w += child.getMeasuredWidth();
+                    w += params.leftMargin + params.rightMargin;
+                }
+            }
+            if (myWidth == -1) {
+                // Easy case: "myWidth" was undefined before so use the width we have just computed
+                myWidth = w;
+            } else {
+                // "myWidth" was defined before, so take the min of it and the computed width if it
+                // is a non null one
+                if (w > 0) {
+                    myWidth = Math.min(myWidth, w);
                 }
             }
         }
@@ -660,7 +697,7 @@
                 mPaddingLeft, mPaddingRight,
                 myWidth);
         int childHeightMeasureSpec;
-        if (myHeight < 0) {
+        if (myHeight < 0 && !mAllowBrokenMeasureSpecs) {
             // Negative values in a mySize/myWidth/myWidth value in RelativeLayout measurement
             // is code for, "we got an unspecified mode in the RelativeLayout's measurespec."
             // Carry it forward.
@@ -692,7 +729,7 @@
     private int getChildMeasureSpec(int childStart, int childEnd,
             int childSize, int startMargin, int endMargin, int startPadding,
             int endPadding, int mySize) {
-        if (mySize < 0) {
+        if (mySize < 0 && !mAllowBrokenMeasureSpecs) {
             // Negative values in a mySize/myWidth/myWidth value in RelativeLayout measurement
             // is code for, "we got an unspecified mode in the RelativeLayout's measurespec."
             // Carry it forward.
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index b088c59..aeee111 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -318,9 +318,13 @@
      */
     private class RemoteViewsFrameLayoutRefSet {
         private HashMap<Integer, LinkedList<RemoteViewsFrameLayout>> mReferences;
+        private HashMap<RemoteViewsFrameLayout, LinkedList<RemoteViewsFrameLayout>>
+                mViewToLinkedList;
 
         public RemoteViewsFrameLayoutRefSet() {
             mReferences = new HashMap<Integer, LinkedList<RemoteViewsFrameLayout>>();
+            mViewToLinkedList =
+                    new HashMap<RemoteViewsFrameLayout, LinkedList<RemoteViewsFrameLayout>>();
         }
 
         /**
@@ -337,6 +341,7 @@
                 refs = new LinkedList<RemoteViewsFrameLayout>();
                 mReferences.put(pos, refs);
             }
+            mViewToLinkedList.put(layout, refs);
 
             // Add the references to the list
             refs.add(layout);
@@ -355,21 +360,34 @@
                 final LinkedList<RemoteViewsFrameLayout> refs = mReferences.get(pos);
                 for (final RemoteViewsFrameLayout ref : refs) {
                     ref.onRemoteViewsLoaded(view, mRemoteViewsOnClickHandler);
+                    if (mViewToLinkedList.containsKey(ref)) {
+                        mViewToLinkedList.remove(ref);
+                    }
                 }
                 refs.clear();
-
                 // Remove this set from the original mapping
                 mReferences.remove(pos);
             }
         }
 
         /**
+         * We need to remove views from this set if they have been recycled by the AdapterView.
+         */
+        public void removeView(RemoteViewsFrameLayout rvfl) {
+            if (mViewToLinkedList.containsKey(rvfl)) {
+                mViewToLinkedList.get(rvfl).remove(rvfl);
+                mViewToLinkedList.remove(rvfl);
+            }
+        }
+
+        /**
          * Removes all references to all RemoteViewsFrameLayouts returned by the adapter.
          */
         public void clear() {
             // We currently just clear the references, and leave all the previous layouts returned
             // in their default state of the loading view.
             mReferences.clear();
+            mViewToLinkedList.clear();
         }
     }
 
@@ -1134,6 +1152,10 @@
             boolean isConnected = mServiceConnection.isConnected();
             boolean hasNewItems = false;
 
+            if (convertView != null && convertView instanceof RemoteViewsFrameLayout) {
+                mRequestedViews.removeView((RemoteViewsFrameLayout) convertView);
+            }
+
             if (!isInCache && !isConnected) {
                 // Requesting bind service will trigger a super.notifyDataSetChanged(), which will
                 // in turn trigger another request to getView()
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index cd8638d..0281602 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -1247,6 +1247,7 @@
      */
     @Override
     public void onActionViewCollapsed() {
+        setQuery("", false);
         clearFocus();
         updateViewsVisibility(true);
         mQueryTextView.setImeOptions(mCollapsedImeOptions);
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 74ea038..9e7f97e 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -109,7 +109,7 @@
         mIds = new int[size];
         mSpellCheckSpans = new SpellCheckSpan[size];
 
-        setLocale(mTextView.getTextServicesLocale());
+        setLocale(mTextView.getSpellCheckerLocale());
 
         mCookie = hashCode();
     }
@@ -120,7 +120,8 @@
         mTextServicesManager = (TextServicesManager) mTextView.getContext().
                 getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
         if (!mTextServicesManager.isSpellCheckerEnabled()
-                ||  mTextServicesManager.getCurrentSpellCheckerSubtype(true) == null) {
+                || mCurrentLocale == null
+                || mTextServicesManager.getCurrentSpellCheckerSubtype(true) == null) {
             mSpellCheckerSession = null;
         } else {
             mSpellCheckerSession = mTextServicesManager.newSpellCheckerSession(
@@ -146,8 +147,10 @@
 
         resetSession();
 
-        // Change SpellParsers' wordIterator locale
-        mWordIterator = new WordIterator(locale);
+        if (locale != null) {
+            // Change SpellParsers' wordIterator locale
+            mWordIterator = new WordIterator(locale);
+        }
 
         // This class is the listener for locale change: warn other locale-aware objects
         mTextView.onLocaleChanged();
@@ -222,9 +225,9 @@
         if (DBG) {
             Log.d(TAG, "Start spell-checking: " + start + ", " + end);
         }
-        final Locale locale = mTextView.getTextServicesLocale();
+        final Locale locale = mTextView.getSpellCheckerLocale();
         final boolean isSessionActive = isSessionActive();
-        if (mCurrentLocale == null || (!(mCurrentLocale.equals(locale)))) {
+        if (locale == null || mCurrentLocale == null || (!(mCurrentLocale.equals(locale)))) {
             setLocale(locale);
             // Re-check the entire text
             start = 0;
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 925864c..fa64fd3 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -25,6 +25,8 @@
 import android.database.DataSetObserver;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.Gravity;
@@ -697,6 +699,69 @@
         return width;
     }
 
+    @Override
+    public Parcelable onSaveInstanceState() {
+        final SavedState ss = new SavedState(super.onSaveInstanceState());
+        ss.showDropdown = mPopup != null && mPopup.isShowing();
+        return ss;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        SavedState ss = (SavedState) state;
+
+        super.onRestoreInstanceState(ss.getSuperState());
+
+        if (ss.showDropdown) {
+            ViewTreeObserver vto = getViewTreeObserver();
+            if (vto != null) {
+                final OnGlobalLayoutListener listener = new OnGlobalLayoutListener() {
+                    @Override
+                    public void onGlobalLayout() {
+                        if (!mPopup.isShowing()) {
+                            mPopup.show();
+                        }
+                        final ViewTreeObserver vto = getViewTreeObserver();
+                        if (vto != null) {
+                            vto.removeOnGlobalLayoutListener(this);
+                        }
+                    }
+                };
+                vto.addOnGlobalLayoutListener(listener);
+            }
+        }
+    }
+
+    static class SavedState extends AbsSpinner.SavedState {
+        boolean showDropdown;
+
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        private SavedState(Parcel in) {
+            super(in);
+            showDropdown = in.readByte() != 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeByte((byte) (showDropdown ? 1 : 0));
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+
     /**
      * <p>Wrapper class for an Adapter. Transforms the embedded Adapter instance
      * into a ListAdapter.</p>
@@ -941,8 +1006,7 @@
             mHintText = hintText;
         }
 
-        @Override
-        public void show() {
+        void computeContentWidth() {
             final Drawable background = getBackground();
             int hOffset = 0;
             if (background != null) {
@@ -955,6 +1019,7 @@
             final int spinnerPaddingLeft = Spinner.this.getPaddingLeft();
             final int spinnerPaddingRight = Spinner.this.getPaddingRight();
             final int spinnerWidth = Spinner.this.getWidth();
+
             if (mDropDownWidth == WRAP_CONTENT) {
                 int contentWidth =  measureContentWidth(
                         (SpinnerAdapter) mAdapter, getBackground());
@@ -977,11 +1042,25 @@
                 hOffset += spinnerPaddingLeft;
             }
             setHorizontalOffset(hOffset);
+        }
+
+        @Override
+        public void show() {
+            final boolean wasShowing = isShowing();
+
+            computeContentWidth();
+
             setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
             super.show();
             getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
             setSelection(Spinner.this.getSelectedItemPosition());
 
+            if (wasShowing) {
+                // Skip setting up the layout/dismiss listener below. If we were previously
+                // showing it will still stick around.
+                return;
+            }
+
             // Make sure we hide if our anchor goes away.
             // TODO: This might be appropriate to push all the way down to PopupWindow,
             // but it may have other side effects to investigate first. (Text editing handles, etc.)
@@ -992,6 +1071,12 @@
                     public void onGlobalLayout() {
                         if (!Spinner.this.isVisibleToUser()) {
                             dismiss();
+                        } else {
+                            computeContentWidth();
+
+                            // Use super.show here to update; we don't want to move the selected
+                            // position or adjust other things that would be reset otherwise.
+                            DropdownPopup.super.show();
                         }
                     }
                 };
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1f09ddd..1f64c5b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -511,7 +511,7 @@
 
     private InputFilter[] mFilters = NO_FILTERS;
 
-    private volatile Locale mCurrentTextServicesLocaleCache;
+    private volatile Locale mCurrentSpellCheckerLocaleCache;
     private final ReentrantLock mCurrentTextServicesLocaleLock = new ReentrantLock();
 
     // It is possible to have a selection even when mEditor is null (programmatically set, like when
@@ -7825,27 +7825,46 @@
                 (isTextSelectable() && mText instanceof Spannable && isEnabled());
     }
 
+    private Locale getTextServicesLocale(boolean allowNullLocale) {
+        // Start fetching the text services locale asynchronously.
+        updateTextServicesLocaleAsync();
+        // If !allowNullLocale and there is no cached text services locale, just return the default
+        // locale.
+        return (mCurrentSpellCheckerLocaleCache == null && !allowNullLocale) ? Locale.getDefault()
+                : mCurrentSpellCheckerLocaleCache;
+    }
+
     /**
      * This is a temporary method. Future versions may support multi-locale text.
      * Caveat: This method may not return the latest text services locale, but this should be
      * acceptable and it's more important to make this method asynchronous.
      *
-     * @return The locale that should be used for a word iterator and a spell checker
+     * @return The locale that should be used for a word iterator
      * in this TextView, based on the current spell checker settings,
      * the current IME's locale, or the system default locale.
+     * Please note that a word iterator in this TextView is different from another word iterator
+     * used by SpellChecker.java of TextView. This method should be used for the former.
      * @hide
      */
     // TODO: Support multi-locale
     // TODO: Update the text services locale immediately after the keyboard locale is switched
     // by catching intent of keyboard switch event
     public Locale getTextServicesLocale() {
-        if (mCurrentTextServicesLocaleCache == null) {
-            // If there is no cached text services locale, just return the default locale.
-            mCurrentTextServicesLocaleCache = Locale.getDefault();
-        }
-        // Start fetching the text services locale asynchronously.
-        updateTextServicesLocaleAsync();
-        return mCurrentTextServicesLocaleCache;
+        return getTextServicesLocale(false /* allowNullLocale */);
+    }
+
+    /**
+     * This is a temporary method. Future versions may support multi-locale text.
+     * Caveat: This method may not return the latest spell checker locale, but this should be
+     * acceptable and it's more important to make this method asynchronous.
+     *
+     * @return The locale that should be used for a spell checker in this TextView,
+     * based on the current spell checker settings, the current IME's locale, or the system default
+     * locale.
+     * @hide
+     */
+    public Locale getSpellCheckerLocale() {
+        return getTextServicesLocale(true /* allowNullLocale */);
     }
 
     private void updateTextServicesLocaleAsync() {
@@ -7864,14 +7883,16 @@
     }
 
     private void updateTextServicesLocaleLocked() {
-        Locale locale = Locale.getDefault();
         final TextServicesManager textServicesManager = (TextServicesManager)
                 mContext.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
         final SpellCheckerSubtype subtype = textServicesManager.getCurrentSpellCheckerSubtype(true);
+        final Locale locale;
         if (subtype != null) {
             locale = SpellCheckerSubtype.constructLocaleFromString(subtype.getLocale());
+        } else {
+            locale = null;
         }
-        mCurrentTextServicesLocaleCache = locale;
+        mCurrentSpellCheckerLocaleCache = locale;
     }
 
     void onLocaleChanged() {
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 485bd37..1d85126 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -374,8 +374,11 @@
                 // remove the old view if necessary
                 handleHide();
                 mView = mNextView;
-                mWM = (WindowManager)mView.getContext().getApplicationContext()
-                        .getSystemService(Context.WINDOW_SERVICE);
+                Context context = mView.getContext().getApplicationContext();
+                if (context == null) {
+                    context = mView.getContext();
+                }
+                mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
                 // We can resolve the Gravity here by using the Locale for getting
                 // the layout direction
                 final Configuration config = mView.getContext().getResources().getConfiguration();
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index 84699dc..b442ff5 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -24,38 +24,32 @@
 public class HandlerCaller {
 
     public final Context mContext;
-    
+
     final Looper mMainLooper;
     final Handler mH;
 
     final Callback mCallback;
 
     class MyHandler extends Handler {
-        MyHandler(Looper looper) {
-            super(looper);
+        MyHandler(Looper looper, boolean async) {
+            super(looper, null, async);
         }
-        
+
         @Override
         public void handleMessage(Message msg) {
             mCallback.executeMessage(msg);
         }
     }
-    
+
     public interface Callback {
         public void executeMessage(Message msg);
     }
-    
-    public HandlerCaller(Context context, Callback callback) {
-        mContext = context;
-        mMainLooper = context.getMainLooper();
-        mH = new MyHandler(mMainLooper);
-        mCallback = callback;
-    }
 
-    public HandlerCaller(Context context, Looper looper, Callback callback) {
+    public HandlerCaller(Context context, Looper looper, Callback callback,
+            boolean asyncHandler) {
         mContext = context;
-        mMainLooper = looper;
-        mH = new MyHandler(mMainLooper);
+        mMainLooper = looper != null ? looper : context.getMainLooper();
+        mH = new MyHandler(mMainLooper, asyncHandler);
         mCallback = callback;
     }
 
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index 5093b4d..52281d9 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -180,6 +180,9 @@
     /** CMD_FULLY_CONNECTED refused because a connection already exists*/
     public static final int STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED = 3;
 
+    /** Error indicating abnormal termination of destination messenger */
+    public static final int STATUS_REMOTE_DISCONNECTION = 4;
+
     /** Service connection */
     private AsyncChannelConnection mConnection;
 
@@ -195,6 +198,9 @@
     /** Messenger for destination */
     private Messenger mDstMessenger;
 
+    /** Death Monitor for destination messenger */
+    private DeathMonitor mDeathMonitor;
+
     /**
      * AsyncChannel constructor
      */
@@ -434,6 +440,7 @@
         mSrcHandler = null;
         mSrcMessenger = null;
         mDstMessenger = null;
+        mDeathMonitor = null;
         mConnection = null;
     }
 
@@ -457,6 +464,10 @@
         if (mSrcHandler != null) {
             replyDisconnected(STATUS_SUCCESSFUL);
         }
+        // Unlink only when bindService isn't used
+        if (mConnection == null && mDstMessenger != null && mDeathMonitor!= null) {
+            mDstMessenger.getBinder().unlinkToDeath(mDeathMonitor, 0);
+        }
     }
 
     /**
@@ -832,6 +843,21 @@
         msg.arg1 = status;
         msg.obj = this;
         msg.replyTo = mDstMessenger;
+
+        /*
+         * Link to death only when bindService isn't used.
+         */
+        if (mConnection == null) {
+            mDeathMonitor = new DeathMonitor();
+            try {
+                mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0);
+            } catch (RemoteException e) {
+                mDeathMonitor = null;
+                // Override status to indicate failure
+                msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
+            }
+        }
+
         mSrcHandler.sendMessage(msg);
     }
 
@@ -877,4 +903,15 @@
     private static void log(String s) {
         Slog.d(TAG, s);
     }
+
+    private final class DeathMonitor implements IBinder.DeathRecipient {
+
+        DeathMonitor() {
+        }
+
+        public void binderDied() {
+            replyDisconnected(STATUS_REMOTE_DISCONNECTION);
+        }
+
+    }
 }
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 6fb459c..61bc002 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -687,6 +687,7 @@
                 if (mSpinner == null) {
                     mSpinner = new Spinner(mContext, null,
                             com.android.internal.R.attr.actionDropDownStyle);
+                    mSpinner.setId(com.android.internal.R.id.action_bar_spinner);
                     mListNavLayout = new LinearLayout(mContext, null,
                             com.android.internal.R.attr.actionBarTabBarStyle);
                     LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 907b52a..555c7c2 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -123,14 +123,14 @@
      */
     public static final int ID_DEFAULT_STATUS_WIDGET = -2;
 
-    protected final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
-    protected final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
-    protected final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
+    public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
+    public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
+    public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
     public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
     public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
-    protected final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
-    protected final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
-    protected final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
+    public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
+    public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
+    public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
     public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
             = "lockscreen.biometric_weak_fallback";
     public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
@@ -138,7 +138,7 @@
     public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
             = "lockscreen.power_button_instantly_locks";
 
-    protected final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
+    public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
 
     private final Context mContext;
     private final ContentResolver mContentResolver;
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index a3981ce..6ee504d 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -71,8 +71,8 @@
     // Don't throw NPE -- I feel like it's sort of mean for a logging function
     // to be all crashy if you pass in NULL -- but make the NULL value explicit.
     const char *str = value != NULL ? env->GetStringUTFChars(value, NULL) : "NULL";
-    jint len = strlen(str);
-    const int max = sizeof(buf) - sizeof(len) - 2;  // Type byte, final newline
+    uint32_t len = strlen(str);
+    size_t max = sizeof(buf) - sizeof(len) - 2;  // Type byte, final newline
     if (len > max) len = max;
 
     buf[0] = EVENT_TYPE_STRING;
diff --git a/core/res/res/layout/list_menu_item_layout.xml b/core/res/res/layout/list_menu_item_layout.xml
index 0f37c71..e8d4983 100644
--- a/core/res/res/layout/list_menu_item_layout.xml
+++ b/core/res/res/layout/list_menu_item_layout.xml
@@ -40,7 +40,8 @@
             android:singleLine="true"
             android:duplicateParentState="true"
             android:ellipsize="marquee"
-            android:fadingEdge="horizontal" />
+            android:fadingEdge="horizontal"
+            android:textAlignment="viewStart" />
 
         <TextView
             android:id="@+id/shortcut"
@@ -50,7 +51,8 @@
             android:layout_alignParentStart="true"
             android:textAppearance="?android:attr/textAppearanceSmall"
             android:singleLine="true"
-            android:duplicateParentState="true" />
+            android:duplicateParentState="true"
+            android:textAlignment="viewStart" />
 
     </RelativeLayout>
 
diff --git a/core/res/res/layout/notification_template_base.xml b/core/res/res/layout/notification_template_base.xml
index 134f45e..d2e25c1 100644
--- a/core/res/res/layout/notification_template_base.xml
+++ b/core/res/res/layout/notification_template_base.xml
@@ -61,7 +61,6 @@
             <ViewStub android:id="@+id/time"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_gravity="center"
                 android:layout_weight="0"
                 android:visibility="gone"
                 android:layout="@layout/notification_template_part_time"
@@ -69,7 +68,6 @@
             <ViewStub android:id="@+id/chronometer"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_gravity="center"
                 android:layout_weight="0"
                 android:visibility="gone"
                 android:layout="@layout/notification_template_part_chronometer"
diff --git a/core/res/res/layout/notification_template_big_base.xml b/core/res/res/layout/notification_template_big_base.xml
index b5da486..7cc6650 100644
--- a/core/res/res/layout/notification_template_big_base.xml
+++ b/core/res/res/layout/notification_template_big_base.xml
@@ -66,7 +66,6 @@
                 <ViewStub android:id="@+id/time"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_gravity="center"
                     android:layout_weight="0"
                     android:visibility="gone"
                     android:layout="@layout/notification_template_part_time"
@@ -74,7 +73,6 @@
                 <ViewStub android:id="@+id/chronometer"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_gravity="center"
                     android:layout_weight="0"
                     android:visibility="gone"
                     android:layout="@layout/notification_template_part_chronometer"
diff --git a/core/res/res/layout/notification_template_big_text.xml b/core/res/res/layout/notification_template_big_text.xml
index 01f1acf..7e6da22 100644
--- a/core/res/res/layout/notification_template_big_text.xml
+++ b/core/res/res/layout/notification_template_big_text.xml
@@ -68,7 +68,6 @@
                 <ViewStub android:id="@+id/time"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_gravity="center"
                     android:layout_weight="0"
                     android:visibility="gone"
                     android:layout="@layout/notification_template_part_time"
@@ -76,7 +75,6 @@
                 <ViewStub android:id="@+id/chronometer"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_gravity="center"
                     android:layout_weight="0"
                     android:visibility="gone"
                     android:layout="@layout/notification_template_part_chronometer"
diff --git a/core/res/res/layout/notification_template_inbox.xml b/core/res/res/layout/notification_template_inbox.xml
index 1b7e659..1eec871 100644
--- a/core/res/res/layout/notification_template_inbox.xml
+++ b/core/res/res/layout/notification_template_inbox.xml
@@ -69,7 +69,6 @@
                 <ViewStub android:id="@+id/time"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_gravity="center"
                     android:layout_weight="0"
                     android:visibility="gone"
                     android:layout="@layout/notification_template_part_time"
@@ -77,7 +76,6 @@
                 <ViewStub android:id="@+id/chronometer"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_gravity="center"
                     android:layout_weight="0"
                     android:visibility="gone"
                     android:layout="@layout/notification_template_part_chronometer"
diff --git a/core/res/res/layout/popup_menu_item_layout.xml b/core/res/res/layout/popup_menu_item_layout.xml
index f67ed4e..452f85d 100644
--- a/core/res/res/layout/popup_menu_item_layout.xml
+++ b/core/res/res/layout/popup_menu_item_layout.xml
@@ -41,7 +41,8 @@
             android:singleLine="true"
             android:duplicateParentState="true"
             android:ellipsize="marquee"
-            android:fadingEdge="horizontal" />
+            android:fadingEdge="horizontal"
+            android:textAlignment="viewStart" />
 
         <TextView
             android:id="@+id/shortcut"
@@ -51,7 +52,8 @@
             android:layout_alignParentStart="true"
             android:textAppearance="?android:attr/textAppearanceSmallPopupMenu"
             android:singleLine="true"
-            android:duplicateParentState="true" />
+            android:duplicateParentState="true"
+            android:textAlignment="viewStart" />
 
     </RelativeLayout>
 
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 4d5a019..14d2412 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Kennisgewing-volume"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Verstek luitoon"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Verstek luitoon (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Stil"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Geen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Luitone"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Onbekende luitoon"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index c929f96..d9b9940 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"የማሳወቂያ ክፍልፍል"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"ነባሪ የስልክ ላይ ጥሪ"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>) ነባሪ የስልክ ላይ ጥሪ"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"ፀጥታ"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"ምንም"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"ጥሪ ድምፆች"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"ያልታወቀ የስልክ ጥሪ ድምፅ"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 7b40a26..a93c75f 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"مستوى صوت الإشعار"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"نغمة الرنين الافتراضية"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"نغمة الرنين الافتراضية (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"صامت"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"لا شيء"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"نغمات الرنين"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"نغمة رنين غير معروفة"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index adbcace..89fba51 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Гучнасць апавяшчэнняў"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Рынгтон па змаўчаннi"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Рынгтон па змаўчаннi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Ціхі рэжым"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Няма"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Рынгтоны"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Невядомы рынгтон"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index a3d9e76..f65fc9d 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Сила на звука при известие"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Стандартна мелодия"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Стандартна мелодия (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Тишина"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Без"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодии"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Неизвестна мелодия"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index df178ca..28e692b 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volum de notificació"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"To predeterminat"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"To predeterminat (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Silenci"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Cap"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Sons de trucada"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"To desconegut"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index cbaf2b6..4bc8571 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Hlasitost oznámení"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Výchozí vyzváněcí tón"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Výchozí vyzváněcí tón (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Ticho"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Žádné"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Vyzváněcí tóny"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Neznámý vyzváněcí tón"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index c139fae..09fee8f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Lydstyrke for meddelelser"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Standardringetone"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standardringetone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Lydløs"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringetoner"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Ukendt ringetone"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index a2082a2..563d1a5 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -241,7 +241,7 @@
     <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Ermöglicht der App, Notfall-Broadcasts zu empfangen und zu verarbeiten. Diese Berechtigung steht nur System-Apps zur Verfügung."</string>
     <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"Cell Broadcast-Nachrichten lesen"</string>
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Ermöglicht der App, von Ihrem Gerät empfangene Cell Broadcast-Nachrichten zu lesen. Cell Broadcast-Benachrichtigungen werden an einigen Standorten gesendet, um Sie über Notfallsituationen zu informieren. Schädliche Apps können die Leistung oder den Betrieb Ihres Geräts beeinträchtigen, wenn eine Cell Broadcast-Notfallbenachrichtigung eingeht."</string>
-    <string name="permlab_sendSms" msgid="5600830612147671529">"Kurznachrichten senden"</string>
+    <string name="permlab_sendSms" msgid="5600830612147671529">"SMS senden"</string>
     <string name="permdesc_sendSms" msgid="7094729298204937667">"Ermöglicht der App, SMS zu senden. Dies kann zu unerwarteten Kosten führen. Schädliche Apps können Kosten verursachen, indem sie Nachrichten ohne Ihre Bestätigung senden."</string>
     <string name="permlab_sendSmsNoConfirmation" msgid="4781483105951730228">"SMS ohne Bestätigung senden"</string>
     <string name="permdesc_sendSmsNoConfirmation" msgid="402569800862935907">"Ermöglicht der App, SMS zu senden. Dies kann zu unerwarteten Kosten führen. Schädliche Apps können Kosten verursachen, indem sie Nachrichten ohne Ihre Bestätigung senden."</string>
@@ -253,7 +253,7 @@
     <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Ermöglicht der App, auf Ihrem Telefon oder Ihrer SIM-Karte gespeicherte SMS zu bearbeiten. Schädliche Apps können so Ihre Nachrichten löschen."</string>
     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"Textnachrichten (WAP) empfangen"</string>
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Ermöglicht der App, WAP-Nachrichten zu empfangen und zu verarbeiten. Mit der Berechtigung können Nachrichten, die an Sie gesendet wurden, überwacht und gelöscht werden, bevor sie Ihnen angezeigt werden."</string>
-    <string name="permlab_getTasks" msgid="6466095396623933906">"aktive Apps abrufen"</string>
+    <string name="permlab_getTasks" msgid="6466095396623933906">"Aktive Apps abrufen"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Ermöglicht der App, Informationen zu aktuellen und kürzlich ausgeführten Aufgaben abzurufen. Damit kann die App möglicherweise ermitteln, welche Apps auf Ihrem Gerät zum Einsatz kommen."</string>
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"Nutzerübergreifend interagieren"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Ermöglicht der App, auf dem Gerät nutzerübergreifend Aktionen durchzuführen. Schädliche Apps können so den zwischen den Nutzern bestehenden Schutz aufheben."</string>
@@ -295,7 +295,7 @@
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Ermöglicht einer App, einen Eingabefilter zu registrieren, der den Stream aller Nutzerereignisse vor ihrem Versand filtert. Eine schädliche App kann die System-UI ohne Eingriff des Nutzers kontrollieren."</string>
     <string name="permlab_magnify_display" msgid="5973626738170618775">"Anzeige vergrößern"</string>
     <string name="permdesc_magnify_display" msgid="7121235684515003792">"Erlaubt der App, den Inhalt einer Anzeige zu vergrößern. Schädliche Apps verändern eventuell die Ansicht, sodass Inhalte nicht richtig angezeigt werden."</string>
-    <string name="permlab_shutdown" msgid="7185747824038909016">"partielles Herunterfahren"</string>
+    <string name="permlab_shutdown" msgid="7185747824038909016">"Partielles Herunterfahren"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Versetzt den Aktivitätsmanager in einen heruntergefahrenen Zustand. Führt kein vollständiges Herunterfahren aus."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"App-Wechsel verhindern"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Hindert den Nutzer daran, zu einer anderen App zu wechseln"</string>
@@ -303,9 +303,9 @@
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Ermöglicht der App, den Start von Systemaktivitäten zu überwachen und zu steuern. Schädliche Apps können so das gesamte System beeinträchtigen. Diese Berechtigung wird nur zu Entwicklungszwecken und nie für die normale Nutzung benötigt."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"Broadcast ohne Paket senden"</string>
     <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Ermöglicht der App, eine Benachrichtigung zu senden, dass ein App-Paket entfernt wurde. Schädliche Apps können so eine andere aktive App beenden."</string>
-    <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"per SMS empfangenen Broadcast senden"</string>
+    <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"Per SMS empfangenen Broadcast senden"</string>
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Ermöglicht der App, eine Benachrichtigung zu senden, dass eine SMS empfangen wurde. Schädliche Apps können so eingehende SMS fälschen."</string>
-    <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"von WAP-PUSH empfangenen Broadcast senden"</string>
+    <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"Von WAP-PUSH empfangenen Broadcast senden"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ermöglicht der App, eine Benachrichtigung zu senden, dass eine WAP PUSH-Nachricht empfangen wurde. Schädliche Apps können so den Empfang von MMS vortäuschen oder unbemerkt den Inhalt einer beliebigen Webseite durch schädliche Inhalte ersetzen."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"Anzahl der laufenden Prozesse beschränken"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ermöglicht der App, die maximale Anzahl an aktiven Prozessen zu steuern. Wird nie für normale Apps benötigt."</string>
@@ -319,7 +319,7 @@
     <string name="permdesc_backup" msgid="6912230525140589891">"Ermöglicht der App, den Sicherungs- und Wiederherstellungsmechanismus des Systems zu steuern. Nicht für normale Apps vorgesehen."</string>
     <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"Vollständige Sicherung oder Wiederherstellung bestätigen"</string>
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Ermöglicht der App, die Benutzeroberfläche zur Bestätigung der vollständigen Sicherung zu starten. Kann nicht von jeder App verwendet werden."</string>
-    <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"nicht autorisierte Fenster anzeigen"</string>
+    <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"Nicht autorisierte Fenster anzeigen"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Ermöglicht der App die Erstellung von Fenstern, die von der Benutzeroberfläche des internen Systems verwendet werden. Nicht für normale Apps vorgesehen."</string>
     <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"Über andere Apps ziehen"</string>
     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Ermöglicht der App, über andere Apps oder Teile der Benutzeroberfläche zu zeichnen. Dies kann sich auf die Oberfläche in jeder App auswirken oder die erwartete Darstellung in anderen Apps verändern."</string>
@@ -397,7 +397,7 @@
     <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"Beim Start ausführen"</string>
     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Ermöglicht der App, sich selbst zu starten, sobald das System gebootet wurde. Dadurch kann es länger dauern, bis das Tablet gestartet wird, und durch die ständige Aktivität der App wird die gesamte Leistung des Tablets beeinträchtigt."</string>
     <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Ermöglicht der App, sich selbst zu starten, sobald das System gebootet wurde. Dadurch kann es länger dauern, bis das Telefon gestartet wird, und durch die ständige Aktivität der App wird die gesamte Leistung des Telefons beeinträchtigt."</string>
-    <string name="permlab_broadcastSticky" msgid="7919126372606881614">"dauerhaften Broadcast senden"</string>
+    <string name="permlab_broadcastSticky" msgid="7919126372606881614">"Dauerhaften Broadcast senden"</string>
     <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Ermöglicht der App, weiluerhafte Broadcasts zu senden, die auch nach Ende des Broadcasts bestehen bleiben. Ein zu intensiver Einsatz kann das Tablet langsam oder instabil machen, weil zu viel Arbeitsspeicher belegt wird."</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Ermöglicht der App, weiluerhafte Broadcasts zu senden, die auch nach Ende des Broadcasts bestehen bleiben. Ein zu intensiver Einsatz kann das Telefon langsam oder instabil machen, weil zu viel Arbeitsspeicher belegt wird."</string>
     <string name="permlab_readContacts" msgid="8348481131899886131">"Kontakte lesen"</string>
@@ -406,7 +406,7 @@
     <string name="permlab_writeContacts" msgid="5107492086416793544">"Meine Kontakte ändern"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Ermöglicht der App, Daten zu Kontakten, die auf Ihrem Tablet gespeichert sind, zu ändern, einschließlich der Häufigkeit, mit der Sie bestimmte Kontakte angerufen, diesen E-Mails gesendet oder anderweitig mit ihnen kommuniziert haben. Die Berechtigung erlaubt Apps, Kontaktdaten zu löschen."</string>
     <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Ermöglicht der App, Daten zu Kontakten, die auf Ihrem Telefon gespeichert sind, zu ändern, einschließlich der Häufigkeit, mit der Sie bestimmte Kontakte angerufen, diesen E-Mails gesendet oder anderweitig mit ihnen kommuniziert haben. Die Berechtigung erlaubt Apps, Kontaktdaten zu löschen."</string>
-    <string name="permlab_readCallLog" msgid="3478133184624102739">"Anrufprotokoll lesen"</string>
+    <string name="permlab_readCallLog" msgid="3478133184624102739">"Anrufliste lesen"</string>
     <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Ermöglicht der App, die Anrufliste Ihres Tablets zu lesen, einschließlich der Daten über ein- und ausgehende Anrufe. Die Berechtigung erlaubt Apps, Ihre Anruflistendaten zu speichern, und schädliche Apps können diese Daten ohne Ihr Wissen weiterleiten."</string>
     <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Ermöglicht der App, die Anrufliste Ihres Telefons zu lesen, einschließlich der Daten über ein- und ausgehende Anrufe. Die Berechtigung erlaubt Apps, Ihre Anruflistendaten zu speichern, und schädliche Apps können diese Daten ohne Ihr Wissen weiterleiten."</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"Anrufprotokoll bearbeiten"</string>
@@ -432,9 +432,9 @@
     <string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"Ermöglicht der App, auf zusätzliche Standortanbieterbefehle zuzugreifen. Damit könnte die App die Funktionsweise von GPS oder anderen Standortquellen beeinträchtigen."</string>
     <string name="permlab_installLocationProvider" msgid="6578101199825193873">"Berechtigung zur Installation eines Standortanbieters"</string>
     <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"Erstellen von simulierten Standortquellen für Testzwecke oder Installation eines neuen Standortanbieters. Damit kann die App den von anderen Standortquellen wie GPS oder Standortanbietern zurückgegebenen Standort und/oder Status überschreiben."</string>
-    <string name="permlab_accessFineLocation" msgid="1191898061965273372">"genauer Standort (GPS- und netzwerkbasiert)"</string>
+    <string name="permlab_accessFineLocation" msgid="1191898061965273372">"Genauer Standort (GPS- und netzwerkbasiert)"</string>
     <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Ermöglicht der App, Ihre genaue Position anhand von GPS-Daten (Global Positioning System) oder über Netzwerkstandortquellen wie Sendemasten oder WLAN zu ermitteln. Diese Standortdienste müssen auf Ihrem Gerät verfügbar und aktiviert sein, damit die App sie verwenden kann. Apps können Ihren Standort anhand dieser Daten ermitteln und verbrauchen eventuell zusätzliche Akkuleistung."</string>
-    <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"ungefährer Standort (netzwerkbasiert)"</string>
+    <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"Ungefährer Standort (netzwerkbasiert)"</string>
     <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Ermöglicht der App, Ihren ungefähren Standort zu ermitteln. Diese Standortangabe stammt von Standortdiensten, die Netzwerkstandortquellen wie etwa Sendemasten oder WLAN verwenden. Diese Standortdienste müssen auf Ihrem Gerät verfügbar und aktiviert sein, damit die App sie verwenden kann. Apps können Ihren ungefähren Standort anhand dieser Daten ermitteln."</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"Auf SurfaceFlinger zugreifen"</string>
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Ermöglicht der App, die systemnahen SurfaceFlinger-Funktionen zu verwenden"</string>
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Benachrichtigungslautstärke"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Standard-Klingelton"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standard-Klingelton (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Lautlos"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Keine"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Klingeltöne"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Unbekannter Klingelton"</string>
   <plurals name="wifi_available">
@@ -1127,7 +1127,7 @@
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Das Telefon wird vorübergehend vom WLAN getrennt, während eine Verbindung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> hergestellt wird."</string>
     <string name="select_character" msgid="3365550120617701745">"Zeichen einfügen"</string>
-    <string name="sms_control_title" msgid="7296612781128917719">"Kurznachrichten werden gesendet"</string>
+    <string name="sms_control_title" msgid="7296612781128917719">"SMS werden gesendet"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sendet eine große Anzahl SMS. Möchten Sie zulassen, dass die App weiterhin Nachrichten sendet?"</string>
     <string name="sms_control_yes" msgid="3663725993855816807">"Zulassen"</string>
     <string name="sms_control_no" msgid="625438561395534982">"Nicht zulassen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index fd19ea3..8b918c6 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Ένταση ήχου ειδοποιήσεων"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Προεπιλεγμένος ήχος κλήσης"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Προεπιλεγμένος ήχος κλήσης (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Σίγαση"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Κανένας"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ήχοι κλήσης"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Άγνωστος ήχος κλήσης"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index d4ee1e8..716f0e2 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1095,7 +1095,8 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Notification volume"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Default ringtone"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Default ringtone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Silent"</string>
+    <!-- no translation found for ringtone_silent (7937634392408977062) -->
+    <skip />
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtones"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Unknown ringtone"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 79163fa..22f429d 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volumen de notificación"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Tono de llamada predeterminado"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Tono de llamada predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Silencioso"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Ninguno"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos de llamada"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Tono de llamada desconocido"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 0216cde..d695225 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volumen de notificaciones"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Tono predeterminado"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Tono predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Silencio"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Ninguno"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Tono desconocido"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index bc6c5dc..5536457 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Teatise helitugevus"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Vaikehelin"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Vaikehelin (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Hääletu"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Puudub"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Helinad"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Tundmatu helin"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index a81b53a..77d9a50 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"میزان صدای اعلان"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"آهنگ زنگ پیش‌فرض"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"آهنگ زنگ پیش‌فرض (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"ساکت"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"هیچکدام"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"آهنگ‌های زنگ"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"آهنگ زنگ ناشناس"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 8acf9c6..47d865f 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Ilmoituksen äänenvoimakkuus"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Oletussoittoääni"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Oletussoittoääni (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Äänetön"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Ei mitään"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Soittoäänet"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Tuntematon soittoääni"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index bb39c1e..97fcecf 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume des notifications"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Sonnerie par défaut"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Sonnerie par défaut (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Silencieux"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Aucune"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Sonneries"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Sonnerie inconnue"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index d2234ec..a90fbd9 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"सूचना वॉल्‍यूम"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"डिफ़ॉल्‍ट रिंगटोन"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"डिफ़ॉल्‍ट रिंगटोन (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"मौन"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"कोई नहीं"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"रिंगटोन"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"अज्ञात रिंगटोन"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 4ce9d74..a111c4b 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Glasnoća obavijesti"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Zadana melodija zvona"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Zadana melodija zvona (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Bešumno"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Nijedan"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Melodije zvona"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nepoznata melodija zvona"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 7e0035b..2ee3c37 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Értesítés hangereje"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Alapértelmezett csengőhang"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Alapértelmezett csengőhang (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Néma"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Egyik sem"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Csengőhangok"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Ismeretlen csengőhang"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index a4c6bc2..1c1af24 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -417,9 +417,9 @@
     <string name="permlab_writeProfile" msgid="907793628777397643">"ubah kartu kontak Anda"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Memungkinkan aplikasi mengubah atau menambah informasi profil pribadi yang tersimpan di perangkat Anda, seperti nama dan informasi kontak. Ini berarti aplikasi tersebut dapat mengenali Anda dan mengirim informasi profil Anda ke orang lain."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"membaca aliran sosial Anda"</string>
-    <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Memungkinkan aplikasi mengakses dan menyinkronkan pembaruan sosial dari Anda dan teman. Hati-hati ketika berbagi informasi -- izin ini memungkinkan aplikasi membaca komunikasi antara Anda dan teman di jaringan sosial, terlepas dari kerahasiaan. Catatan: izin ini tidak dapat diberlakukan di semua jaringan sosial."</string>
+    <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Memungkinkan aplikasi mengakses dan menyinkronkan pembaruan sosial dari Anda dan teman. Hati-hati ketika berbagi informasi -- izin ini memungkinkan aplikasi membaca komunikasi antara Anda dan teman di jejaring sosial, terlepas dari kerahasiaan. Catatan: izin ini tidak dapat diberlakukan di semua jejaring sosial."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"menulis ke aliran sosial Anda"</string>
-    <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"Memungkinkan aplikasi menampilkan pembaruan sosial dari teman Anda. Berhati-hatilah saat berbagi informasi -- izin ini memungkinkan aplikasi menghasilkan pesan yang mungkin kelihatannya berasal dari seorang teman. Catatan: izin ini tidak dapat diberlakukan di semua jaringan sosial."</string>
+    <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"Memungkinkan aplikasi menampilkan pembaruan sosial dari teman Anda. Berhati-hatilah saat berbagi informasi -- izin ini memungkinkan aplikasi menghasilkan pesan yang mungkin kelihatannya berasal dari seorang teman. Catatan: izin ini tidak dapat diberlakukan di semua jejaring sosial."</string>
     <string name="permlab_readCalendar" msgid="5972727560257612398">"baca acara kalender serta informasi rahasia"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Memungkinkan aplikasi membaca semua acara kalender yang tersimpan di tablet Anda, termasuk milik teman atau rekan kerja. Izin ini memungkinkan aplikasi berbagi atau menyimpan data kalender Anda, terlepas dari kerahasiaan atau sensitivitas."</string>
     <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Memungkinkan aplikasi membaca semua acara kalender yang tersimpan di ponsel Anda, termasuk milik teman atau rekan kerja. Izin ini memungkinkan aplikasi berbagi atau menyimpan data kalender Anda, terlepas dari kerahasiaan atau sensitivitas."</string>
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume pemberitahuan"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Nada dering default"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Nada dering default (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Senyap"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Tidak Ada"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Nada dering"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nada dering tidak dikenal"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index ab57809..7c160d7 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume notifiche"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Suoneria predefinita"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Suoneria predefinita (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Silenzioso"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Nessuna"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Suonerie"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Suoneria sconosciuta"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 76a2daa..1b5c661 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1047,7 +1047,7 @@
     <string name="chooseUsbActivity" msgid="6894748416073583509">"בחר יישום עבור התקן ה-USB"</string>
     <string name="noApplications" msgid="2991814273936504689">"אין יישומים שיכולים לבצע פעולה זו."</string>
     <string name="aerr_title" msgid="1905800560317137752"></string>
-    <string name="aerr_application" msgid="932628488013092776">"לצערנו, פעולת ה<xliff:g id="APPLICATION">%1$s</xliff:g> הופסקה."</string>
+    <string name="aerr_application" msgid="932628488013092776">"לצערנו, פעולת <xliff:g id="APPLICATION">%1$s</xliff:g> הופסקה."</string>
     <string name="aerr_process" msgid="4507058997035697579">"לצערנו, התהליך <xliff:g id="PROCESS">%1$s</xliff:g> הופסק."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
     <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> אינו מגיב."\n\n"תרצה לסגור אותו?"</string>
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"עוצמת קול של התראות"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"רינגטון ברירת מחדל"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"רינגטון ברירת מחדל (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"שקט"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"ללא"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"רינגטונים"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"רינגטון לא ידוע"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 535a288..6b7eb01 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"通知音量"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"プリセット着信音"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"端末の基本着信音(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"サイレント"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"なし"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"着信音"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"不明な着信音"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index ff0f5d4..8346fee 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -570,9 +570,9 @@
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"화면 잠금 사용 중지"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"앱이 키 잠금 및 관련 비밀번호 보안을 사용중지할 수 있도록 허용합니다. 예를 들어, 휴대전화가 수신전화를 받을 때 키 잠금을 사용중지했다가 통화가 끝나면 키 잠금을 다시 사용할 수 있습니다."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"동기화 설정 읽기"</string>
-    <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"앱이 계정의 동기화 설정을 읽을 수 있도록 허용합니다. 예를 들어, 계정에서 피플 앱을 동기화할지 여부를 확인할 수 있습니다."</string>
+    <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"앱이 계정의 동기화 설정을 읽을 수 있도록 허용합니다. 예를 들어, 계정에서 주소록 앱을 동기화할지 여부를 확인할 수 있습니다."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"동기화 사용 및 사용 중지 전환"</string>
-    <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"앱이 계정의 동기화 설정을 수정할 수 있도록 허용합니다. 예를 들어, 계정에서 피플 앱을 동기화할 목적으로 앱이 사용될 수 있습니다."</string>
+    <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"앱이 계정의 동기화 설정을 수정할 수 있도록 허용합니다. 예를 들어, 계정에서 주소록 앱을 동기화할 목적으로 앱이 사용될 수 있습니다."</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"동기화 통계 읽기"</string>
     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"앱이 동기화된 일정의 기록이나 동기화된 데이터의 양 등을 포함하여 계정의 동기화 통계를 읽을 수 있도록 허용합니다."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"가입된 피드 읽기"</string>
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"알림 볼륨"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"기본 벨소리"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"기본 벨소리(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"무음"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"없음"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"벨소리"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"알 수 없는 벨소리"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 0b25abe..25fc107 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Pranešimo apimtis"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Numatytasis skambėjimo tonas"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Numatytasis skambėjimo tonas (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Tylus"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Nėra"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Skambėjimo tonai"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nežinomas skambėjimo tonas"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 3ef2f61..3f85435 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Paziņojumu skaļums"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Noklusējuma zvana signāls"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Noklusējuma zvana signāls (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Klusums"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Nav"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Zvana signāli"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nezināms zvana signāls"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-mcc286/config.xml b/core/res/res/values-mcc286/config.xml
new file mode 100755
index 0000000..d99d051
--- /dev/null
+++ b/core/res/res/values-mcc286/config.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds.  DO NOT TRANSLATE. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- National Language Identifier codes for the following two config items.
+         (from 3GPP TS 23.038 V9.1.1 Table 6.2.1.2.4.1):
+          0  - reserved
+          1  - Turkish
+          2  - Spanish (single shift table only)
+          3  - Portuguese
+          4  - Bengali
+          5  - Gujarati
+          6  - Hindi
+          7  - Kannada
+          8  - Malayalam
+          9  - Oriya
+         10  - Punjabi
+         11  - Tamil
+         12  - Telugu
+         13  - Urdu
+         14+ - reserved -->
+
+    <!-- National language single shift tables to enable for SMS encoding.
+         Decoding is always enabled. 3GPP TS 23.038 states that this feature
+         should not be enabled until a formal request is issued by the relevant
+         national regulatory body. Array elements are codes from the table above.
+         Example 1: devices sold in Turkey must include table 1 to conform with
+           By-Law Number 27230. (http://www.btk.gov.tr/eng/pdf/2009/BY-LAW_SMS.pdf)
+         Example 2: devices sold in India should include tables 4 through 13
+           to enable use of the new Release 9 tables for Indic languages. -->
+    <integer-array name="config_sms_enabled_single_shift_tables"><item>1</item></integer-array>
+
+    <!-- National language locking shift tables to enable for SMS encoding.
+         Decoding is always enabled. 3GPP TS 23.038 states that this feature
+         should not be enabled until a formal request is issued by the relevant
+         national regulatory body. Array elements are codes from the table above.
+         Example 1: devices sold in Turkey must include table 1 after the
+           Turkish Telecommunication Authority requires locking shift encoding
+           to be enabled (est. July 2012). (http://www.btk.gov.tr/eng/pdf/2009/BY-LAW_SMS.pdf)
+           See also: http://www.mobitech.com.tr/tr/ersanozturkblog_en/index.php?entry=entry090223-160014
+         Example 2: devices sold in India should include tables 4 through 13
+         to enable use of the new Release 9 tables for Indic languages. -->
+    <!-- <integer-array name="config_sms_enabled_locking_shift_tables"></integer-array> -->
+
+</resources>
diff --git a/core/res/res/values-mcc450/config.xml b/core/res/res/values-mcc450/config.xml
new file mode 100644
index 0000000..2a2bd76
--- /dev/null
+++ b/core/res/res/values-mcc450/config.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, 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>
+
+    <!-- Whether camera shutter sound is forced or not  (country specific). -->
+    <bool name="config_camera_sound_forced">true</bool>
+
+</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 4346a39..9d29e3c 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Kelantangan pemberitahuan"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Nada dering lalai"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Nada dering lalai (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Senyap"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Tiada"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Nada dering"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nada dering tidak diketahui"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index a5e473b..b9291a0 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Varslingsvolum"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Standard ringetone"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standard ringetone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Stille"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringetoner"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Ukjent ringetone"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index ec6d073..4e38a7d 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Meldingsvolume"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Standaardbeltoon"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standaardbeltoon (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Stil"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Geen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Beltonen"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Onbekende beltoon"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 41e1c25..8ab9d52 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Głośność powiadomień"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Dzwonek domyślny"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Dzwonek domyślny (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Cichy"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Brak"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Dzwonki"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nieznany dzwonek"</string>
   <plurals name="wifi_available">
@@ -1364,7 +1364,7 @@
     <string name="data_usage_limit_body" msgid="3317964706973601386">"Dotknij, aby włączyć."</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Przekroczono limit danych 2G/3G"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Przekroczono limit danych 4G"</string>
-    <string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Przekroczono limit danych komór."</string>
+    <string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Przekroczenie limitu danych"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Przekroczono limit danych Wi-Fi"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> ponad określony limit"</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Dane w tle są ograniczone"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 50adccc..d8652cd 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume de notificações"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Toque predefinido"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Toque predefinido (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Silencioso"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Nada"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Toque desconhecido"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 1ba453c..6e61195 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume da notificação"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Toque padrão"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Toque padrão (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Silencioso"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Nenhum"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Toque desconhecido"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 79997db..8b8f32b 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1701,7 +1701,8 @@
     <skip />
     <string name="ringtone_default" msgid="3789758980357696936">"Tun da scalin predefinì"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Tun da scalin predefinì (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Silenzius"</string>
+    <!-- no translation found for ringtone_silent (7937634392408977062) -->
+    <skip />
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tuns da scalin"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Tun da scalin nunenconuschent"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 000d2cc..82d7532 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volum notificare"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Ton de apel prestabilit"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Ton de apel prestabilit (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Silenţios"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Niciunul"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonuri de apel"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Ton de apel necunoscut"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 1a6138c..89b0e06 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Громкость уведомлений"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Мелодия по умолчанию"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"По умолчанию (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Без звука"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Без звука"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодии"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Неизвестная мелодия"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 6eb0f18..8d1250e 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Hlasitosť upozornení"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Predvolený vyzváňací tón"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Predvolený vyzváňací tón (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Tichý"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Žiadny"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Vyzváňacie tóny"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Neznámy vyzváňací tón"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index bef7237..508156b 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Glasnost obvestila"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Privzeta melodija zvonjenja"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Privzeta melodija zvonjenja (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Tiho"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Brez"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Melodije zvonjenja"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Neznana melodija zvonjenja"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index bc4aae0..8b624af 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -996,7 +996,7 @@
     <string name="years" msgid="6881577717993213522">"годинe(а)"</string>
   <plurals name="duration_seconds">
     <item quantity="one" msgid="6962015528372969481">"1 секунда"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> сек"</item>
+    <item quantity="other" msgid="1886107766577166786">"Секунди: <xliff:g id="COUNT">%d</xliff:g>"</item>
   </plurals>
   <plurals name="duration_minutes">
     <item quantity="one" msgid="4915414002546085617">"1 минут"</item>
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Јачина звука обавештења"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Подразумевани звук звона"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Подразумевани звук звона (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Нечујно"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Без"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Звукови звона"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Непознати звук звона"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 9f1edc9..b8de45c 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Meddelandevolym"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Standardringsignal"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standardringsignal (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Tyst"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringsignaler"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Okänd ringsignal"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 4b6758a4..51fc346 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Sauti ya arifa"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Toni mlio chaguo-msingi"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Toni mlio chaguo-msingi  (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Kimya"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Hamna"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Toni za mlio"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Mlio amabo haujulikani"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 218bdd7..5aa1cbe 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"ระดับเสียงของการแจ้งเตือน"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"เสียงเรียกเข้าเริ่มต้น"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"เสียงเรียกเข้าเริ่มต้น (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"ปิดเสียง"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"ไม่มี"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"เสียงเรียกเข้า"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"ไม่ทราบเสียงเรียกเข้า"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 1578e7d..092ce73 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume ng notification"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Default na ringtone"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Default na ringtone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Tahimik"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Wala"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Mga Ringtone"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Hindi kilalang ringtone"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index d8ca187..d335479 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Bildirim ses düzeyi"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Varsayılan zil sesi"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Varsayılan zil sesi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Sessiz"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Yok"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Zil sesleri"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Bilinmeyen zil sesi"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 6ccc115..904adae 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Гучність сповіщення"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Мелодія за умовч."</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Мелодія за умовч. (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Без звуку"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Немає"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодії"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Невідома мелодія"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 2afbb49..01b76c3 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Âm lượng thông báo"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Nhạc chuông mặc định"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Nhạc chuông mặc định (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Im lặng"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Không"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Nhạc chuông"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nhạc chuông không xác định"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 6d8d220..bc7df02 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"通知音量"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"默认铃声"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"默认铃声(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"静音"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"无"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"铃声"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"未知铃声"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 7f51b51..21c4a64 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"通知音量"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"預設鈴聲"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"預設鈴聲 (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"靜音"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"無"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"鈴聲"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"未知的鈴聲"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 2c7a884..6dab9ff 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1095,7 +1095,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Ivolumu yesaziso"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Iringithoni emisiwe"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Iringithoni ezenzakalelayo <xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>"</string>
-    <string name="ringtone_silent" msgid="4440324407807468713">"Thulile"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Akunalutho"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Amaringithoni"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Iringithoni engaziwa"</string>
   <plurals name="wifi_available">
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 460a811..7ef501f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1031,4 +1031,7 @@
         <item>150</item>
         <item>100</item>
     </integer-array>
+
+    <!-- Flag indicating if the speed up audio on mt call code should be executed -->
+    <bool name="config_speed_up_audio_on_mt_calls">false</bool>
 </resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 547a192..21bae04 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -79,4 +79,5 @@
   <item type="id" name="action_menu_presenter" />
   <item type="id" name="overflow_menu_presenter" />
   <item type="id" name="popup_submenu_presenter" />
+  <item type="id" name="action_bar_spinner" />
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 592ebb7..4c3644c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -218,6 +218,7 @@
   <java-symbol type="id" name="sms_short_code_remember_choice_checkbox" />
   <java-symbol type="id" name="sms_short_code_remember_undo_instruction" />
   <java-symbol type="id" name="breadcrumb_section" />
+  <java-symbol type="id" name="action_bar_spinner" />
 
   <java-symbol type="attr" name="actionModeShareDrawable" />
   <java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -277,6 +278,7 @@
   <java-symbol type="bool" name="config_safe_media_volume_enabled" />
   <java-symbol type="bool" name="config_camera_sound_forced" />
   <java-symbol type="bool" name="config_dontPreferApn" />
+  <java-symbol type="bool" name="config_speed_up_audio_on_mt_calls" />
 
   <java-symbol type="integer" name="config_cursorWindowSize" />
   <java-symbol type="integer" name="config_longPressOnPowerBehavior" />
diff --git a/data/sounds/AudioPackage10.mk b/data/sounds/AudioPackage10.mk
index a930a54..90d8eaa 100755
--- a/data/sounds/AudioPackage10.mk
+++ b/data/sounds/AudioPackage10.mk
@@ -29,6 +29,7 @@
 	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \
diff --git a/data/sounds/effects/ogg/LowBattery.ogg b/data/sounds/effects/ogg/LowBattery.ogg
index 710e385..ab9eba3 100644
--- a/data/sounds/effects/ogg/LowBattery.ogg
+++ b/data/sounds/effects/ogg/LowBattery.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/WirelessChargingStarted.ogg b/data/sounds/effects/ogg/WirelessChargingStarted.ogg
new file mode 100644
index 0000000..66f6cd2
--- /dev/null
+++ b/data/sounds/effects/ogg/WirelessChargingStarted.ogg
Binary files differ
diff --git a/docs/html/google/google_toc.cs b/docs/html/google/google_toc.cs
index b6e26e3..b2051d1 100644
--- a/docs/html/google/google_toc.cs
+++ b/docs/html/google/google_toc.cs
@@ -45,32 +45,47 @@
     </ul>
   </li>
 
+
   <li class="nav-section">
     <div class="nav-section-header"><a href="<?cs var:toroot ?>google/play/billing/index.html">
       <span class="en">Google Play In-app Billing</span></a>
     </div>
     <ul>
-          <li><a href="<?cs var:toroot?>google/play/billing/billing_overview.html">
-              <span class="en">In-app Billing Overview</span></a>
-          </li>
-          <li><a href="<?cs var:toroot?>google/play/billing/billing_integrate.html">
-              <span class="en">Implementing In-app Billing</span></a>
-          </li>
-          <li><a href="<?cs var:toroot?>google/play/billing/billing_subscriptions.html">
-              <span class="en">Subscriptions</span></a>
-          </li>
-          <li><a href="<?cs var:toroot?>google/play/billing/billing_best_practices.html">
+      <li><a href="<?cs var:toroot?>google/play/billing/billing_overview.html">
+              <span class="en">Overview</span></a>
+      </li>
+      <li class="nav-section"><div class="nav-section-header"><a href="<?cs var:toroot?>google/play/billing/api.html">
+              <span class="en">Version 3 API</span></a></div>
+              <ul>
+              <li><a href="<?cs var:toroot?>google/play/billing/billing_integrate.html">
+              <span class="en">Implementing the API</span></a></li>
+              <li><a href="<?cs var:toroot?>google/play/billing/billing_reference.html">
+              <span class="en">Reference</span></a></li>
+              </ul>
+      </li>
+      <li class="nav-section"><div class="nav-section-header"><a href="<?cs var:toroot?>google/play/billing/v2/api.html">
+              <span class="en">Version 2 API</span></a></div>
+              <ul>
+              <li><a href="<?cs var:toroot?>google/play/billing/v2/billing_integrate.html">
+              <span class="en">Implementing the API</span></a></li>
+              <li><a href="<?cs var:toroot?>google/play/billing/v2/billing_subscriptions.html">
+              <span class="en">Subscriptions</span></a></li>
+              <li><a href="<?cs var:toroot?>google/play/billing/v2/billing_reference.html">
+              <span class="en">Reference</span></a></li>
+              </ul>
+      </li>
+      <li><a href="<?cs var:toroot?>google/play/billing/billing_best_practices.html">
               <span class="en">Security and Design</span></a>
-          </li>
-          <li><a href="<?cs var:toroot?>google/play/billing/billing_testing.html">
+      </li>
+      <li><a href="<?cs var:toroot?>google/play/billing/billing_testing.html">
               <span class="en">Testing In-app Billing</span></a>
-          </li>
-          <li><a href="<?cs var:toroot?>google/play/billing/billing_admin.html">
+      </li>
+      <li><a href="<?cs var:toroot?>google/play/billing/billing_admin.html">
               <span class="en">Administering In-app Billing</span></a>
-          </li>
-          <li><a href="<?cs var:toroot?>google/play/billing/billing_reference.html">
-              <span class="en">Reference</span></a>
-          </li>
+      </li>
+      <li><a href="<?cs var:toroot?>google/play/billing/versions.html">
+              <span class="en">Version Notes</span></a>
+      </li>
     </ul>
   </li>
 
@@ -86,11 +101,9 @@
       <li><a href="<?cs var:toroot ?>google/play/publishing/multiple-apks.html">
           <span class="en">Multiple APK Support</span></a>
       </li>
-
       <li><a href="<?cs var:toroot ?>google/play/expansion-files.html">
           <span class="en">APK Expansion Files</span></a>
       </li>
-
       <li class="nav-section">
         <div class="nav-section-header"><a href="<?cs var:toroot ?>google/play/licensing/index.html">
           <span class="en">Application Licensing</span></a>
diff --git a/docs/html/google/play/billing/api.jd b/docs/html/google/play/billing/api.jd
new file mode 100644
index 0000000..9091f51
--- /dev/null
+++ b/docs/html/google/play/billing/api.jd
@@ -0,0 +1,116 @@
+page.title=In-app Billing Version 3
+parent.title=In-app Billing
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+  <h2>Topics</h2>
+  <ol>
+    <li><a href="#producttypes">Product Types</a>
+       <ol>
+       <li><a href="#managed">Managed In-app Products</a><li>
+       </ol>
+    </li>
+    <li><a href="#purchase">Purchasing Items</a></li>
+    <li><a href="#consume">Consuming Items</a>
+       <ol>
+       <li><a href="#consumetypes">Non-consumable and Consumable Items</a><li>
+       <li><a href="#managingconsumables">Managing Consumable Purchases</a><li>
+       </ol>
+    </li>
+    <li><a href="#caching">Local Caching</a></li>
+  </ol>
+  
+  <h2>Reference</h2>
+  <ol>
+    <li><a href="{@docRoot}google/play/billing/billing_reference.html">In-app Billing
+    Reference (V3)</a></li>
+  </ol>
+  
+ <h2>See also</h2>
+  <ol>
+    <li><a href="{@docRoot}training/in-app-billing/index.html">Selling In-app Products</a></li>
+  </ol>  
+</div>
+</div>
+
+<p>The In-app Billing Version 3 API makes it easier for you to integrate In-app Billing into your applications. The features in this version include improved synchronous purchase flow, APIs to let you easily track ownership of consumable goods, and local caching of in-app purchase data.</p>
+
+<h2 id="producttypes">Product Types</h2>
+<p>You define your products using the Google Play Developer Console, including product type, SKU, price, description, and so on. For more information, see <a
+href="{@docRoot}google/play/billing/billing_admin.html">Administering In-app Billing</a>. The Version 3 API only supports the managed in-app product type.</p>
+<h3 id="managed">Managed In-app Products</h3>
+<p>Managed in-app products are items that have their ownership information tracked and managed by Google Play. When a user purchases a managed in-app item, Google Play stores the purchase information for each item on a per-user basis. This enables you to later query Google Play at any time to restore the state of the items a specific user has purchased. This information is persistent on the Google Play servers even if the user uninstalls the application or if they change devices.</p>
+<p>If you are using the Version 3 API, you can also consume managed items within your application. You would typically implement consumption for items that can be purchased multiple times (such as in-game currency, fuel, or magic spells). Once purchased, a managed item cannot be purchased again until you consume the item, by sending a consumption request to Google Play. To learn more about in-app product consumption, see <a href="#consume">Consuming Items</a></p>
+
+
+<h2 id="purchase">Purchasing Items</h2>
+
+<div class="figure" style="width:430px">
+<img src="{@docRoot}images/in-app-billing/v3/iab_v3_purchase_flow.png" id="figure1" height="530"/>
+<p class="img-caption">
+  <strong>Figure 1.</strong> The basic sequence for a purchase request.
+</p>
+</div>
+
+<p>A typical purchase flow with the Version 3 API is as follows:
+<ol>
+<li>Your application sends a {@code isBillingSupported} request to Google Play to determine that the target version of the In-app Billing API that you are using is supported.  </li>
+<li>When your application starts or user logs in, it's good practice to check with Google Play to determine what items are owned by the user. To query the user's in-app purchases, send a {@code getPurchases} request. If the request is successful, Google Play returns a {@code Bundle} containing a list of product IDs of the purchased items, a list of the individual purchase details, and a list of the signatures for the purchases.</li>
+<li>Usually, you'll want to inform the user of the products that are available for purchase. To query the details of the in-app products that you defined in Google Play, your application can send a {@code getSkuDetails} request. You must specify a list of product IDs in the query request. If the request is successful, Google Play returns a {@code Bundle} containing product details including the product’s price, title, description, and the purchase type. 
+</li>
+<li>If an in-app product is not owned by the user, you can initiate a purchase for it. To start a purchase request, your application sends a {@code getBuyIntent} request, specifying the product ID of the item to purchase, along with other parameters. You should record the product ID when you create a new in-app product in the Developer Console.
+  <ol type="a">
+  <li>Google Play returns a {@code Bundle} that contains a {@code PendingIntent} which you application uses to start the checkout UI for the purchase.</li>
+  <li>Your application launches the pending intent by calling the {@code startIntentSenderForResult} method.</li>
+  <li>When the checkout flow finishes (that is, the user successfully purchases the item or cancels the purchase), Google Play sends a response {@code Intent} to your {@code onActivityResult} method. The result code of the {@code onActivityResult} has a result code that indicates whether the purchase was successful or canceled. The response {@code Intent} contains information about the purchased item, including a {@code purchaseToken} String that is generated by Google Play to uniquely identify this purchase transaction. The {@code Intent} also contains the signature of the purchase, signed with your private developer key.</li> 
+  </ol>
+</li>
+</ol>
+</p>
+<p>To learn more about the Version 3 API calls and server responses, see <a href="{@docRoot}google/play/billing/billing_reference.html">In-app Billing Reference</a>.</p>
+
+<h2 id="consume">Consuming Items</h2>
+<p>You can use the consumption mechanism to track the user's ownership of in-app products.</p>
+<p>In Version 3, all in-app products are managed. This means that the user's ownership of all in-app item purchases is maintained by Google Play, and your application can query the user's purchase information when needed. When the user successfully purchases an item, that purchase is recorded in Google Play. Once an item is purchased, it is considered to be "owned". Items in the "owned" state cannot be purchased from Google Play. You must send a consumption request for the "owned" item before Google Play makes it available for purchase again. Consuming the item reverts it to the "unowned" state, and discards the previous purchase data.</p>
+<div class="figure" style="width:420px">
+<img src="{@docRoot}images/in-app-billing/v3/iab_v3_consumption_flow.png" id="figure2" height="300"/>
+<p class="img-caption">
+  <strong>Figure 2.</strong> The basic sequence for a consumption request.
+</p>
+</div>
+<p>To retrieve the list of product's owned by the user, your application sends a {@code getPurchases} call to Google Play. Your application can make a consumption request by sending a {@code consumePurchase} call. In the request argument, you must specify the item's unique {@code purchaseToken} String that you obtained from Google Play when it was purchased. Google Play returns a status code indicating if the consumption was recorded successfully.</p>
+
+<h3 id="consumetypes">Non-consumable and Consumable Items</h3>
+<p>It's up to you to decide if you want to handle your in-app products as non-consumable or consumable items.</p>
+<dl>
+<dt>Non-consumable Items</dt>
+<dd>Typically, you would not implement consumption for items that can only be purchased once in your application and provide a permanent benefit. Once purchased, these items will be permanently associated to the user's Google account. An example of a non-consumable item is a premium upgrade or a level pack.</dd>
+<dt>Consumable items</dt>
+<dd>In contrast, you can implement consumption for items that can be made available for purchase multiple times. Typically, these items provide certain temporary effects. For example, the user's in-game character might gain life points or gain extra gold coins in their inventory. Dispensing the benefits or effects of the purchased item in your application is called <em>provisioning</em> the in-app product. You are responsible for controlling and tracking how in-app products are provisioned to the users.
+<p class="note"><strong>Important:</strong> Before provisioning the consumable item in your application, you must send a consumption request to Google Play and receive a successful response indicating that the consumption was recorded.</p>
+</dd>
+</dl>
+<h3 id="managingconsumables">Managing consumable purchases in your application</h3>
+<p>Here is the basic flow for purchasing a consumable item:</p>
+<ol>
+<li>Launch a purchase flow with a {@code getBuyIntent} call</li>
+<li>Get a response {@code Bundle}from Google Play indicating if the purchase completed successfully.</li>
+<li>If the purchase was successful, consume the purchase by making a {@code consumePurchase} call.</li>
+<li>Get a response code from Google Play indicating if the consumption completed successfully.</li>
+<li>If the consumption was successful, provision the product in your application.</li>
+</ol>
+<p>Subsequently, when the user starts up or logs in to your application, you should check if the user owns any outstanding consumable items; if so, make sure to consume and provision those items. Here's the recommended application startup flow if you implement consumable items in your application:</p>
+<ol>
+<li>Send a {@code getPurchases} request to query the owned items for the user.</li>
+<li>If there are any consumable items, consume the items by calling {@code consumePurchase}. This step is necessary because the application might have completed the purchase order for the consumable item, but stopped or got disconnected before the application had the chance to send a consumption request.</li>
+<li>Get a response code from Google Play indicating if the consumption completed successfully.</li>
+<li>If the consumption was successful, provision the product in your application.</li>
+</ol>
+
+<h2 id="caching">Local Caching</h2>
+<p>Because the Google Play client now caches In-app Billing information locally on the device, you can use the Version 3 API to query for this information more frequently, for example through a {@code getPurchases} call. Unlike with previous versions of the API, many Version 3 API calls will be serviced through cache lookups instead of through a network connection to Google Play, which significantly speeds up the API's response time. </p>
+
+
diff --git a/docs/html/google/play/billing/billing_about.html b/docs/html/google/play/billing/billing_about.html
deleted file mode 100644
index 38616e6..0000000
--- a/docs/html/google/play/billing/billing_about.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<html>
-<head>
-<meta http-equiv="refresh"
-content="0;url=http://developer.android.com/google/play/billing/index.html">
-<title>Redirecting...</title>
-</head>
-<body>
-<p>You should be redirected. Please <a
-href="http://developer.android.com/google/play/billing/index.html">click
-here</a>.</p>
-</body>
-</html>
\ No newline at end of file
diff --git a/docs/html/google/play/billing/billing_admin.jd b/docs/html/google/play/billing/billing_admin.jd
index c0f46d0..cfa7a30 100644
--- a/docs/html/google/play/billing/billing_admin.jd
+++ b/docs/html/google/play/billing/billing_admin.jd
@@ -8,78 +8,66 @@
   <h2>In this document</h2>
   <ol>
     <li><a href="#billing-list-setup">Creating a Product List</a></li>
-    <li><a href="#billing-purchase-type">Choosing a Purchase Type</a></li>
+    <li><a href="#billing-purchase-type">Choosing a Product Type</a></li>
     <li><a href="#billing-testing-setup">Setting up Test Accounts</a></li>
     <li><a href="#billing-refunds">Handling Refunds</a></li>
     <li><a href="#billing-refunds">Working with Order Numbers</a></li>
     <li><a href="#billing-support">Where to Get Support</a></li>
   </ol>
-  <h2>Downloads</h2>
-  <ol>
-    <li><a href="{@docRoot}google/play/billing/billing_integrate.html#billing-download">Sample
-    Application</a></li>
+
   </ol>
   <h2>See also</h2>
   <ol>
     <li><a href="{@docRoot}google/play/billing/billing_overview.html">Overview of In-app
     Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_integrate.html">Implementing In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_best_practices.html">Security and
-    Design</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_testing.html">Testing In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_reference.html">In-app Billing
-    Reference</a></li>
   </ol>
 </div>
 </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>
+few administrative tasks, including setting up and maintaining your product list on the Google Play
+Developer Console, registering test accounts, and handling refunds when necessary.</p>
 
 <p>You must have a Google Play 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 Google Play, 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 a Google Play developer and set up a publisher account at the
-Google Play <a href="http://play.google.com/apps/publish">publisher site</a>. If you do not have a
-Google Checkout merchant account, you can register for one at the <a
+need to register for a new account to support in-app billing.</p>
+
+<p>If you do not have a publisher account, you can register as a Google Play
+developer and set up a publisher account at the <a
+href="http://play.google.com/apps/publish">Google Play Developer Console</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 Google Play publisher site provides a product list for each of your published
+<p>The Google Play Developer Console provides a product list for each of your published
 applications. You can sell an item using Google Play's 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>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
+link in applications listed in your developer 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>
+merchant account and the application's manifest includes the <code>com.android.vending.BILLING</code>
 permission.</p>
 
-<img src="{@docRoot}images/billing_product_list_entry.png" height="548" 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>A product list specifies items you are selling in an application &mdash; in-app products,
 subscriptions, or a combination of both. For each item, the product list contains information such as a product id,
-product description, and price (see figure 2). The product list stores only metadata about the items
+product description, and price. 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="658" id="figure2" />
-<p class="img-caption">
-  <strong>Figure 2.</strong> An application's product list.
+<div style="margin:1em;">
+<img style="border:1px solid #ddd;padding-bottom:.5em" src="{@docRoot}images/in-app-billing/billing_product_list.png" xheight="548" id="figure1" />
+<p class="img-caption" style="padding-left:.5em;">
+  <strong>Figure 1.</strong> You can access an application's product list by clicking the
+  <strong>In-App Products</strong> link in the main Apps navigation.
 </p>
+</div>
 
 <p>You can create a product list for any published application or any draft application that's been
-uploaded and saved to the Google Play site. However, you must have a Google Checkout merchant
+uploaded and saved to the Developer Console. 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
@@ -95,8 +83,8 @@
 you are using the multiple APK feature.</p>
 
 <p>You can add items to a product list two ways: you can add items one at a time by using the In-app
-Products UI (see figure 3), or you can add a batch of items by importing the items from a
-comma-separated values (CSV) file (see figure 2). Adding items one at a time is useful if your
+Products UI (see figure 2), or you can add a batch of items by importing the items from a
+comma-separated values (CSV) file. Adding items one at a time is useful if your
 application has only a few in-app items or you are adding only a few items to a
 product list for testing purposes. The CSV file method is useful if your application has a large
 number of in-app items.</p>
@@ -111,16 +99,17 @@
   <li><a href="http://play.google.com/apps/publish">Log in</a> to your publisher account.</li>
   <li>In the <strong>All Google Play 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 3), provide details about the item you are
+  <li>Click <strong>Add new product</strong> (see figure 2) and provide details about the item you are
   selling and then click <strong>Save</strong> or <strong>Publish</strong>.</li>
 </ol>
 
-<img src="{@docRoot}images/billing_list_form.png" height="840" id="figure3" />
-<p class="img-caption">
-  <strong>Figure 3.</strong> The Create New In-app Product page lets you add items to an
+<div style="margin:1em;">
+<img style="border:1px solid #ddd;padding-bottom:.5em;" src="{@docRoot}images/in-app-billing/billing_add.png" height="300" id="figure2" />
+<p class="img-caption" style="padding-left:.5em;">
+  <strong>Figure 2.</strong> The Add New Product page lets you add items to an
   application's product list.
 </p>
+</div>
 
 <p>You must enter the following information for each item in a product list:</p>
 <ul>
@@ -132,10 +121,10 @@
     <p>In addition, you cannot modify an item's product ID after it is created, and you cannot reuse
     a product ID.</p>
   </li>
-  <li><strong>Purchase Type</strong>
-    <p>The purchase type can be <strong>Managed per user account</strong>, <strong>Unmanaged</strong>,
-    or <strong>Subscription</strong>. You can never change an item's purchase type after you set it. For more
-    information, see <a href="#billing-purchase-type">Choosing a purchase type</a> later in this
+  <li><strong>Product Type</strong>
+    <p>The product type can be <strong>Managed per user account</strong>, <strong>Unmanaged</strong>,
+    or <strong>Subscription</strong>. You can never change an item's product type after you set it. For more
+    information, see <a href="#billing-purchase-type">Choosing a product type</a> later in this
     document.</p>
   </li>
   <li><strong>Publishing State</strong>
@@ -147,14 +136,14 @@
     href="{@docRoot}google/play/billing/billing_testing.html#billing-testing-real">Testing In-app
     Billing</a> for more information.</p>
   </li>
-  <li><strong>Language</strong>
-    <p>The language setting determines which languages are used to display the item title and
-    item description during checkout. A product list inherits its default language from the
-    parent application. You can add more languages by clicking <strong>add language</strong>. You
-    can also choose to have the title and description automatically translated from the default
-    language by selecting the <strong>Fill fields with auto translation</strong> checkbox (see
-    figure 4). If you do not use the auto translation feature, you must provide the translated
-    versions of the title and description.</p>
+  <li><strong>Languages and Translations</strong>
+    <p>You can provide localized titles and descriptions for your in-app
+    products using the Add Translations button. If you want Google Play to translate
+    your title and description for you, based on the title and description in the
+    default language, just click the languages that you want to offer. If you want
+    to provide custom translations in specific languages, you can also do that. By
+    default, an in-app product inherits its default 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
@@ -174,20 +163,22 @@
     page in the Google Play developer console.</p>
     <p>To specify prices in other currencies, you can manually enter the price for each
     currency or you can click <strong>Auto Fill</strong> and let Google Play do a one-time
-    conversion from your home currency to the currencies you are targeting (see figure 4).</p>
+    conversion from your home currency to the currencies you are targeting (see figure 3).</p>
     <p>For subscription items, note that you can not change the item's price once you have published it. </p>
   </li>
 </ul>
-<img src="{@docRoot}images/billing_list_form_2.png" height="1226" id="figure4" />
-<p class="img-caption">
-  <strong>Figure 4.</strong> Specifying additional currencies and additional languages for the
-  item title and description.
+
+<div style="margin:1em;">
+<img style="border:1px solid #ddd;padding-bottom:.5em" src="{@docRoot}images/in-app-billing/billing_list_form_2.png" xheight="1226" id="figure3" />
+<p class="img-caption" style="padding-left:.5em;">
+  <strong>Figure 3.</strong> Specifying additional currencies for an in-app product.
 </p>
+</div>
 
 <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
+href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&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
+href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&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
@@ -231,7 +222,7 @@
     published</code> or <code>unpublished</code>.</p>
   </li>
   <li><em>purchase_type</em>
-    <p>This is equivalent to the Purchase Type setting in the In-app Products UI. Can be <code>
+    <p>This is equivalent to the Product Type setting in the In-app Products UI. Can be <code>
     managed_by_android</code>, which is equivalent to <strong>Managed per user account
     </strong> in the In-app Products UI, or <code>managed_by_publisher</code>, which is equivalent
     to <strong>Unmanaged</strong> in the In-app Products UI.</p>
@@ -393,41 +384,18 @@
 </strong> on the In-app Product List page. This is useful if you have manually added items to
 a product list and you want to start managing the product list through a CSV file.</p>
 
-<h3 id="billing-purchase-type">Choosing a Purchase Type</h3>
+<h3 id="billing-purchase-type">Choosing a Product Type</h3>
 
-<p>An item's purchase type controls how Google Play manages the purchase of the item. There are
-two purchase types: "managed per user account" and "unmanaged."</p>
+<p>An item's product type controls how Google Play manages the purchase of the item. There are
+several product types, including "managed per user account", "unmanaged," and "subscription." However,
+note that the product types supported vary
+across In-app Billing Version, so you should always choose a product type that's valid for the
+version of In-app BIlling that your app uses. </p>
 
-<p>Items that are managed per user account can be purchased only once per user account. When an item
-is managed per user account, Google Play permanently stores the transaction information for each
-item on a per-user basis. This enables you to query Google Play with the
-<code>RESTORE_TRANSACTIONS</code> request and restore the state of the items a specific user has
-purchased.</p>
-
-<p>If a user attempts to purchase a managed item that has already been purchased, Google Play
-displays an "Item already purchased" error. This occurs during checkout, when Google Play
-displays the price and description information on the checkout page. When the user dismisses the
-error message, the checkout page disappears and the user returns to your user interface. As a best
-practice, your application should prevent the user from seeing this error. The sample application
-demonstrates how you can do this by keeping track of items that are managed and already purchased
-and not allowing users to select those items from the list. Your application should do something
-similar&mdash;either graying out the item or hiding it so that it cannot be selected.</p>
-
-<p>The "manage by user account" purchase type is useful if you are selling items such as game levels
-or application features. These items are not transient and usually need to be restored whenever a
-user reinstalls your application, wipes the data on their device, or installs your application on a
-new device.</p>
-
-<p>Items that are unmanaged do not have their transaction information stored on Google Play,
-which means you cannot query Google Play to retrieve transaction information for items whose
-purchase type is listed as unmanaged. You are responsible for managing the transaction information
-of unmanaged items. Also, unmanaged items can be purchased multiple times as far as Google Play
-is concerned, so it's also up to you to control how many times an unmanaged item can be
-purchased.</p>
-
-<p>The "unmanaged" purchase type is useful if you are selling consumable items, such as fuel or
-magic spells. These items are consumed within your application and are usually purchased multiple
-times.</p>
+<p>For details, refer to the documentation for <a
+href="{@docRoot}google/play/billing/api.html#producttype">In-app Billing Version
+3</a> or <a href="{@docRoot}google/play/billing/v2/api.html#producttype">In-app
+Billing Version 2</a>.
 
 <h2 id="billing-refunds">Handling Refunds</h2>
 
@@ -436,13 +404,13 @@
 refund through your Google Checkout merchant account. When you do this, Google Play receives a
 refund notification from Google Checkout, and Google Play sends a refund message to your
 application. For more information, see <a
-href="{@docRoot}google/play/billing/billing_overview.html#billing-action-notify">Handling
+href="{@docRoot}google/play/billing/v2/api.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
+href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1153485">In-app Billing
 Pricing</a>.</p>
 
 <p class="caution"><strong>Important:</strong> You cannot use the Google Checkout API to issue
-refunds or cancel in-app billing transactions. You must do this manually through your Google
+refunds or cancel In-app Billing transactions. You must do this manually through your Google
 Checkout merchant account. However, you can use the Google Checkout API to retrieve order
 information.</p>
 
@@ -478,13 +446,13 @@
 
 <h2 id="billing-testing-setup">Setting Up Test Accounts</h2>
 
-<p>The Google Play publisher site lets you set up one or more test accounts. A test account is a
-regular Google account that you register on the publisher site as a test account. Test accounts are
+<p>The Google Play Developer Console lets you set up one or more test accounts. A test account is a
+regular Google account that you register on the Developer Console as a test account. Test accounts are
 authorized to make in-app purchases from applications that you have uploaded to the Google Play
-site but have not yet published.</p>
+Developer Console but have not yet published.</p>
 
 <p>You can use any Google account as a test account. Test accounts are useful if you want to let
-multiple people test in-app billing on applications without giving them access to your publisher
+multiple people test In-app Billing on applications without giving them access to your publisher
 account's sign-in credentials. If you want to own and control the test accounts, you can create the
 accounts yourself and distribute the credentials to your developers or testers.</p>
 
@@ -503,28 +471,39 @@
 
 <ol>
   <li><a href="http://play.google.com/apps/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
-  5).</li>
-  <li>In Test Accounts, add the email addresses for the test accounts you want to register,
+  <li>Click the <strong>Settings</strong> icon. (If you are using the old Developer Console UI, click
+  <strong>Edit profile</strong> in the upper left part of the page, under your name,)</li>
+  <li>Locate the License Testing panel. (In the old UI, scroll down to the Licensing &amp; In-app Billing panel.)</li>
+  <li>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>
 
-<img src="{@docRoot}images/billing_public_key.png" height="510" id="figure5" />
-<p class="img-caption">
-  <strong>Figure 5.</strong> The Licensing and In-app Billing panel of your account's Edit Profile
-  page lets you register test accounts.
+<h3 id="license_key">Getting an app's license key</h3>
+
+<p>The Google Play Developer Console provides a public licensing key for each app. To get the key for an app,
+load the app's publishing details in the Developer Console and click the <strong>Settings</strong> icon. The key
+for the app is available for copy/paste in License Key for this Application field, as shown in the figure below.</p>
+
+<p>Previously, the Developer Console provided a single public key per developer account. To transition apps to the
+new per-app public key, the Developer Console set the app-specific key as the former developer key. This ensures
+compatibility for apps that depend on the (former) developer key. </p>
+
+<div style="margin:1em;">
+<img style="border:1px solid #ddd;padding-bottom:.5em" src="{@docRoot}images/in-app-billing/billing_app_key.png" xheight="510" id="figure4" />
+<p class="img-caption" style="padding-left:.5em;">
+  <strong>Figure 4.</strong> You can find the license key for each app in the <strong>Services & APIs</strong> panel.
 </p>
+</div>
 
 <h2 id="billing-support">Where to Get Support</h2>
 
-<p>If you have questions or encounter problems while implementing in-app billing, contact the
+<p>If you have questions or encounter problems while implementing In-app Billing, contact the
 support resources listed in the following table (see table 2). By directing your queries to the
 correct forum, you can get the support you need more quickly.</p>
 
 <p class="table-caption" id="support-table"><strong>Table 2.</strong> Developer support resources
-for Google Play in-app billing.</p>
+for Google Play In-app Billing.</p>
 
 <table>
 
@@ -549,7 +528,7 @@
 <td>Billing issue tracker</td>
 <td><a href="http://code.google.com/p/marketbilling/issues/">Billing
 project issue tracker</a></td>
-<td>Bug and issue reports related specifically to in-app billing sample code.</td>
+<td>Bug and issue reports related specifically to In-app Billing sample code.</td>
 </tr>
 </table>
 
diff --git a/docs/html/google/play/billing/billing_best_practices.jd b/docs/html/google/play/billing/billing_best_practices.jd
index dbf1057..015e7c3 100644
--- a/docs/html/google/play/billing/billing_best_practices.jd
+++ b/docs/html/google/play/billing/billing_best_practices.jd
@@ -7,42 +7,40 @@
 <div id="qv">
   <h2>In this document</h2>
   <ol>
-    <li><a href="#billing-security">Security Best Practices</a></li>
-  </ol>
-  <h2>Downloads</h2>
-  <ol>
-    <li><a href="{@docRoot}google/play/billing/billing_integrate.html#billing-download">Sample
-    Application</a></li>
+    <li><a href="#billing-security">Security Best Practices</a>
+       <ol>
+       <li><a href="#unlocked">Protect Unlocked Content</a></li>
+       <li><a href="#obfuscate">Obfuscate Your Code</a></li>
+       <li><a href="#sample">Modify Sample Code</a></li>
+       <li><a href="#nonce">Use Secure Random Nonces</a></li>
+       <li><a href="#payload">Set the Developer Payload String</a></li>
+       <li><a href="#trademark">Report Trademark and Copyright Infringement</a></li>
+       <li><a href="#revocable">Implement a Revocability scheme</a></li>
+       <li><a href="#key">Protect Your Public Key</a></li>
+       </ol>
+    </li>
   </ol>
   <h2>See also</h2>
   <ol>
     <li><a href="{@docRoot}google/play/billing/billing_overview.html">Overview of In-app
     Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_integrate.html">Implementing In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_testing.html">Testing In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_admin.html">Administering In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_reference.html">In-app Billing
-    Reference</a></li>
   </ol>
 </div>
 </div>
 
-<p>As you design your in-app billing implementation, be sure to follow the security and design
+<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 Google Play's in-app billing service.</p>
+anyone who is using Google Play's In-app Billing service.</p>
 
 <h2>Security Best Practices</h2>
 
-<h4>Perform signature verification tasks on a server</h4>
+<h3 id="sign">Perform signature verification tasks on a server</h3>
 <p>If practical, you should perform signature verification on a remote server and not on a device.
 Implementing the verification process on a server makes it difficult for attackers to break the
 verification process by reverse engineering your .apk file. If you do offload security processing to
 a remote server, be sure that the device-server handshake is secure.</p>
 
-<h4>Protect your unlocked content</h4>
+<h3 id="unlocked">Protect your unlocked content</h3>
 <p>To prevent malicious users from redistributing your unlocked content, do not bundle it in your
 .apk file. Instead, do one of the following:</p>
   <ul>
@@ -54,29 +52,29 @@
 content in device memory or store it on the device's SD card. If you store content on an SD card, be
 sure to encrypt the content and use a device-specific encryption key.</p>
 
-<h4>Obfuscate your code</h4>
-<p>You should obfuscate your in-app billing code so it is difficult for an attacker to reverse
+<h3 id="obfuscate">Obfuscate your code</h3>
+<p>You should obfuscate your In-app Billing code so it is difficult for an attacker to reverse
 engineer security protocols and other application components. At a minimum, we recommend that you
 run an  obfuscation tool like <a
 href="{@docRoot}tools/help/proguard.html">Proguard</a> on your
 code.</p>
 <p>In addition to running an obfuscation program, we recommend that you use the following techniques
-to obfuscate your in-app billing code.</p>
+to obfuscate your In-app Billing code.</p>
 <ul>
   <li>Inline methods into other methods.</li>
   <li>Construct strings on the fly instead of defining them as constants.</li>
   <li>Use Java reflection to call methods.</li>
 </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>
+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><code>-keep class com.android.vending.billing.**</code></p>
 </div>
   
-<h4>Modify all sample application code</h4>
-<p>The in-app billing sample application is publicly distributed and can be downloaded by anyone,
+<h3 id="sample">Modify all sample application code</h3>
+<p>The In-app Billing sample application is publicly distributed and can be downloaded by anyone,
 which means it is relatively easy for an attacker to reverse engineer your application if you use
 the sample code exactly as it is published. The sample application is intended to be used only as an
 example. If you use any part of the sample application, you must modify it before you publish it or
@@ -84,25 +82,31 @@
 <p>In particular, attackers look for known entry points and exit points in an application, so it is
 important that you modify these parts of your code that are identical to the sample application.</p>
 
-<h4>Use secure random nonces</h4>
+<h3 id="nonce">Use secure random nonces</h3>
 <p>Nonces must not be predictable or reused. Always use a cryptographically secure random number
 generator (like {@link java.security.SecureRandom}) when you generate nonces. This can help reduce
 replay attacks.</p>
 <p>Also, if you are performing nonce verification on a server, make sure that you generate the
 nonces on the server.</p>
 
-<h4>Take action against trademark and copyright infringement</h4>
+<h3 id="payload">Set the developer payload string when making purchase requests</h3>
+<p>With the In-app Billing Version 3 API, you can include a 'developer payload' string token when sending your purchase request to Google Play. Typically, this is used to pass in a string token that uniquely identifies this purchase request. If you specify a string value, Google Play returns this string along with the purchase response. Subsequently, when you make queries about this purchase, Google Play returns this string together with the purchase details.</p>
+<p>You should pass in a string token that helps your application to identify the user who made the purchase, so that you can later verify that this is a legitimate purchase by that user. For consumable items, you can use a randomly generated string, but for non-consumable items you should use a string that uniquely identifies the user.</p>
+<p>When you get back the response from Google Play, make sure to verify that the developer payload string matches the token that you sent previously with the purchase request. As a further security precaution, you should perform the verification on your own secure server.</p>
+
+
+<h3 id="trademark">Take action against trademark and copyright infringement</h3>
 <p>If you see your content being redistributed on Google Play, act quickly and decisively. File a
-<a href="http://market.android.com/support/bin/answer.py?hl=en&amp;answer=141511">trademark notice
+<a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=141511">trademark notice
 of infringement</a> or a <a href="http://www.google.com/android_dmca.html">copyright notice of
 infringement</a>.</p>
 
-<h4>Implement a revocability scheme for unlocked content</h4>
+<h3 id="revocable">Implement a revocability scheme for unlocked content</h3>
 <p>If you are using a remote server to deliver or manage content, have your application verify the
 purchase state of the unlocked content whenever a user accesses the content. This allows you to
 revoke use when necessary and minimize piracy.</p>
 
-<h4>Protect your Google Play public key</h4>
+<h3 id="key">Protect your Google Play public key</h3>
 <p>To keep your public key safe from malicious users and hackers, do not embed it in any code as a
 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
diff --git a/docs/html/google/play/billing/billing_integrate.jd b/docs/html/google/play/billing/billing_integrate.jd
index b7e2667..9f0dfe5 100644
--- a/docs/html/google/play/billing/billing_integrate.jd
+++ b/docs/html/google/play/billing/billing_integrate.jd
@@ -1,4 +1,4 @@
-page.title=Implementing In-app Billing
+page.title=Implementing In-app Billing <span style="font-size:16px;">(IAB Version 3)</span>
 parent.title=In-app Billing
 parent.link=index.html
 @jd:body
@@ -7,1094 +7,284 @@
 <div id="qv">
   <h2>In this document</h2>
   <ol>
-    <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-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>
+    <li><a href="#billing-add-aidl">Adding the AIDL file</a></li>
+    <li><a href="#billing-permission">Updating Your Manifest</a></li>
+    <li><a href="#billing-service">Creating a ServiceConnection</a></li>
+    <li><a href="#billing-requests">Making In-app Billing Requests</a>
+       <ol>
+       <li><a href="#QueryDetails">Querying Items Available for Purchase</a><li>
+       <li><a href="#Purchase">Purchasing an Item</a></li>
+       <li><a href="QueryPurchases">Querying Purchased Items</a></li>
+       <li><a href="Consume">Consuming a Purchase</a><li>
+       </ol>
+    </li>
   </ol>
-  <h2>Downloads</h2>
+  <h2>Reference</h2>
   <ol>
-    <li><a href="#billing-download">Sample Application</a></li>
+    <li><a href="{@docRoot}google/play/billing/billing_reference.html">In-app Billing
+    Reference (V3)</a></li>
+  </ol>
+  <h2>Related Samples</h2>
+  <ol>
+    <li><a href="{@docRoot}training/in-app-billing/preparing-iab-app.html#GetSample">Sample Application (V3)</a></li>
   </ol>
   <h2>See also</h2>
   <ol>
-    <li><a href="{@docRoot}google/play/billing/billing_overview.html">Overview of In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_best_practices.html">Security and
-    Design</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_testing.html">Testing In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_admin.html">Administering In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_reference.html">In-app Billing
-    Reference</a></li>
-  </ol>
+    <li><a href="{@docRoot}training/in-app-billing/index.html">Selling In-app Products</a></li>
+  </ol>  
 </div>
 </div>
 
-<p>In-app Billing on Google Play provides a straightforward, simple interface for sending in-app
-billing requests and managing in-app billing transactions using Google Play. 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>In-app Billing on Google Play provides a straightforward, simple interface for sending In-app Billing requests and managing In-app Billing transactions using Google Play. The information below covers the basics of how to make calls from your application to the In-app Billing service using the Version 3 API. </p>
 
-<p>Before you implement in-app billing in your own application, be sure that you read <a
-href="{@docRoot}google/play/billing/billing_overview.html">Overview of In-app Billing</a> and <a
-href="{@docRoot}google/play/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>
+<p class="note"><strong>Note:</strong> To see a complete implementation and learn how to test your application, see the <a href="{@docRoot}training/in-app-billing/index.html">Selling In-app Products</a> training class. The training class provides a complete sample In-app Billing application, including convenience classes to handle key tasks related to setting up your connection, sending billing requests and processing responses from Google Play, and managing background threading so that you can make In-app Billing calls from your main activity.</p>
 
-<p>To implement in-app billing in your application, you need to do the following:</p>
+<p>Before you start, be sure that you read the <a href="{@docRoot}google/play/billing/billing_overview.html">In-app Billing Overview</a> to familiarize yourself with concepts that will make it easier for you to implement In-app Billing.</p>
+
+<p>To implement In-app Billing in your application, you need to do the following:</p>
 <ol>
-  <li><a href="#billing-download">Download the in-app billing sample application</a>.</li>
-  <li><a href="#billing-add-aidl">Add the IMarketBillingService.aidl file</a> to your project.</li>
-  <li><a href="#billing-permission">Update your AndroidManifest.xml file</a>.</li>
-  <li><a href="#billing-service">Create a Service</a> and bind it to the
-  <code>MarketBillingService</code> so your application can send billing requests and receive
-  billing responses from Google Play.</li>
-  <li><a href="#billing-broadcast-receiver">Create a BroadcastReceiver</a> to handle broadcast
-  intents from Google Play.</li>
-  <li><a href="#billing-signatures">Create a security processing component</a> to verify the
-  integrity of the transaction messages that are sent by Google Play.</li>
-  <li><a href="#billing-implement">Modify your application code</a> to support in-app billing.</li>
+  <li>Add the In-app Billing library to your project.</li>
+  <li>Update your {@code AndroidManifest.xml} file.</li>
+  <li>Create a {@code ServiceConnection} and bind it to {@code IInAppBillingService}.</li>
+  <li>Send In-app Billing requests from your application to {@code IInAppBillingService}.</li>
+  <li>Handle In-app Billing responses from Google Play.</li>
 </ol>
 
-<h2 id="billing-download">Downloading the Sample Application</h2>
-
-<p>The in-app billing sample application shows you how to perform several tasks that are common to
-all in-app billing implementations, including:</p>
-
-<ul>
-  <li>Sending in-app billing requests to Google Play.</li>
-  <li>Handling synchronous responses from Google Play.</li>
-  <li>Handling broadcast intents (asynchronous responses) from Google Play.</li>
-  <li>Using in-app billing security mechanisms to verify the integrity of billing responses.</li>
-  <li>Creating a user interface that lets users select items for purchase.</li>
-</ul>
-
-<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> In-app billing sample
-application source files.</p>
-
-<table>
-<tr>
-<th>File</th>
-<th>Description</th>
-</tr>
-
-<tr>
-<td>IMarketBillingService.aidl</td>
-<td>Android Interface Definition Library (AIDL) file that defines the IPC interface to Google
-Play's in-app billing service (<code>MarketBillingService</code>).</td>
-</tr>
-
-<tr>
-<td>Dungeons.java</td>
-<td>Sample application file that provides a UI for making purchases and displaying purchase
-history.</td>
-</tr>
-
-<tr>
-<td>PurchaseDatabase.java</td>
-<td>A local database for storing purchase information.</td>
-</tr>
-
-<tr>
-  <td>BillingReceiver.java</td>
-  <td>A {@link android.content.BroadcastReceiver} that receives asynchronous response messages
-  (broadcast intents) from Google Play. Forwards all messages to the
-  <code>BillingService</code>.</td>
-</tr>
-<tr>
-  <td>BillingService.java</td>
-  <td>A {@link android.app.Service} that sends messages to Google Play on behalf of the
-  application by connecting (binding) to the <code>MarketBillingService</code>.</td>
-</tr>
-
-<tr>
-  <td>ResponseHandler.java</td>
-  <td>A {@link android.os.Handler} that contains methods for updating the purchases database and the
-  UI.</td>
-</tr>
-
-<tr>
-  <td>PurchaseObserver.java</td>
-  <td>An abstract class for observing changes related to purchases.</td>
-</tr>
-
-<tr>
-<td>Security.java</td>
-<td>Provides various security-related methods.</td>
-</tr>
-
-<tr>
-<td>Consts.java</td>
-<td>Defines various Google Play constants and sample application constants. All constants that
-are defined by Google Play must be defined the same way in your application.</td>
-</tr>
-
-<tr>
-<td>Base64.java and Base64DecoderException.java</td>
-<td>Provides conversion services from binary to Base64 encoding. The <code>Security</code> class
-relies on these utility classes.</td>
-</tr>
-
-</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 Manager and then
-select the <strong>Google Market Billing package</strong> component (see figure 1), and click <strong>Install
-Selected</strong> to begin the download.</p>
-
-
-<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 Manager saves the component into the
-following directory:</p>
-
-<p><code>&lt;sdk&gt;/extras/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 Google Play.</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 Google Play 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 Google Play. To add your public key to the sample application code, do the
-    following:</p>
-    <ol>
-      <li>Log in to your Google Play <a href="http://play.google.com/apps/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>. Google Play 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}tools/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 Google Play 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 Google Play.</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 Google Play. To learn how to upload an application to Google Play, 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}google/play/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 Google Play
-  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}google/play/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 Google Play
-  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 Google Play application. To learn how to check the
-    version of the Google Play application, see <a
-    href="http://market.android.com/support/bin/answer.py?answer=190860">Updating Google
-    Play</a>.</p>
-  </li>
-  <li><strong>Install the application onto your device.</strong>
-    <p>Even though you uploaded the application to Google Play, the application is not published,
-    so you cannot download it from Google Play 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}tools/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}google/play/billing/billing_admin.html#billing-testing-setup">test accounts</a>
-    that you registered on the Google Play publisher 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
-    Wallet 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 Google Play's 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>
+<p>The {@code TriviaDriva} sample application contains an Android Interface Definition Language (AIDL) file which defines the interface to Google Play's In-app Billing service. When you add this file to your project, the Android build environment creates an interface file (<code>IIAppBillingService.java</code>). You can then use this interface to make billing requests by invoking IPC method calls.</p>
 
-<p>If you are using the ADT plug-in with Eclipse, you can just add this file to your
-<code>/src</code> directory. Eclipse will automatically generate the interface file when you build
-your project (which should happen immediately). If you are not using the ADT plug-in, you can put
-the AIDL file into your project and use the Ant tool to build your project so that the
-<code>IMarketBillingService.java</code> file gets generated.</p>
-
-<p>To add the <code>IMarketBillingService.aidl</code> file to your project, do the following:</p>
-
+<p>To add the In-app Billing Version 3 library to your project:</p>
 <ol>
-  <li>Create the following directory in your application's <code>/src</code> directory:
-    <p><code>com/android/vending/billing/</code></p>
-  </li>
-  <li>Copy the <code>IMarketBillingService.aidl</code> file into the
-  <code>sample/src/com/android/vending/billing/</code> directory.</li>
-  <li>Build your application.</li>
+<li>Copy the {@code IInAppBillingService.aidl} file to your Android project.
+  <ul>
+  <li>If you are using Eclipse: Import the {@code IInAppBillingService.aidl} file into your {@code /src} directory. Eclipse automatically generates the interface file when you build your project.</li>
+  <li>If you are developing in a non-Eclipse environment: Create the following directory {@code /src/com/android/vending/billing} and copy the {@code IInAppBillingService.aidl} file into this directory. Put the AIDL file into your project and use the Ant tool to build your project so that the
+<code>IInAppBillingService.java</code> file gets generated.</li>
+  </ul>
+</li>
+<li>Build your application. You should see a generated file named {@code IInAppBillingService.java} in the {@code /gen} directory of your project.</li>
 </ol>
 
-<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 Google Play application, which handles all communication between
-your application and the Google Play server. To use the Google Play 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,
-Google Play will refuse the requests and respond with a <code>RESULT_DEVELOPER_ERROR</code>
-response code.</p>
+<p>In-app billing relies on the Google Play application, which handles all communication between your application and the Google Play server. To use the Google Play application, your application must request the proper permission. You can do this by adding the {@code com.android.vending.BILLING} permission to your AndroidManifest.xml file. If your application does not declare the In-app Billing permission, but attempts to send billing requests, Google Play will refuse the requests and respond with an error.</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 Google Play, 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 Google
-Play. 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 Google Play 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 Google Play
-application and <code>BillingService</code> is the {@link android.app.Service} that sends requests
-to the Google Play application.</p>
-
+<p>To give your app the necessary permission, add this line in your {@code Android.xml} manifest file:</p>
 <pre>
-&lt;?xml version="1.0" encoding="utf-8"?&gt;
-&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
-  package="com.example.dungeons"
-  android:versionCode="1"
-  android:versionName="1.0"&gt;
-
-  &lt;uses-permission android:name="com.android.vending.BILLING" /&gt;
-
-  &lt;application android:icon="@drawable/icon" android:label="@string/app_name"&gt;
-    &lt;activity android:name=".Dungeons" android:label="@string/app_name"&gt;
-      &lt;intent-filter&gt;
-        &lt;action android:name="android.intent.action.MAIN" /&gt;
-        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
-      &lt;/intent-filter&gt;
-    &lt;/activity&gt;
-
-    &lt;service android:name="BillingService" /&gt;
-
-    &lt;receiver android:name="BillingReceiver"&gt;
-      &lt;intent-filter&gt;
-        &lt;action android:name="com.android.vending.billing.IN_APP_NOTIFY" /&gt;
-        &lt;action android:name="com.android.vending.billing.RESPONSE_CODE" /&gt;
-        &lt;action android:name="com.android.vending.billing.PURCHASE_STATE_CHANGED" /&gt;
-      &lt;/intent-filter&gt;
-    &lt;/receiver&gt;
-
-  &lt;/application&gt;
-&lt;/manifest&gt;
+&lt;uses-permission android:name="com.android.vending.BILLING" /&gt;
 </pre>
 
-<h2 id="billing-service">Creating a Local Service</h2>
+<h2 id="billing-service">Creating a ServiceConnection</h2>
 
-<p>Your application must have a local {@link android.app.Service} to facilitate messaging between
-your application and Google Play. At a minimum, this service must do the following:</p>
+<p>Your application must have a {@link android.content.ServiceConnection} to facilitate messaging between
+your application and Google Play. At a minimum, your application must do the following:</p>
 
 <ul>
-  <li>Bind to the <code>MarketBillingService</code>.
-  <li>Send billing requests (as IPC method calls) to the Google Play application. The five types
-  of billing requests include:
-    <ul>
-      <li><code>CHECK_BILLING_SUPPORTED</code> requests</li>
-      <li><code>REQUEST_PURCHASE</code> requests</li>
-      <li><code>GET_PURCHASE_INFORMATION</code> requests</li>
-      <li><code>CONFIRM_NOTIFICATIONS</code> requests</li>
-      <li><code>RESTORE_TRANSACTIONS</code> requests</li>
-    </ul>
-  </li>
+  <li>Bind to {@code IInAppBillingService}.
+  <li>Send billing requests (as IPC method calls) to the Google Play application.</li>
   <li>Handle the synchronous response messages that are returned with each billing request.</li>
 </ul>
 
-<h3>Binding to the MarketBillingService</h3>
-
-<p>Binding to the <code>MarketBillingService</code> is relatively easy if you've already added the
-<code>IMarketBillingService.aidl</code> file to your project. The following code sample shows how to
-use the {@link android.content.Context#bindService bindService()} method to bind a service to the
-<code>MarketBillingService</code>. You could put this code in your service's {@link
-android.app.Activity#onCreate onCreate()} method.</p>
-
+<h3>Binding to IInAppBillingService</h3>
+<p>To establish a connection with the In-app Billing service on Google Play, implement a {@link android.content.ServiceConnection} to bind your activity to {@code IInAppBillingService}. Override the {@link android.content.ServiceConnection#onServiceDisconnected onServiceDisconnected} and {@link
+android.content.ServiceConnection#onServiceConnected onServiceConnected} methods to get a reference to the {@code IInAppBillingService} instance after a connection has been established.</p>
 <pre>
-try {
-  boolean bindResult = mContext.bindService(
-    new Intent("com.android.vending.billing.MarketBillingService.BIND"), this,
-    Context.BIND_AUTO_CREATE);
-  if (bindResult) {
-    Log.i(TAG, "Service bind successful.");
-  } else {
-    Log.e(TAG, "Could not bind to the MarketBillingService.");
-  }
-} catch (SecurityException e) {
-  Log.e(TAG, "Security exception: " + e);
+IInAppBillingService mService;
+
+ServiceConnection mServiceConn = new ServiceConnection() {
+   &#64;Override
+   public void onServiceDisconnected(ComponentName name) {
+       mService = null;
+   }
+
+   &#64;Override
+   public void onServiceConnected(ComponentName name, 
+      IBinder service) {
+       mService = IInAppBillingService.Stub.asInterface(service);
+   }
+};
+</pre>
+
+<p>In your activity’s {@link android.app.Activity#onCreate onCreate} method, perform the binding by calling the {@link android.content.Context#bindService bindService} method. Pass the method an {@link android.content.Intent} that references the In-app Billing service and an instance of the {@link android.content.ServiceConnection} that you created.</p>
+<pre>
+&#64;Override
+public void onCreate(Bundle savedInstanceState) {    
+   super.onCreate(savedInstanceState);
+   setContentView(R.layout.activity_main);        
+   bindService(new 
+      Intent("com.android.vending.billing.InAppBillingService.BIND"),
+          mServiceConn, Context.BIND_AUTO_CREATE);
+</pre>
+<p>You can now use the mService reference to communicate with the Google Play service.</p>
+<p class="note"><strong>Important:</strong> Remember to unbind from the In-app Billing service when you are done with your {@link android.app.Activity}. If you don’t unbind, the open service connection could cause your device’s performance to degrade. This example shows how to perform the unbind operation on a service connection to In-app Billing called {@code mServiceConn} by overriding the activity’s {@link android.app.Activity#onDestroy onDestroy} method.</p>
+<pre>
+&#64;Override
+public void onDestroy() {
+   if (mServiceConn != null) {
+      unbindService(mServiceConn);
+   }	
 }
 </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>For a complete implementation of a service connection that binds to the {@code IInAppBillingService}, see the <a href="{@docRoot}/training/in-app-billing/preparing-iab-app.html#Connect">Selling In-app Products</a> training class.</p>
 
-<pre>
-/**
-  * The Android system calls this when we are connected to the MarketBillingService.
-  */
-  public void onServiceConnected(ComponentName name, IBinder service) {
-    Log.i(TAG, "MarketBillingService connected.");
-    mService = IMarketBillingService.Stub.asInterface(service);
-  }
-</pre>
-
-<p>You can now use the <code>mService</code> reference to invoke the
-<code>sendBillingRequest()</code> method.</p>
-
-<p>For a complete implementation of a service that binds to the <code>MarketBillingService</code>,
-see the <code>BillingService</code> class in the sample application.</p>
-
-<h3>Sending billing requests to the MarketBillingService</h3>
-
-<p>Now that your {@link android.app.Service} has a reference to the
-<code>IMarketBillingService</code> interface, you can use that reference to send billing requests
-(via IPC method calls) to the <code>MarketBillingService</code>. The
-<code>MarketBillingService</code> IPC interface exposes a single public method
-(<code>sendBillingRequest()</code>), which takes a single {@link android.os.Bundle} parameter. The
-Bundle that you deliver with this method specifies the type of request you want to perform, using
-various key-value pairs. For instance, one key indicates the type of request you are making, another
-indicates the item being purchased, and another identifies your application. The
-<code>sendBillingRequest()</code> method immediately returns a Bundle containing an initial response
-code. However, this is not the complete purchase response; the complete response is delivered with
-an asynchronous broadcast intent. For more information about the various Bundle keys that are
-supported by the <code>MarketBillingService</code>, see <a
-href="{@docRoot}google/play/billing/billing_reference.html#billing-interface">In-app Billing
-Service Interface</a>.</p>
-
-<p>You can use the <code>sendBillingRequest()</code> method to send five types of billing requests.
-The five request types are specified using the <code>BILLING_REQUEST</code> Bundle key. This Bundle
-key can have the following five values:</p>
-
-<ul>
-  <li><code>CHECK_BILLING_SUPPORTED</code>&mdash;verifies that the Google Play application
-  supports in-app billing and the version of the In-app Billing API available.</li>
-  <li><code>REQUEST_PURCHASE</code>&mdash;sends a purchase request for an in-app item.</li>
-  <li><code>GET_PURCHASE_INFORMATION</code>&mdash;retrieves transaction information for a purchase
-  or refund.</li>
-  <li><code>CONFIRM_NOTIFICATIONS</code>&mdash;acknowledges that you received the transaction
-  information for a purchase or refund.</li>
-  <li><code>RESTORE_TRANSACTIONS</code>&mdash;retrieves a user's transaction history for <a
-  href="{@docRoot}google/play/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 {@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) {
-  Bundle request = new Bundle();
-  request.putString(BILLING_REQUEST, method);
-  request.putInt(API_VERSION, 1);
-  request.putString(PACKAGE_NAME, getPackageName());
-  return request;
-</pre>
-
-<p>To use this helper method, you pass in a <code>String</code> that corresponds to one of the five
-types of billing requests. The method returns a Bundle that has the three required keys defined. The
-following sections show you how to use this helper method when you send a billing request.</p>
-
-<p class="caution"><strong>Important</strong>: You must make all in-app billing requests from your
-application's main thread.</p>
-
-<h4>Verifying that in-app billing is supported (CHECK_BILLING_SUPPPORTED)</h4>
-
-<p>The following code sample shows how to verify whether the Google Play application supports
-in-app billing and confirm what version of the API it supports. In the sample, <code>mService</code>
-is an instance of the <code>MarketBillingService</code> interface.</p>
-
-<pre>
-/**
-* Request type is CHECK_BILLING_SUPPORTED
-*/
-  Bundle request = makeRequestBundle("CHECK_BILLING_SUPPORTED");
-  Bundle response = mService.sendBillingRequest(request);
-  // 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>. If you are offering subscriptions in
-your app, set the API_VERSION key to a value of "2", to confirm that In-app Billing v2 is
-available. For an examnple, see
-<a href="{@docRoot}google/play/billing/billing_subscriptions.html#version">Subscriptions</a>.</p>
-
-<p>The <code>CHECK_BILLING_SUPPORTED</code> 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;the spedified version of in-app billing is supported.</li>
-  <li><code>RESULT_BILLING_UNAVAILABLE</code>&mdash;in-app billing is not available because the 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 Google Play
-  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 Google Play 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 Google Play</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>
-
-<ul>
-  <li>Send the <code>REQUEST_PURCHASE</code> request.</li>
-  <li>Launch the {@link android.app.PendingIntent} that is returned from the Google Play
-  application.</li>
-  <li>Handle the broadcast intents that are sent by the Google Play application.</li>
-</ul>
-
-<h5>Making the request</h5>
-
-<p>You must specify four keys in the request {@link android.os.Bundle}. The following code sample
-shows how to set these keys and make a purchase request for a single in-app item. In the sample,
-<code>mProductId</code> is the Google Play product ID of an in-app item (which is listed in the
-application's <a href="{@docRoot}google/play/billing/billing_admin.html#billing-list-setup">product
-list</a>), and <code>mService</code> is an instance of the <code>MarketBillingService</code>
-interface.</p>
-
-<pre>
-/**
-* Request type is REQUEST_PURCHASE
-*/
-  Bundle request = makeRequestBundle("REQUEST_PURCHASE");
-  request.putString(ITEM_ID, mProductId);
-  // Request is for a standard in-app product
-  request.putString(ITEM_TYPE, "inapp");
-  // Note that the developer payload is optional.
-  if (mDeveloperPayload != null) {
-    request.putString(DEVELOPER_PAYLOAD, mDeveloperPayload);
-  }
-  Bundle response = mService.sendBillingRequest(request);
-  // 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 <code>ITEM_ID</code> key is then added
-to the Bundle prior to invoking the <code>sendBillingRequest()</code> method.</p>
-
-<p>The request returns a synchronous {@link android.os.Bundle} response, which contains three keys:
-<code>RESPONSE_CODE</code>, <code>PURCHASE_INTENT</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. The
-<code>PURCHASE_INTENT</code> key provides you with a {@link android.app.PendingIntent}, which you
-can use to launch the checkout UI.</p>
-
-<h5>Using 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 <code>PurchaseObserver.java</code> file in the sample
-application.</p>
-
-<pre>
-void startBuyPageActivity(PendingIntent pendingIntent, Intent intent) {
-  if (mStartIntentSender != null) {
-    // This is on Android 2.0 and beyond.  The in-app checkout page activity
-    // will be on the activity stack of the application.
-    try {
-      // This implements the method call:
-      // mActivity.startIntentSender(pendingIntent.getIntentSender(),
-      //     intent, 0, 0, 0);
-      mStartIntentSenderArgs[0] = pendingIntent.getIntentSender();
-      mStartIntentSenderArgs[1] = intent;
-      mStartIntentSenderArgs[2] = Integer.valueOf(0);
-      mStartIntentSenderArgs[3] = Integer.valueOf(0);
-      mStartIntentSenderArgs[4] = Integer.valueOf(0);
-      mStartIntentSender.invoke(mActivity, mStartIntentSenderArgs);
-    } catch (Exception e) {
-      Log.e(TAG, "error starting activity", e);
-      }
-  } else {
-    // This is on Android 1.6. The in-app checkout page activity will be on its
-    // own separate activity stack instead of on the activity stack of
-    // the application.
-    try {
-      pendingIntent.send(mActivity, 0 /* code */, intent);
-    } catch (CanceledException e) {
-      Log.e(TAG, "error starting activity", e);
-      }
-  }
-}
-</pre>
-
-<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 Google Play 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 Google Play application sends a <code>RESPONSE_CODE</code> broadcast intent,
-which provides error information about the request. If the request does not generate an
-error, the <code>RESPONSE_CODE</code> broadcast intent returns <code>RESULT_OK</code>, which
-indicates that the request was successfully sent. (To be clear, a <code>RESULT_OK</code> response
-does not indicate that the requested purchase was successful; it indicates that the request was sent
-successfully to Google Play.)</p>
-
-<p>Next, when the requested transaction changes state (for example, the purchase is successfully
-charged to a credit card or the user cancels the purchase), the Google Play 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 class="note"><strong>Note:</strong> The Google Play application also sends
-an <code>IN_APP_NOTIFY</code> for refunds. For more information, see <a
-href="{@docRoot}google/play/billing/billing_overview.html#billing-action-notify">Handling
-IN_APP_NOTIFY messages</a>.</p>
-
-<p>Because the purchase process is not instantaneous and can take several seconds (or more), you
-must assume that a purchase request is pending from the time you receive a <code>RESULT_OK</code>
-message until you receive an <code>IN_APP_NOTIFY</code> message for the transaction. While the
-transaction is pending, the Google Play checkout UI displays an "Authorizing purchase..."
-notification; however, this notification is dismissed after 60 seconds and you should not rely on
-this notification as your primary means of conveying transaction status to users. Instead, we
-recommend that you do the following:</p>
-
-<ul>
-  <li>Add an {@link android.app.Activity} to your application that shows users the status of pending
-and completed in-app purchases.</li>
-  <li>Use a <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">status
-bar notification</a> to keep users informed about the progress of a purchase.</li>
-</ul>
-
-<p>To use these two UI elements, you could invoke a status bar notification with a ticker-text
-message that says "Purchase pending" when your application receives a <code>RESULT_OK</code>
-message. Then, when your application receives an <code>IN_APP_NOTIFY</code> message, you could
-update the notification with a new message that says "Purchase succeeded" or "Purchase failed." When
-a user touches the expanded status bar notification, you could launch the activity that shows the
-status of pending and completed in-app purchases.</p>
-
-<p>If you use some other UI technique to inform users about the state of a pending transaction,
-be sure that your pending status UI does not block your application. For example, you should avoid
-using a hovering progress wheel to convey the status of a pending transaction because a pending
-transaction could last a long time, particularly if a device loses network connectivity and cannot
-receive transaction updates from Google Play.</p>
-
-<p class="caution"><strong>Important:</strong> If a user purchases a managed item, you must prevent
-the user from purchasing the item again while the original transaction is pending. If a user
-attempts to purchase a managed item twice, and the first transaction is still pending, Google
-Play will display an error to the user; however, Google Play will not send an error to your
-application notifying you that the second purchase request was canceled. This might cause your
-application to get stuck in a pending state while it waits for an <code>IN_APP_NOTIFY</code> message
-for the second purchase request.</p>
-
-<h4>Retrieving transaction information for a purchase or refund (GET_PURCHASE_INFORMATION)</h4>
-
-<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>
-
-<pre>
-/**
-* Request type is GET_PURCHASE_INFORMATION
-*/
-  Bundle request = makeRequestBundle("GET_PURCHASE_INFORMATION");
-  request.putLong(REQUEST_NONCE, mNonce);
-  request.putStringArray(NOTIFY_IDS, mNotifyIds);
-  Bundle response = mService.sendBillingRequest(request);
-  // 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 Google Play 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 Google Play 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 Google Play 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>
-
-<p>To acknowledge that you received transaction information you send a
-<code>CONFIRM_NOTIFICATIONS</code> request. You must specify four 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>
-
-<pre>
-/**
-* Request type is CONFIRM_NOTIFICATIONS
-*/
-  Bundle request = makeRequestBundle("CONFIRM_NOTIFICATIONS");
-  request.putStringArray(NOTIFY_IDS, mNotifyIds);
-  Bundle response = mService.sendBillingRequest(request);
-  // 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>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;a
-<code>RESPONSE_CODE</code> broadcast intent. This broadcast intent provides status and error
-information about the request.</p>
-
-<p>You must send a confirmation when you receive transaction information from Google Play. If you
-don't send a confirmation message, Google Play will continue sending
-<code>IN_APP_NOTIFY</code> messages for the transactions you have not confirmed. Also,
-your application must be able to handle <code>IN_APP_NOTIFY</code> messages that contain multiple
-orders.</p>
-
-<p>In addition, 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 Google Play indicating
-that you need to deliver the product.</p>
-
-<h4>Restoring transaction information (RESTORE_TRANSACTIONS)</h4>
-
-<p>To restore a user's transaction information, you send a <code>RESTORE_TRANSACTIONS</code>
-request. You must specify four 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>
-
-<pre>
-/**
-* Request type is RESTORE_TRANSACTIONS
-*/
-  Bundle request = makeRequestBundle("RESTORE_TRANSACTIONS");
-  request.putLong(REQUEST_NONCE, mNonce);
-  Bundle response = mService.sendBillingRequest(request);
-  // 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 Google Play 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 Google Play 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 Google Play 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>
-
-<p class="note"><strong>Note:</strong> You should use the <code>RESTORE_TRANSACTIONS</code>
-request type only when your application is installed for the first time on a device or when your
-application has been removed from a device and reinstalled.</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 Google Play 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}google/play/billing/billing_best_practices.html">Security and Design</a>.</p>
-
-<h2 id="billing-broadcast-receiver">Creating a BroadcastReceiver</h2>
-
-<p>The Google Play 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>com.android.vending.billing.RESPONSE_CODE
-  <p>This broadcast intent contains a Google Play 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}google/play/billing/billing_reference.html#billing-codes">Google Play Response
-  Codes for In-app Billing</a>.</p>
-  </li>
-  <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}google/play/billing/billing_reference.html#billing-intents">In-app Billing
-  Broadcast Intents</a></p>
-  </li>
-  <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}google/play/billing/billing_reference.html#billing-intents">In-app Billing
-  Broadcast Intents</a></p>
-  </li>
-</ul>
-
-<p>Each of these broadcast intents provide intent extras, which your {@link
-android.content.BroadcastReceiver} must handle. The intent extras are listed in the following table
-(see table 1).</p>
-
-<p class="table-caption"><strong>Table 1.</strong> Description of broadcast intent extras that are
-sent in response to billing requests.</p>
-
-<table>
-
-<tr>
-<th>Intent</th>
-<th>Extra</th>
-<th>Description</th>
-</tr>
-<tr>
-  <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 Google Play at the time a request is made.</td>
-</tr>
-<tr>
-  <td><code>com.android.vending.billing.RESPONSE_CODE</code></td>
-  <td><code>response_code</code></td>
-  <td>An <code>int</code> representing the actual Google Play server response code.</td>
-</tr>
-<tr>
-  <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.
-  Google Play 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>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>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>
-
-<p>The following code sample shows how to handle these broadcast intents and intent extras within a
-{@link android.content.BroadcastReceiver}. The BroadcastReceiver in this case is named
-<code>BillingReceiver</code>, just as it is in the sample application.</p>
-
-<pre>
-public class BillingReceiver extends BroadcastReceiver {
-
-  private static final String TAG = "BillingReceiver";
-
-  // Intent actions that we receive in the BillingReceiver from Google Play.
-  // These are defined by Google Play and cannot be changed.
-  // The sample application defines these in the Consts.java file.
-  public static final String ACTION_NOTIFY = "com.android.vending.billing.IN_APP_NOTIFY";
-  public static final String ACTION_RESPONSE_CODE = "com.android.vending.billing.RESPONSE_CODE";
-  public static final String ACTION_PURCHASE_STATE_CHANGED =
-    "com.android.vending.billing.PURCHASE_STATE_CHANGED";
-
-  // The intent extras that are passed in an intent from Google Play.
-  // These are defined by Google Play and cannot be changed.
-  // The sample application defines these in the Consts.java file.
-  public static final String NOTIFICATION_ID = "notification_id";
-  public static final String INAPP_SIGNED_DATA = "inapp_signed_data";
-  public static final String INAPP_SIGNATURE = "inapp_signature";
-  public static final String INAPP_REQUEST_ID = "request_id";
-  public static final String INAPP_RESPONSE_CODE = "response_code";
-
-
-  &#64;Override
-  public void onReceive(Context context, Intent intent) {
-    String action = intent.getAction();
-    if (ACTION_PURCHASE_STATE_CHANGED.equals(action)) {
-      String signedData = intent.getStringExtra(INAPP_SIGNED_DATA);
-      String signature = intent.getStringExtra(INAPP_SIGNATURE);
-      // Do something with the signedData and the signature.
-    } else if (ACTION_NOTIFY.equals(action)) {
-      String notifyId = intent.getStringExtra(NOTIFICATION_ID);
-      // Do something with the notifyId.
-    } else if (ACTION_RESPONSE_CODE.equals(action)) {
-      long requestId = intent.getLongExtra(INAPP_REQUEST_ID, -1);
-      int responseCodeIndex = intent.getIntExtra(INAPP_RESPONSE_CODE,
-        ResponseCode.RESULT_ERROR.ordinal());
-      // Do something with the requestId and the responseCodeIndex.
-    } else {
-      Log.w(TAG, "unexpected action: " + action);
-    }
-  }
-  // Perform other processing here, such as forwarding intent messages to your local service.
-}
-</pre>
-
-<p>In addition to receiving broadcast intents from the Google Play 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}google/play/billing/billing_best_practices.html">Security and Design </a>.</p>
-
-<h2 id="billing-signatures">Verifying Signatures and Nonces</h2>
-
-<p>Google Play's in-app billing service uses two mechanisms to help verify the integrity of the
-transaction information you receive from Google Play: 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;();
-
-  public static long generateNonce() {
-    long nonce = RANDOM.nextLong();
-    sKnownNonces.add(nonce);
-    return nonce;
-  }
-
-  public static void removeNonce(long nonce) {
-    sKnownNonces.remove(nonce);
-  }
-
-  public static boolean isNonceKnown(long nonce) {
-    return sKnownNonces.contains(nonce);
-  }
-</pre>
-
-<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}google/play/billing/billing_best_practices.html">Security and Design</a> and
-obfuscate your code.</p>
-
-<p>You will need to use your Google Play public key to perform the signature verification. The
-following procedure shows you how to retrieve Base64-encoded public key from the Google Play
-publisher site.</p>
-
-<ol>
-  <li>Log in to your <a href="http://play.google.com/apps/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.</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>
-
-<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.
+<h2 id="billing-requests">Making In-app Billing Requests</h2>
+<p>Once your application is connected to Google Play, you can initiate purchase requests for in-app products. Google Play provides a checkout interface for users to enter their payment method, so your application does not need to handle payment transactions directly. When an item is purchased, Google Play recognizes that the user has ownership of that item and prevents the user from purchasing another item with the same product ID until it is consumed. You can control how the item is consumed in your application, and notify Google Play to make the item available for purchase again. You can also query Google Play to quickly retrieve the list of purchases that were made by the user. This is useful, for example, when you want to restore the user's purchases when your user launches your app.
 </p>
 
-<h2 id="billing-implement">Modifying Your Application Code</h2>
+<h3 id="QueryDetails">Querying for Items Available for Purchase</h3>
+<p>In your application, you can query the item details from Google Play using the In-app Billing Version 3 API. To pass a request to the In-app Billing service, first create a {@link android.os.Bundle}  that contains a String {@link java.util.ArrayList} of product IDs with key "ITEM_ID_LIST", where each string is a product ID for an purchasable item.</p>
+<pre>
+ArrayList<String> skuList = new ArrayList<String>();
+skuList.add("premiumUpgrade");
+skuList.add("gas");
+Bundle querySkus = new Bundle();
+querySkus.putStringArrayList(“ITEM_ID_LIST”, skuList);
+</pre>
+<p>To retrieve this information from Google Play, call the {@code getSkuDetails} method on the In-app Billing Version 3 API, and pass the method the In-app Billing API version (“3”), the package name of your calling app, the purchase type (“inapp”), and the {@link android.os.Bundle} that you created.</p>
+<pre>
+Bundle skuDetails = mService.getSkuDetails(3, 
+   getPackageName(), “inapp”, querySkus);
+</pre>
+<p>If the request is successful, the returned {@link android.os.Bundle}has a response code of {@code BILLING_RESPONSE_RESULT_OK} (0).</p>
+<p class="note"><strong>Warning:</strong> Do not call the {@code getSkuDetails} method on the main thread. Calling this method triggers a network request which could block your main thread.  Instead, create a separate thread and call the {@code getSkuDetails} method from inside that thread.</p>
 
-<p>After you finish adding in-app billing components to your project, you are ready to modify your
-application's code. For a typical implementation, like the one that is demonstrated in the sample
-application, this means you need to write code to do the following: </p>
+<p>To see all the possible response codes from Google Play, see <a href="{@docRoot}google/play/billing/billing_reference.html#billing-codes">In-app Billing Reference</a>.</p>  
 
-<ul>
-  <li>Create a storage mechanism for storing users' purchase information.</li>
-  <li>Create a user interface that lets users select items for purchase.</li>
-</ul>
+<p>The query results are stored in a String ArrayList with key {@code DETAILS_LIST}.  The purchase information is stored in the String in JSON format. To see the types of product detail information that are returned, see <a href="{@docRoot}google/play/billing/billing_reference.html#getSkuDetails">In-app Billing Reference</a>.</p>
 
-<p>The sample code in <code>Dungeons.java</code> shows you how to do both of these tasks.</p>
+<p>In this example, you are retrieving the prices for your in-app items from the skuDetails {@link android.os.Bundle} returned from the previous code snippet.</p>
+<pre>
+int response = skuDetails.getInt("RESPONSE_CODE");
+if (response == 0) {
+   ArrayList<String> responseList 
+      = skuDetails.getStringArrayList("DETAILS_LIST");
+   
+   for (String thisResponse : responseList) {
+      JSONObject object = new JSONObject(thisResponse);
+      String sku = object.getString("productId");
+      String price = object.getString("price");
+      if (sku.equals(“premiumUpgrade”)) mPremiumUpgradePrice = price;
+      else if (sku.equals(“gas”)) mGasPrice = price;
+   }
+}
+</pre>
 
-<h3>Creating a storage mechanism for storing purchase information</h3>
+<h3 id="Purchase">Purchasing an Item</h3>
+<p>To start a purchase request from your app, call the {@code getBuyIntent} method on the In-app Billing service. Pass in to the method the In-app Billing API version (“3”), the package name of your calling app, the product ID for the item to purchase, the purchase type (“inapp”), and a {@code developerPayload} String. The {@code developerPayload} String is used to  specify any additional arguments that you want Google Play to send back along with the purchase information.</p>
 
-<p>You must set up a database or some other mechanism for storing users' purchase information. The
-sample application provides an example database (PurchaseDatabase.java); however, the example
-database has been simplified for clarity and does not exhibit the security best practices that we
-recommend. If you have a remote server, we recommend that you store purchase information on your
-server instead of in a local database on a device. For more information about security best
-practices, see <a href="{@docRoot}google/play/billing/billing_best_practices.html">Security and
-Design</a>.</p>
+<pre>
+Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(),
+   sku, "inapp", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
+</pre>
+<p>
+If the request is successful, the returned {@link android.os.Bundle} has a response code of {@code BILLING_RESPONSE_RESULT_OK} (0) and a {@link android.app.PendingIntent} that you can use to start the purchase flow. To see all the possible response codes from Google Play, see <a href="{@docRoot}google/play/billing/billing_reference.html#billing-codes">In-app Billing Reference</a>. Next, extract a {@link android.app.PendingIntent} from the response {@link android.os.Bundle} with key {@code BUY_INTENT}.
+</p>
+<pre>
+PendingIntent pendingIntent = buyIntentBundle.getParcelable(“BUY_INTENT”);
+</pre>
+<p>
+To complete the purchase transaction, call the {@link android.app.Activity#startIntentSenderForResult startIntentSenderForResult} method and use the {@link android.app.PendingIntent} that you created. In this example, you are using an arbitrary value of 1001 for the request code.</p>
+<pre>
+startIntentSenderForResult(pendingIntent.getIntentSender(),
+   1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0),
+   Integer.valueOf(0));
+</pre>
+<p>Google Plays sends a response to your {@link android.app.PendingIntent} to the {@link android.app.Activity#onActivityResult onActivityResult} method of your application. The {@link android.app.Activity#onActivityResult onActivityResult} method will have a result code of {@code Activity.RESULT_OK} (1) or {@code Activity.RESULT_CANCELED} (0). To see the types of order information that is returned in the response {@link android.content.Intent}, see <a href="{@docRoot}google/play/billing/billing_reference.html#getBuyIntent">In-app Billing Reference</a>.</p> 
 
-<p class="note"><strong>Note</strong>: If you store any purchase information on a device, be sure to
-encrypt the data and use a device-specific encryption key. Also, if the purchase type for any of
-your items is "unmanaged," we recommend that you back up the purchase information for these items to
-a remote server or use Android's <a href="{@docRoot}guide/topics/data/backup.html">data
-backup</a> framework to back up the purchase information. Backing up purchase information for
-unmanaged items is important because unmanaged items cannot be restored by using the
-<code>RESTORE_TRANSACTIONS</code> request type.</p>
+<p>The purchase data for the order is a String in JSON format that is mapped to the {@code INAPP_PURCHASE_DATA} key in the response {@link android.content.Intent}, for example:
+<pre>
+'{ 
+   "orderId":"12999763169054705758.1371079406387615", 
+   "packageName":"com.example.app",
+   "productId":"exampleSku",
+   "purchaseTime":1345678900000,
+   "purchaseState":0,
+   "developerPayload":"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ",
+   “purchaseToken”:“rojeslcdyyiapnqcynkjyyjh”
+ }'
+</pre>
+</p>
 
-<h3>Creating a user interface for selecting items</h3>
+<p>Continuing from the previous example, you get the response code, purchase data, and signature from the response {@link android.content.Intent}.</p>
+<pre>
+&#64;Override
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {	
+   if (requestCode == 1001) {    	
+      int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
+      String purchaseData = data.getStringExtra(“INAPP_PURCHASE_DATA”);
+      String dataSignature = data.getStringExtra(“INAPP_DATA_SIGNATURE”);
+        
+      if (resultCode == RESULT_OK) {
+         try {
+            JSONObject jo = new JSONObject(purchaseData);
+            String sku = jo.getString("productId");
+            alert("You have bought the " + sku + ". Excellent choice, 
+               adventurer!");
+          }
+          catch (JSONException e) {
+             alert("Failed to parse purchase data.");
+             e.printStackTrace();
+          }
+      }
+   }
+}
+</pre>
+<p class="note"><strong>Security Recommendation:</strong> When you send a purchase request, create a String token that uniquely identifies this purchase request and include this token in the {@code developerPayload}.You can use a randomly generated string as the token. When you receive the purchase response from Google Play, make sure to check the returned data signature, the {@code orderId}, and the {@code developerPayload} String. For added security, you should perform the checking on your own secure server. Make sure to verify that the {@code orderId} is a unique value that you have not previously processed, and the {@code developerPayload} String matches the token that you sent previously with the purchase request.</p>
 
-<p>You must provide users with a means for selecting items that they want to purchase. Google
-Play provides the checkout user interface (which is where the user provides a form of payment and
-approves the purchase), but your application must provide a control (widget) that invokes the
-<code>sendBillingRequest()</code> method when a user selects an item for purchase.</p>
+<h3 id="QueryPurchases">Querying for Purchased Items</h3>
+<p>To retrieve information about purchases made by a user from your app, call the {@code getPurchases} method on the In-app Billing Version 3 service. Pass in to the method the In-app Billing API version (“3”), the package name of your calling app, and the purchase type (“inapp”).</p>
+<pre>
+Bundle ownedItems = mService.getPurchases(3, getPackageName(), “inapp”, null);
+</pre>
+<p>The Google Play service returns only the purchases made by the user account that is currently logged in to the device. If the request is successful, the returned {@link android.os.Bundle} has a response code of 0. The response {@link android.os.Bundle} also contains a list of the product IDs, a list of the order details for each purchase, and the signatures for each purchase.</p>
+<p>To improve performance, the In-app Billing service returns only up to 700 products that are owned by the user when {@code getPurchase} is first called. If the user owns a large number of products, Google Play includes a String token mapped to the key {@code INAPP_CONTINUATION_TOKEN} in the response {@link android.os.Bundle} to indicate that more products can be retrieved. Your application can then make a subsequent {@code getPurchases} call, and pass in this token as an argument. Google Play continues to return a continuation token in the response {@link android.os.Bundle} until all products that are owned by the user has been sent to your app.</p>
+<p>For more information about the data returned by {@code getPurchases}, see <a href="{@docRoot}google/play/billing/billing_reference.html#getPurchases">In-app Billing Reference</a>. The following example shows how you can retrieve this data from the response.
+<pre>
+int response = ownedItems.getInt("RESPONSE_CODE");
+if (response == 0) {
+   ArrayList<String> ownedSkus = 
+      ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
+   ArrayList<String> purchaseDataList = 
+      ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
+   ArrayList<String> signatureList = 
+      ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE");
+   String continuationToken = 
+      ownedItems.getString("INAPP_CONTINUATION_TOKEN");
+   
+   for (int i = 0; i < purchaseDataList.size(); ++i) {
+      String purchaseData = purchaseDataList.get(i);
+      String signature = signatureList.get(i);
+      String sku = ownedSkus.get(i);
+  
+      // do something with this purchase information
+      // e.g. display the updated list of products owned by user
+   } 
 
-<p>You can render the control and trigger the <code>sendBillingRequest()</code> method any way you
-want. The sample application uses a spinner widget and a button to present items to a user and
-trigger a billing request (see <code>Dungeons.java</code>). The user interface also shows a list of
-recently purchased items.</p>
+   // if continuationToken != null, call getPurchases again 
+   // and pass in the token to retrieve more items
+}
+
+</pre>
+
+<h3 id="Consume">Consuming a Purchase</h3>
+<p>You can use the In-app Billing Version 3 API to track the ownership of purchased items in Google Play. Once an item is purchased, it is considered to be "owned" and cannot be purchased from Google Play. You must send a consumption request for the item before Google Play makes it available for purchase again. All managed in-app products are consumable.  How you use the consumption mechanism in your app is up to you. Typically, you would implement consumption for products with temporary benefits that users may want to purchase multiple times (for example, in-game currency or equipment). You would typically not want to implement consumption for products that are purchased once and provide a permanent effect (for example, a premium upgrade).</p>
+<p>To record a purchase consumption, send the {@code consumePurchase} method to the In-app Billing service and pass in the {@code purchaseToken} String value that identifies the purchase to be removed. The {@code purchaseToken} is part of the data returned in the {@code INAPP_PURCHASE_DATA} String by the Google Play service following a successful purchase request. In this example, you are recording the consumption of a product that is identified with the {@code purchaseToken} in the {@code token} variable.</p>
+<pre>
+int response = mService.consumePurchase(3, getPackageName(), token);
+</pre>
+<p class="note"><strong>Warning:</strong> Do not call the {@code consumePurchase} method on the main thread.  Calling this method triggers a network request which could block your main thread.  Instead, create a separate thread and call the {@code consumePurchase} method from inside that thread.</p>
+<p>It's your responsibility to control and track how the in-app product is provisioned to the user. For example, if the user purchased in-game currency, you should update the player's inventory with the amount of currency purchased.</p>
+<p class="note"><strong>Security Recommendation:</strong> You must send a consumption request before provisioning the benefit of the consumable in-app purchase to the user. Make sure that you have received a successful consumption response from Google Play before you provision the item.</p>
+
+
+
+
+
+
+
+
+
 
diff --git a/docs/html/google/play/billing/billing_overview.jd b/docs/html/google/play/billing/billing_overview.jd
index be9dc8d..aa48fc8 100644
--- a/docs/html/google/play/billing/billing_overview.jd
+++ b/docs/html/google/play/billing/billing_overview.jd
@@ -5,504 +5,223 @@
 
 <div id="qv-wrapper">
 <div id="qv">
+  <h2>Quickview</h2>
+  <ul>
+    <li>Use In-app Billing to sell digital goods, including one-time items and recurring subscriptions.</li>
+    <li>Supported for any app published on Google Play. You only need a Google Play publisher account and a Google Checkout Merchant account.</li>
+    <li>Checkout processing is automatically handled by Google Play, with the same look-and-feel as for app purchases.</li>
+  </ul>
   <h2>In this document</h2>
   <ol>
-    <li><a href="#billing-types">Product and Purchase Types</a></li>
-    <li><a href="#billing-arch">In-app Billing Architecture</a></li>
-    <li><a href="#billing-msgs">In-app Billing Messages</a></li>
-    <ol>
-      <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 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>
+    <li><a href="#api">In-app Billing API</a></li>
+    <li><a href="#products">In-app Products</a>
+       <ol>
+       <li><a href="#prodtypes">Product Types</a>
+       </ol>
+    </li>
+    <li><a href="#console">Google Play Developer Console</a></li>
+    <li><a href="#checkout">Google Play Purchase Flow</a></li>
+    <li><a href="#samples">Sample Apps</a></li> 
+    <li><a href="#migration">Migration Considerations</a></li>
   </ol>
-  <h2>Downloads</h2>
+   <h2>Related Samples</h2>
   <ol>
-    <li><a href="{@docRoot}google/play/billing/billing_integrate.html#billing-download">Sample
-    Application</a></li>
-  </ol>
-  <h2>See also</h2>
-  <ol>
-    <li><a href="{@docRoot}google/play/billing/billing_integrate.html">Implementing In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_best_practices.html">Security and
-    Design</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_testing.html">Testing In-app Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_admin.html">Administering In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_reference.html">In-app Billing
-    Reference</a></li>
-  </ol>
+    <li><a href="{@docRoot}training/in-app-billing/preparing-iab-app.html#GetSample">Sample Application (V3)</a></li>
+    <li><a href="{@docRoot}google/play/billing/v2/billing_integrate.html#billing-download">Sample
+    Application (V2)</a></li>
+  </ol> 
 </div>
 </div>
 
-<p>In-app Billing is a Google Play service 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 Google Play's in-app billing
-service.</p>
+<p>This documentation describes the fundamental In-app Billing components and 
+features that you need to understand in order to add In-app 
+Billing features into your application.</p>
 
-<h2 id="billing-types">Product and Purchase Types</h2>
-
-<p>In-app Billing supports different product types and purchase types to give you flexibility in how you monetize your app. In all cases, you define your products using the Google Play Developer Console, including product type, purchase type, SKU, price, description, and so on. For more information, see <a href="billing_admin.html">Administering In-app Billing</a>.</p>
-
-<h3 id="producttypes">Product Types</h3>
-
-<p>With In-app Billing, you can sell two types of products &mdash; <em>in-app products</em> and <em>subscriptions</em>. The billing characteristics of the two types are very different, but the In-app Billing API lets you handle the two product types in your app using the same communication model, data structures, and user interactions, as described later in this document.</p>
-
-<ul>
-<li><em>In-app products</em> &mdash; Items that a user would purchase one-at-a-time. For example, typical in-app products would let users purchase digital content, unlock functionality in an app, pay for one-time charges, or add almost anything to the application experience. Unlike with priced applications, once the user has purchased an in-app product there is no refund window. Users desiring refunds must contact the developer directly.
-
-<p>In-app products can be sold using either the "managed per user account" or "unmanaged" purchase type. In-app products are always explicitly associated with one and only one app. That is, one app cannot purchase an in-app product published for another app, even if they are from the same developer. In-app products are supported in all versions of In-app Billing.</p></li>
-
-<li><em>Subscriptions</em> &mdash; Items that are sold with a developer-specified, recurring billing interval. When a user purchases a subscription, Google Play and its payment processor automatically bill the user's account at the specified interval and price, charging the amount to the original payment method. Once the user purchases a subscription, Google Play continues billing the account indefinitely, without requiring approval or action from the user. The user can cancel the subscription at any time. 
-
-<p>Subscriptions can only be sold using the "managed per user account" purchase type. As with in-app products, once the user has purchased an in-app product there is no refund window. Users desiring refunds must contact the developer directly. For more information about subscriptions and how to sell them in your apps, see the <a href="billing_subscriptions.html">Subscriptions</a> document.</p></li>
-</ul>
-
-<h3 id="purchasetypes">Purchase Types</h3>
-
-<p>In-app Billing offers two purchase types that you can use when selling in-app products, "managed per user account" and "unmanaged". The purchase type controls how Google Play handles and tracks purchases for the products. </p>
-
-<ul>
-<li><em>Managed per user account</em> &mdash; Items that can be purchased only once per user account on Google Play. When a user purchases an item that uses the "managed per user account" purchase type, Google Play permanently stores the transaction information for each item on a per-user basis. This enables you to later query Google Play to restore the state of the items a specific user has purchased. If a user attempts to purchase a managed item that has already been purchased, Google Play prevents the user from purchasing the item again and displays an "Item already purchased" error.
-
-<p>The "managed per user account" purchase type is useful if you are selling items such as game levels or application features. These items are not transient and usually need to be restored whenever a user reinstalls your application, wipes the data on their device, or installs your application on a new device.</p>
-
-<li><em>Unmanaged</em> &mdash; Items that do not have their transaction information stored on Google Play. This means that you cannot later query Google Play to retrieve transaction information for those items. For "unmanaged" purchases, you are responsible for managing the transaction information. Also, Google Play does not attempt to prevent the user from purchasing an item multiple times if it uses the "unmanaged" purchase type. It's up to you to control how many times an unmanaged item can be purchased.</p>
-
-<p>The "unmanaged" purchase type is useful if you are selling consumable items, such as fuel or magic spells. These items are consumed within your application and are usually purchased multiple times.</p></li>
-</ul>
-
-<h2 id="billing-arch">In-app Billing Architecture</h2>
-
-<p>Your app accesses the In-app Billing service using an API that is exposed by
-the Google Play app installed on the device. The Google Play app then uses an
-asynchronous message loop to convey billing requests and responses between your
-application and the Google Play server. In practice, your application never
-directly communicates with the Google Play server (see figure 1). Instead, your
-application sends billing requests to the Google Play application over
-interprocess communication (IPC) and receives purchase responses from the Google
-Play application in the form of asynchronous broadcast intents. Your application
-does not manage any network connections between itself and the Google Play
-server or use any special APIs from the Android platform.</p>
-
-<div class="figure" style="width:440px">
-<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
-  Google Play application, which handles all communication with the Google Play server.</p>
-</div>
-
-<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>
-
-<p>A typical in-app billing implementation relies on three components:</p>
-<ul>
-  <li>A {@link android.app.Service} (named <code>BillingService</code> in the sample application),
-  which processes purchase messages from the application and sends billing requests to the Google
-  Play in-app billing service.</li>
-  <li>A {@link android.content.BroadcastReceiver} (named <code>BillingReceiver</code> in the sample
-  application), which receives all asynchronous billing responses from the Google Play
-  application.</li>
-  <li>A security component (named <code>Security</code> in the sample application), which performs
-  security-related tasks, such as signature verification and nonce generation. For more information
-  about in-app billing security, see <a href="#billing-security">Security controls</a> later in this
-  document.</li>
-</ul>
-
-<p>You may also want to incorporate two other components to support in-app billing:</p>
-<ul>
-  <li>A response {@link android.os.Handler} (named <code>ResponseHandler</code> in the sample
-  application), which provides application-specific processing of purchase notifications, errors,
-  and other status messages.</li>
-  <li>An observer (named <code>PurchaseObserver</code> in the sample application), which is
-  responsible for sending callbacks to your application so you can update your user interface with
-  purchase information and status.</li>
-</ul>
-
-<p>In addition to these components, your application must provide a way to store information about
-users' purchases and some sort of user interface that lets users select items to purchase. You do
-not need to provide a checkout user interface. When a user initiates an in-app purchase, the Google
-Play application presents the checkout user interface to your user. When the user completes the
-checkout process, your application resumes.</p>
-
-<h2 id="billing-msgs">In-app Billing Messages</h2>
-
-<p>When the user initiates a purchase, your application sends billing messages to Google Play's
-in-app billing service (named <code>MarketBillingService</code>) using simple IPC method calls. The
-Google Play application responds to all billing requests synchronously, providing your
-application with status notifications and other information. The Google Play application also
-responds to some billing requests asynchronously, providing your application with error messages and
-detailed transaction information. The following section describes the basic request-response
-messaging that takes place between your application and the Google Play application.</p>
-
-<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/components/aidl.html">Android Interface Definition Language</a> file
-(<code>IMarketBillingService.aidl</code>). You can <a
-href="{@docRoot}google/play/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
-its type, 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}google/play/billing/billing_reference.html#billing-interface">In-app Billing
-Service Interface</a>.
-
-<p>One of the most important keys that every request Bundle must have is the
-<code>BILLING_REQUEST</code> key. This key lets you specify the type of billing request you are
-making. Google Play's in-app billing service supports the following five types of billing
-requests:</p>
-
-<ul>
-  <li><code>CHECK_BILLING_SUPPORTED</code>
-    <p>This request verifies that the Google Play application supports in-app billing. You
-    usually send this request when your application first starts up. This request is useful if you
-    want to enable or disable certain UI features that are relevant only to in-app billing.</p>
-  </li>
-  <li><code>REQUEST_PURCHASE</code>
-    <p>This request sends a purchase message to the Google Play application and is the foundation
-    of in-app billing. You send this request when a user indicates that he or she wants to purchase
-    an item in your application. Google Play then handles the financial transaction by displaying
-    the checkout user interface.</p>
-  </li>
-  <li><code>GET_PURCHASE_INFORMATION</code>
-    <p>This request retrieves the details of a purchase state change. A purchase changes state when
-    a requested purchase is billed successfully or when a user cancels a transaction during
-    checkout. It can also occur when a previous purchase is refunded. Google Play notifies your
-    application when a purchase changes state, so you only need to send this request when there is
-    transaction information to retrieve.</p>
-  </li>
-  <li><code>CONFIRM_NOTIFICATIONS</code>
-    <p>This request acknowledges that your application received the details of a purchase state
-    change. Google Play 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 <a
-    href="{@docRoot}google/play/billing/billing_admin.html#billing-purchase-type">managed
-    purchases</a> and <a
-    href="{@docRoot}google/play/billing/billing_admin.html#billing-purchase-type">subscriptions</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>
-
-<h3 id="billing-response">In-app Billing Responses</h3>
-
-<p>The Google Play application responds to in-app billing requests with both synchronous and
-asynchronous responses. The synchronous response is a {@link android.os.Bundle} with the following
-three keys:</p>
-
-<ul>
-  <li><code>RESPONSE_CODE</code>
-    <p>This key provides status information and error information about a request.</p>
-  </li>
-  <li><code>PURCHASE_INTENT</code>
-    <p>This key provides a {@link android.app.PendingIntent}, which you use to launch the checkout
-    activity.</p>
-  </li>
-  <li><code>REQUEST_ID</code>
-    <p>This key provides you with a request identifier, which you can use to match asynchronous
-    responses with requests.</p>
-  </li>
-</ul>
-<p>Some of these keys are not relevant to every request. For more information, see <a
-href="#billing-message-sequence">Messaging sequence</a> later in this document.</p>
-
-<p>The asynchronous response messages are sent in the form of individual broadcast intents and
-include the following:</p>
-
-<ul>
-    <li><code>com.android.vending.billing.RESPONSE_CODE</code>
-    <p>This response contains a Google Play 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 Google Play 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}google/play/billing/billing_reference.html#billing-codes">Server Response Codes
-    for In-app Billing</a>.</p>
-  </li>
-  <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>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>PURCHASE_STATE_CHANGED</code> intent provides
-your application with the details of one or more billing transactions. An example of this JSON
-string for a subscription item is shown below:</p>
-<pre class="no-pretty-print" style="color:black">{ "nonce" : 1836535032137741465,
-  "orders" :
-    [{ "notificationId" : "android.test.purchased",
-       "orderId" : "12999556515565155651.5565135565155651",
-       "packageName" : "com.example.dungeons",
-       "productId" : "android.test.purchased",
-       "developerPayload" : "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ",
-       "purchaseTime" : 1290114783411,
-       "purchaseState" : 0,
-       "purchaseToken" : "rojeslcdyyiapnqcynkjyyjh" }]
-}
-</pre>
-
-<p>For more information about the fields in this JSON string, see <a
-href="{@docRoot}google/play/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>, 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 Google Play 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.
-    <p class="note"><strong>Note:</strong> You must launch the pending intent from an activity
-    context and not an application context.</p>
-  </li>
-  <li>When the checkout flow finishes (that is, the user successfully purchases the item or cancels
-  the purchase), Google Play 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 Google Play application sends a Bundle with a <code>RESPONSE_CODE</code> key and a 
-  <code>REQUEST_ID</code> key.
-  <li>Google Play 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 Google Play application sends your application a Bundle with a
-  <code>RESPONSE_CODE</code> key and a <code>REQUEST_ID</code> key.</li>
-</ol>
-
-<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>Keep in mind, you must send a confirmation when you receive transaction information from Google
-Play (step 8 in figure 2). If you don't send a confirmation message, Google Play will
-continue sending <code>IN_APP_NOTIFY</code> messages for the transactions you have not
-confirmed. 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 Google Play indicating
-that you need to deliver the product. Also, as a best practice, your application must be able to
-handle <code>IN_APP_NOTIFY</code> messages that contain multiple orders.</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="" 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> key and a <code>REQUEST_ID</code> key. Next, the Google Play
-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 a
-<code>PURCHASE_STATE_CHANGED</code> broadcast intent, which contains the same type of transaction
-information that is sent during a purchase request. Unlike with a purchase request, however, the transactions
-are given without any associated notification IDs, so you do not need to respond to this
-intent with a <code>CONFIRM_NOTIFICATIONS</code> message. </p>
-
-<p class="note"><strong>Note:</strong> You should use the <code>RESTORE_TRANSACTIONS</code> request
-type only when your application is installed for the first time on a device or when your
-application has been removed from a device and reinstalled.</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="" 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 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 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
+<h2 id="api">In-app Billing API</h2>
+<p>Your application accesses the In-app Billing service using an API that is 
+exposed by the Google Play app that is installed on the device. The Google Play 
+app then conveys billing requests and responses between your 
+application and the Google Play server. In practice, your application never 
+directly communicates with the Google Play server. Instead, your application 
+sends billing requests to the Google Play application over interprocess 
+communication (IPC) and receives responses from the Google Play app. 
+Your application does not manage any network connections between itself and 
 the Google Play server.</p>
+<p>In-app Billing can be implemented only in applications that you publish 
+through Google Play. To complete in-app purchase requests, the Google Play app 
+must be able to access the Google Play server over the network.</p>
 
-<h3 id="billing-action-notify">Handling IN_APP_NOTIFY messages</h3>
-
-<p>Usually, your application receives an <code>IN_APP_NOTIFY</code> broadcast intent from Google
-Play 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. Google Play 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
-Google Play that you have received the purchase state change information.</p>
-
-<p>In some special cases, you may receive multiple <code>IN_APP_NOTIFY</code> messages even though
-you have confirmed receipt of the purchase information, or you may receive
-<code>IN_APP_NOTIFY</code> messages for a purchase change even though you never initiated the
-purchase. Your application must handle both of these special cases.</p>
-
-<h4>Handling multiple IN_APP_NOTIFY messages</h4>
-
-<p>When Google Play receives a <code>CONFIRM_NOTIFICATIONS</code> message for a given
-<code>PURCHASE_STATE_CHANGED</code> message, it usually stops sending <code>IN_APP_NOTIFY</code>
-intents for that <code>PURCHASE_STATE_CHANGED</code> message. Sometimes, however, Google
-Play may send repeated <code>IN_APP_NOTIFY</code> intents for a
-<code>PURCHASE_STATE_CHANGED</code> 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, Google Play
-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
-transaction 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>
-
-<h4>Handling refunds and other unsolicited IN_APP_NOTIFY messages</h4>
-
-<p>There are two cases where your application may 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 may 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, Google Play 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}google/play/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 Google Play receives a refund notification from Google Checkout. In this case, Google
-Play 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>
-
-<p class="caution"><strong>Important:</strong> You cannot use the Google Checkout API to
-issue refunds or cancel in-app billing transactions. You must do this manually through your
-Google Checkout merchant account. However, you can use the Google Checkout API to retrieve order
-information.</p>
-
-<h2 id="billing-security">Security Controls</h2>
-
-<p>To help ensure the integrity of the transaction information that is sent to your application,
-Google Play signs the JSON string that is contained in the <code>PURCHASE_STATE_CHANGED</code>
-broadcast intent. Google Play 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 Google Play licensing.</p>
-
-<p>When Google Play 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 Google Play. 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 Google Play 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}google/play/billing/billing_best_practices.html">Security and Design</a>.</p>
-
-<h2 id="billing-limitations">In-app Billing Requirements and Limitations</h2>
-
-<p>Before you get started with in-app billing, be sure to review the following requirements and
-limitations.</p>
-
+<p>Currently, Google Play supports two versions of the In-app Billing API. 
+To determine which version you should use, see <a href="#migration">Migration 
+Considerations</a>.</p>
+<h4><a href="{@docRoot}google/play/billing/api.html">Version 3</a> (recommended)</h4>
 <ul>
-  <li>In-app billing can be implemented only in applications that you publish through Google
-  Play.</li>
-  <li>You must have a Google Checkout Merchant account to use Google Play In-app Billing.</li>
-  <li>In-app billing requires version 2.3.4 (or higher) of the Android Market application.
-  To support subscriptions, version 3.5 or higher of the Google Play app is required. On devices
-  running Android 3.0, version 5.0.12 (or higher) of the MyApps application is required.</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>Google Play 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 Google Play server over
-  the network. </li>
+<li>Requests are sent through a streamlined API that allows you to easily request 
+product details from Google Play, order in-app products, and quickly restore 
+items based on users' product ownership</li>
+<li>Order information is synchronously propagated to the device on purchase 
+completion</li>
+<li>All purchases are “managed” (that is, Google Play keeps track of the user's 
+ownership of in-app products). The user cannot own multiple copies of an in-app 
+item; only one copy can be owned at any point in time</li>
+<li>Purchased items can be consumed. When consumed, the item reverts to the 
+"unowned" state and can be purchased again from Google Play</li>
+</ul>
+<h4><a href="{@docRoot}google/play/billing/v2/api.html">Version 2</a></h4>
+<ul>
+<li>Requests are sent via a single API interface ({@code sendBillingRequest})</li>
+<li>Responses from Google Play are asynchronous, in the form of broadcast intents</li>
+<li>No consumption model provided. You have to implement your own solution</li>
+<li>Provides support for subscriptions and unmanaged in-app purchase items, 
+as well as managed in-app products</li>
+</ul>
+<p>Both versions offer very broad compatibility across the range of Android 
+devices. In-app Billing Version 3 is supported on devices running Android 2.2 or 
+higher that have the latest version of the Google Play store installed 
+(over 90% of active devices). Version 2 offers similar compatibility. See 
+<a href="{@docRoot}google/play/billing/versions.html">Version Notes</a> for 
+more details.</p>
+
+<h2 id="products">In-app Products</h2>
+<p>In-app products are the digital goods that you offer for sale from inside your 
+application to users. Examples of digital goods includes in-game currency, 
+application feature upgrades that enhance the user experience, and new content 
+for your application.</p>
+<p>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. Unlike with priced applications, once 
+the user has purchased an in-app product there is no refund window.</p>
+<p>Google Play does not provide any form of content delivery. You are 
+responsible for delivering the digital content that you sell in your 
+applications. In-app products are always explicitly associated with one and 
+only one app. That is, one application cannot purchase an in-app product 
+published for another app, even if they are from the same developer.</p>
+
+<h3 id="prodtypes">Product types</h3>
+<p>In-app Billing supports different product types to give you flexibility in 
+how you monetize your application. In all cases, you define your products using 
+the Google Play Developer Console.</p>
+<p>You can specify these types of products for your In-app Billing application  
+— <em>managed in-app products</em>, <em>subscriptions</em>, and <em>unmanaged 
+in-app products</em>.  The term “managed” indicates that Google Play handles and 
+tracks ownership for in-app products on your application on a per user account 
+basis, while “unmanaged” indicates that you will manage the ownership  information yourself.</p>
+<p>To learn more about the product types supported by the different API versions, 
+see the related documentation for <a href="{@docRoot}google/play/billing/v2/api.html#billing-types">Version 2</a> and <a href="{@docRoot}google/play/billing/api.html#producttypes">Version 3</a>.</p>
+
+<h2 id="console">Google Play Developer Console</h2>
+<p>The Developer Console is where you can publish your 
+In-app Billing application, and manage the various in-app products that are 
+available for purchase from your application.</p>
+<p>You can create a product list of 
+digital goods that are associated with your application, including items for 
+one-time purchase and recurring subscriptions. For each item, you can define 
+information such as the item’s unique product ID (also called its SKU), product 
+type, pricing, description, and how Google Play should handle and track 
+purchases for that product.</p>
+<p>You can also create test accounts to authorize 
+access for testing applications that are unpublished.</p>
+<p>To learn how to use the Developer Console to configure your in-app 
+products and product list, see 
+<a href="{@docRoot}google/play/billing/billing_admin.html">Administering 
+In-app Billing</a>.</p>
+
+<h2 id="checkout">Google Play Purchase Flow</h2>
+<p>Google Play uses the same checkout backend service as is used for application 
+purchases, so your users experience a consistent and familiar purchase flow.</p>
+<p class="note"><strong>Important:</strong> You must have a Google Checkout
+Merchant account to use the In-app Billing service on Google Play.</p>
+<p>To initiate a purchase, your application sends a billing request for a 
+specific in-app product. Google Play then handles all of the checkout details for 
+the transaction, including requesting and validating the form of payment and 
+processing the financial transaction.</p> 
+<p>When the checkout process is complete, 
+Google Play 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 
+Google Play.</p>
+<img src="{@docRoot}images/in-app-billing/v3/iab_v3_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). Google Play responds to the request by 
+providing the checkout user interface (middle screen). When checkout is 
+complete, the application resumes.
+</p>
+
+<h2 id="samples">Sample Applications</h2>
+<p>To help you integrate In-app Billing into your application, the Android SDK 
+provides two sample applications that demonstrate how to sell in-app products 
+from inside an app.</p>
+
+<dl>
+<dt><a href="{@docRoot}training/in-app-billing/preparing-iab-app.html#GetSample">TrivialDrive sample for the Version 3 API</a></dt>
+<dd>This sample shows how to use the In-app Billing Version 3 API to implement 
+in-app product purchases for a driving game. The application demonstrates how to 
+send In-app Billing requests, and handle synchronous responses from Google Play. 
+The application also shows how to record item consumption with the API. The 
+Version 3 sample includes convenience classes for processing In-app Billing 
+operations as well as perform automatic signature verification.</dd>
+
+<dt><a href="{@docRoot}google/play/billing/v2/billing_integrate.html#billing-download">Dungeons sample for the Version 2 API</a></dt>
+<dd>This sample demonstrates how to use the In-app Billing Version 2 API to sell 
+standard in-app products and subscriptions for an adventuring game. It also 
+contains examples of the database, user interface, and business logic you might 
+use to implement In-app Billing.</dd>
+</dl>
+<p class="caution"><strong>Important</strong>: It's <em>strongly recommended</em> 
+that you obfuscate the code in your application before you publish it. For 
+more information, see
+<a href="{@docRoot}google/play/billing/billing_best_practices.html">Security 
+and Design</a>.</p>
+
+<h2 id="migration">Migration Considerations</h2>
+<p>The following considerations may be applicable if you are planning to create a new 
+in-app biling application, or migrate your existing In-app Billing implementation 
+from the <a href="{@docRoot}google/play/billing/v2/api.html">Version 2</a> or 
+earlier API to the <a href="{@docRoot}google/play/billing/api.html">Version 3</a> API.</p>
+<p>Google Play will continue to support both the Version 2 and Version 3 APIs for 
+some time, so you can plan to migrate to Version 3 at your own pace. The Google 
+Play team will give advance notice of any upcoming changes to the support 
+status of In-app Billing Version 2.</p>
+<p>You can use the following table to decide which version of the API to use, 
+depending on the needs of your application.</p>
+<p class="table-caption" id="table1">
+  <strong>Table 1.</strong> Selecting the In-app Billing API Version for Your 
+Project</p>
+
+<table>
+<tr>
+<th scope="col">Choose Version 3 if ...</th>
+<th scope="col">Choose Version 2 if ...</th>
+</tr>
+<tr>
+<td>
+  <ul>
+  <li>You want to sell in-app products only (and not subscriptions)</li>
+  <li>You need synchronous order confirmations when purchases complete</li>
+  <li>You need to synchronously restore a user's current purchases</li>
+  </ul>
+</td>
+<td>
+  <ul>
+  <li>You want to sell subscriptions in your app</li>
+  </ul>
+</td>
+</tr>
+</table>
+<p>If you have published apps selling in-app products, note that:</p>
+<ul>
+<li>Managed items that you have previously defined in the Developer Console will 
+work with Version 3 as before.</li>
+<li>Unmanaged items that you have defined for existing applications will be 
+treated as managed products if you make a purchase request for these items using 
+the Version 3 API. You do not need to create a new product entry in Developer 
+Console for these items, and you can use the same product IDs to purchase these 
+items. They will still continue to be treated as unmanaged items if you make a 
+purchase request for them using the Version 2 or earlier API. 
 </ul>
 
-<p>For more information about in-app billing requirements, see <a
-href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1153481">In-App
-Billing Availability and Policies</a>.</p>
+
+
+
+
diff --git a/docs/html/google/play/billing/billing_reference.jd b/docs/html/google/play/billing/billing_reference.jd
index 0c82fd5..758e21d 100644
--- a/docs/html/google/play/billing/billing_reference.jd
+++ b/docs/html/google/play/billing/billing_reference.jd
@@ -1,4 +1,4 @@
-page.title=In-app Billing Reference
+page.title=In-app Billing Reference <span style="font-size:16px;">(IAB Version 3)</span>
 parent.title=In-app Billing
 parent.link=index.html
 @jd:body
@@ -7,485 +7,213 @@
 <div id="qv">
   <h2>In this document</h2>
   <ol>
-    <li><a href="#billing-codes">Server Response Codes for In-app Billing</a></li>
-    <li><a href="#billing-interface">In-app Billing Service Interface</a></li>
-    <li><a href="#billing-intents">In-app Billing Broadcast Intents</a></li>
-    <li><a href="#other-intents">Other Broadcast Intents</a></li>
-    <li><a href="#billing-versions">In-app Billing API Versions</a></li>
+    <li><a href="#billing-codes">Server Response Codes</a></li>
+    <li><a href="#billing-interface">API Reference</a>
+    <ol>
+      <li><a href="#getSkuDetails">getSkuDetails()</a></li>
+      <li><a href="#getBuyIntent">getBuyIntent()</a></li>
+      <li><a href="#getPurchases">getPurchases()</a></li>
+    </ol>
+    </li>
   </ol>
   <h2>Downloads</h2>
   <ol>
     <li><a href="{@docRoot}google/play/billing/billing_integrate.html#billing-download">Sample
-    Application</a></li>
+    Application (V3)</a></li>
   </ol>
   <h2>See also</h2>
   <ol>
-    <li><a href="{@docRoot}google/play/billing/billing_overview.html">Overview of In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_integrate.html">Implementing In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_best_practices.html">Security and
-    Design</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_testing.html">Testing In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_admin.html">Administering In-app
-    Billing</a></li>
+    <li><a href="{@docRoot}google/play/billing/api.html">In-app Billing Version 3</a></li>
+    <li><a href="{@docRoot}training/in-app-billing/index.html">Selling In-app Products</a></li>
   </ol>
 </div>
 </div>
+<p>This documentation provides technical reference information for using the In-app Billing Version 3 API. </p>
 
-<p>The following document provides technical reference information for the following:</p>
+<h2 id="billing-codes">Server Response Codes</h2>
+<p>The following table lists all of the server response codes that are sent from Google Play to your application. Google Play sends the response code synchronously as an integer mapped to the {@code RESPONSE_CODE} key in the response {@code Bundle}. Your application must handle all of these response codes.</p>
 
-<ul>
-  <li><a href="#billing-codes">Google Play Server Response Codes for In-app Billing</a></li>
-  <li><a href="#billing-interface">In-app Billing Interface Parameters</a></li>
-  <li><a href="#billing-intents">In-app Billing Broadcast Intents</a></li>
-  <li><a href="#other-intents">Other Intents</a></li>
-  <li><a href="#billing-versions">In-app Billing API Versions</a></li>
-</ul>
-
-<h2 id="billing-codes">Server Response Codes for In-app Billing</h2>
-
-<p>The following table lists all of the server response codes that are sent from Google Play to
-your application. Google Play 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 Google Play.</p>
-
+<p class="table-caption" id="response-codes-table">
+<strong>Table 1.</strong> Summary of response codes for In-app Billing Version 3 API calls.</p>
 <table>
-
-<tr>
-<th>Response Code</th>
-<th>Value</th>
-<th>Description</th>
-</tr>
-<tr>
-  <td><code>RESULT_OK</code></td>
-  <td>0</td>
-  <td>Indicates that the request was sent to the server successfully. When this code is returned in
-  response to a <code>CHECK_BILLING_SUPPORTED</code> request, indicates that billing is
-  supported.</td>
-</tr>
-<tr>
-  <td><code>RESULT_USER_CANCELED</code></td>
-  <td>1</td>
-  <td>Indicates that the user pressed the back button on the checkout page instead of buying the
-  item.</td>
-</tr>
-<tr>
-  <td><code>RESULT_SERVICE_UNAVAILABLE</code></td>
-  <td>2</td>
-  <td>Indicates that the network connection is down.</td>
-</tr>
-<tr>
-  <td><code>RESULT_BILLING_UNAVAILABLE</code></td>
-  <td>3</td>
-  <td>Indicates that in-app billing is not available because the <code>API_VERSION</code> that you
-  specified is not recognized by the Google Play 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>
-  <td>4</td>
-  <td>Indicates that Google Play cannot find the requested item in the application's product
-  list. This can happen if the product ID is misspelled in your <code>REQUEST_PURCHASE</code>
-  request or if an item is unpublished in the application's product list.</td>
-</tr>
-<tr>
-  <td><code>RESULT_DEVELOPER_ERROR</code></td>
-  <td>5</td>
-  <td>Indicates that an 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, such as a
-  request with missing Bundle keys or a request that uses an unrecognized request type.</td>
-</tr>
-<tr>
-  <td><code>RESULT_ERROR</code></td>
-  <td>6</td>
-  <td>Indicates an unexpected server error. For example, this error is triggered if you try to
-purchase an item from yourself, which is not allowed by Google Checkout.</td>
-</tr>
+  <tr>
+    <th scope="col">Response Code</th>
+    <th scope="col">Value</th>
+    <th scope="col">Description</th>
+  </tr>
+  <tr>
+    <td>{@code BILLING_RESPONSE_RESULT_OK}</td>
+    <td>0</td>
+    <td>Success</td>
+  </tr>
+  <tr>
+    <td>{@code BILLING_RESPONSE_RESULT_USER_CANCELED}</td>
+    <td>1</td>
+    <td>User pressed back or canceled a dialog</td>
+  </tr>
+  <tr>
+    <td>{@code BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE}</td>
+    <td>3</td>
+    <td>Billing API version is not supported for the type requested</td>
+  </tr>
+  <tr>
+    <td>{@code BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE}</td>
+    <td>4</td>
+    <td>Requested product is not available for purchase</td>
+  </tr>
+  <tr>
+    <td>{@code BILLING_RESPONSE_RESULT_DEVELOPER_ERROR}</td>
+    <td>5</td>
+    <td>Invalid arguments provided to the API. This error can also indicate that the application was not correctly signed or properly set up for In-app Billing in Google Play, or does not have the necessary permissions in its manifest</td>
+  </tr>
+  <tr>
+    <td>{@code BILLING_RESPONSE_RESULT_ERROR}</td>
+    <td>6</td>
+    <td>Fatal error during the API action</td>
+  </tr>
+  <tr>
+    <td>{@code BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED}</td>
+    <td>7</td>
+    <td>Failure to purchase since item is already owned</td>
+  </tr>
+  <tr>
+    <td>{@code BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED}</td>
+    <td>8</td>
+    <td>Failure to consume since item is not owned</td>
+  </tr>
 </table>
 
-<h2 id="billing-interface">In-app Billing Service Interface</h2>
+<h2 id="billing-interface">API Reference</h2>
+<p>The In-app Billing Version 3 API is defined in the {@code IInAppBillingService.aidl} file, which is included with the Version 3 <a href="{@docRoot}training/in-app-billing/preparing-iab-app.html#GetSample">sample application</a>.</p>
 
-<p>The following section describes the interface for Google Play's 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}google/play/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>
+<h3 id="getSkuDetails">The getSkuDetails() method</h3>
+<p>This method returns product details for a list of product IDs. In the response {@code Bundle} sent by Google Play, the query results are stored in a String {@code ArrayList} mapped to the {@code DETAILS_LIST} key. Each String in the details list contains product details for a single product in JSON format. The fields in the JSON string with the product details 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>
-
+<p class="table-caption" id="product-details-table">
+<strong>Table 2.</strong> Description of JSON fields with product item details returned from a {@code getSkuDetails} request.</p>
 <table>
-
-<tr>
-<th>Key</th>
-<th>Type</th>
-<th>Possible Values</th>
-<th>Required?</th>
-<th>Description</th>
-</tr>
-<tr>
-  <td><code>BILLING_REQUEST</code></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>API_VERSION</code></td>
-  <td><code>int</code></td>
-  <td>  <ul>
-  <li><code>"2"</code> [<a href="#version_2">details</a>]</li>
-  <li><code>"1"</code> [<a href="#version_1">details</a>]</li>
-  </ul></td>
-  <td>Yes</td>
-  <td>The version of Google Play's in-app billing service you want to use. The current version is
-  2.</td>
-</tr>
-<tr>
-  <td><code>PACKAGE_NAME</code></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><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 Google Play's in-app billing service must have a unique product ID, which you
-  specify on the Google Play publisher site.</td>
-</tr>
-<tr>
-  <td><code>NONCE</code></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>PURCHASE_STATE_CHANGED</code> broadcast intent, so you can use this value
-  to verify the integrity of transaction responses form Google Play.</td>
-</tr>
-<tr>
-  <td><code>NOTIFY_IDS</code></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>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><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 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>
+  <tr>
+    <th scope="col">Key</th>
+    <th scope="col">Description</th>
+  </tr>
+  <tr>
+    <td>{@code productId}</td>
+    <td>The product ID for the product.</td>
+  </tr>
+  <tr>
+    <td>{@code type}</td>
+    <td>Value must be “inapp” for an in-app purchase type.</td>
+  </tr>
+  <tr>
+    <td>{@code price}</td>
+    <td>Formatted price of the item, including its currency sign. The price does not include tax.</td>
+  </tr>
+  <tr>
+    <td>{@code title}</td>
+    <td>Title of the product.</td>
+  </tr>
+  <tr>
+    <td>{@code description}</td>
+    <td>Description of the product.</td>
+  </tr>
 </table>
+</p>
 
-<p>The <code>BILLING_REQUEST</code> key can have the following values:</p>
+<h3 id="getBuyIntent">The getBuyIntent() method</h3>
+<p>This method returns a response code integer mapped to the {@code RESPONSE_CODE} key, and a {@code PendingIntent} to launch the puchase flow for the in-app item mapped to the {@code BUY_INTENT} key. When it receives the {@code PendingIntent}, Google Play sends a response {@code Intent} with the data for that purchase order.  The data that is returned in the response {@code Intent} is summarized in table 3.</p>
 
-<ul>
-  <li><code>CHECK_BILLING_SUPPORTED</code>
-    <p>This request verifies that the Google Play application supports in-app billing. You
-    usually send this request when your application first starts up. This request is useful if you
-    want to enable or disable certain UI features that are relevant only to in-app billing.</p>
-  </li>
-  <li><code>REQUEST_PURCHASE</code>
-    <p>This request sends a purchase message to the Google Play application and is the foundation
-    of in-app billing. You send this request when a user indicates that he or she wants to purchase
-    an item in your application. Google Play then handles the financial transaction by displaying
-    the checkout user interface.</p>
-  </li>
-  <li><code>GET_PURCHASE_INFORMATION</code>
-    <p>This request retrieves the details of a purchase state change. A purchase state change can
-    occur when a purchase request is billed successfully or when a user cancels a transaction during
-    checkout. It can also occur when a previous purchase is refunded. Google Play notifies your
-    application when a purchase changes state, so you only need to send this request when there is
-    transaction information to retrieve.</p>
-  </li>
-  <li><code>CONFIRM_NOTIFICATIONS</code>
-    <p>This request acknowledges that your application received the details of a purchase state
-    change. That is, this message confirms that you sent a <code>GET_PURCHASE_INFORMATION</code>
-    request for a given notification and that you received the purchase information for the
-    notification.</p>
-  </li>
-  <li><code>RESTORE_TRANSACTIONS</code>
-    <p>This request retrieves a user's transaction status for managed purchases (see <a
-    href="{@docRoot}google/play/billing/billing_admin.html#billing-purchase-type">Choosing a
-    Purchase Type</a> for more information). You should send this message 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>
-
-<p>Every in-app billing request generates a synchronous response. The response is a {@link
-android.os.Bundle} and can include one or more of the following keys:</p>
-
-<ul>
-  <li><code>RESPONSE_CODE</code>
-    <p>This key provides status information and error information about a request.</p>
-  </li>
-  <li><code>PURCHASE_INTENT</code>
-    <p>This key provides a {@link android.app.PendingIntent}, which you use to launch the checkout
-    activity.</p>
-  </li>
-  <li><code>REQUEST_ID</code>
-    <p>This key provides you with a request identifier, which you can use to match asynchronous
-    responses with requests.</p>
-  </li>
-</ul>
-
-<p>Some of these keys are not relevant to certain types of requests. Table 3 shows which keys are
-returned for each request type.</p>
-
-<p class="table-caption"><strong>Table 3.</strong> Description of Bundle keys that are returned with
-each in-app billing request type.</p>
-
+<p class="table-caption" id="purchase-pendingintent-response-table">
+<strong>Table 3.</strong>  Response data from an In-app Billing Version 3 purchase request.</p>
 <table>
-
-<tr>
-<th>Request Type</th>
-<th>Keys Returned</th>
-<th>Possible Response Codes</th>
-</tr>
-<tr>
-  <td><code>CHECK_BILLING_SUPPORTED</code></td>
-  <td><code>RESPONSE_CODE</code></td>
-  <td><code>RESULT_OK</code>, <code>RESULT_BILLING_UNAVAILABLE</code>, <code>RESULT_ERROR</code>,
-  <code>RESULT_DEVELOPER_ERROR</code></td>
-</tr>
-<tr>
-  <td><code>REQUEST_PURCHASE</code></td>
-  <td><code>RESPONSE_CODE</code>, <code>PURCHASE_INTENT</code>, <code>REQUEST_ID</code></td>
-  <td><code>RESULT_OK</code>, <code>RESULT_ERROR</code>, <code>RESULT_DEVELOPER_ERROR</code></td>
-</tr>
-<tr>
-  <td><code>GET_PURCHASE_INFORMATION</code></td>
-  <td><code>RESPONSE_CODE</code>, <code>REQUEST_ID</code></td>
-  <td><code>RESULT_OK</code>, <code>RESULT_ERROR</code>, <code>RESULT_DEVELOPER_ERROR</code></td>
-</tr>
-<tr>
-  <td><code>CONFIRM_NOTIFICATIONS</code></td>
-  <td><code>RESPONSE_CODE</code>, <code>REQUEST_ID</code></td>
-  <td><code>RESULT_OK</code>, <code>RESULT_ERROR</code>, <code>RESULT_DEVELOPER_ERROR</code></td>
-</tr>
-<tr>
-  <td><code>RESTORE_TRANSACTIONS</code></td>
-  <td><code>RESPONSE_CODE</code>, <code>REQUEST_ID</code></td>
-  <td><code>RESULT_OK</code>, <code>RESULT_ERROR</code>, <code>RESULT_DEVELOPER_ERROR</code></td>
-</tr>
+  <tr>
+    <th scope="col">Key</th>
+    <th scope="col">Description</th>
+  </tr>
+  <tr>
+    <td>{@code RESPONSE_CODE}</td>
+    <td>0 if the purchase was success, error otherwise.</td>
+  </tr>
+  <tr>
+    <td>{@code INAPP_PURCHASE_DATA}</td>
+    <td>
+       A String in JSON format that contains details about the purchase order. See table 4 for a description of the JSON fields.
+    </td>
+  </tr>
+  <tr>
+    <td>{@code INAPP_DATA_SIGNATURE}</td>
+    <td>String containing the signature of the purchase data that was signed with the private key of the developer.</td>
+  </tr>
 </table>
+</p>
 
-<h2 id="billing-intents">In-app Billing Broadcast Intents</h2>
-
-<p>The following section describes the in-app billing broadcast intents that are sent by the Google
-Play 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}google/play/billing/billing_integrate.html#billing-download">sample
-application</a>.</p>
-
-<h4>com.android.vending.billing.RESPONSE_CODE</h4>
-
-<p>This broadcast intent contains a Google Play 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 Google Play 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">Google Play 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>request_id</code>&mdash;a <code>long</code> representing a request ID. A request ID
-  identifies a specific billing request and is returned by Google Play at the time a request is
-  made.</li>
-  <li><code>response_code</code>&mdash;an <code>int</code> representing the Google Play server
-  response code.</li>
-</ul>
-
-<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>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 <code>String</code> representing the notification ID for
-  a given purchase state change. Google Play 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>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. 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 <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>
-
+<p>Table 4 describes the JSON fields that are returned in the response data for a purchase order.</p>
+<p class="table-caption" id="purchase-data-table">
+<strong>Table 4.</strong>  Descriptions of the JSON fields for {@code INAPP_PURCHASE_DATA}.</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. Google Play 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 Google Play server. Your application sends back the <code>notificationId</code> with the
-  <code>GET_PURCHASE_INFORMATION</code> message so Google Play 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 transaction's Merchant
-  Order Number. For transactions dated previous to 5 December 2012, the orderID correcponds to the transaction's 
-  Google Order Number. For more information, see <a href="{@docRoot}google/play/billing/billing_admin.html#orderId">Working
-  with order numbers</a>.</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 Google Play 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), 2
-  (refunded), or 3 (expired, for subscription purchases only).</td>
-</tr>
-<tr>
-  <td>purchaseToken</td>
-  <td>A token that uniquely identifies a subscription purchase for a given item and user pair.
-  You can use the token to specify the subscription when querying for subscription validity.
-  
-  <p><br><em>Supported only in In-app Billing API version 2 and higher.</em></p></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>
+  <tr>
+    <th scope="col">Field</th>
+    <th scope="col">Description</th>
+  </tr>
+  <tr>
+    <td>{@code orderId}</td>
+    <td>A unique order identifier for the transaction. This corresponds to the Google Wallet Order ID.</td>
+  </tr>
+  <tr>
+    <td>{@code packageName}</td>
+    <td>The application package from which the purchase originated.</td>
+  </tr>
+  <tr>
+    <td>{@code 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 Google Play publisher site.</td>
+  </tr>
+  <tr>
+    <td>{@code purchaseTime}</td>
+    <td>The time the product was purchased, in milliseconds since the epoch (Jan 1, 1970).</td>
+  </tr>
+  <tr>
+    <td>{@code purchaseState}</td>
+    <td>The purchase state of the order. Possible values are 0 (purchased), 1 (canceled), or 2 (refunded).</td>
+  </tr>
+  <tr>
+    <td>{@code 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 getBuyIntent} request.</td>
+  </tr>
+  <tr>
+    <td>{@code purchaseToken}</td>
+    <td>A token that uniquely identifies a purchase for a given item and user pair. </td>
+  </tr>
 </table>
+</p>
 
-<!--<h2 id="other-intents">Other Intents</h2> 
-
-<p>The following Intents related to In-app Billing may be useful in your
-implemention. </p> -->
-
-<h2 id="http-api">HTTP API for verification and cancelation</h2>
-
-<p>Google Play offers an HTTP-based API that you can use to remotely query the
-validity of a specific subscription at any time or cancel a subscription. The
-API is designed to be used from your backend servers as a way of securely
-managing subscriptions, as well as extending and integrating subscriptions with
-other services. See <a
-href="{@docRoot}google/play/billing/billing_subscriptions.html#play-dev-api">
-Google Play Android Developer API</a> for more information.</p>
-
-<h2 id="billing-versions">In-app Billing API Versions</h2>
-
-<p>The In-app Billing API is versioned, with each version offering
-additional features to your app. At run time, your app can query the Google Play app to determine
-what version of the API it supports and what features are available. Typically, the Google Play app
-will be updated and will support the latest version of the API. 
-
-<p>The sections below list the supported versions of the In-app Billing API.
-Versions are specified in the <code>API_VERSION</code> key of the Bundle object
-passed in the <code>sendBillingRequest()</code>, which is defined in the defined
-in the <code>IMarketBillingService.aidl</code> file, which is included with the
-in-app billing <a
-href="{@docRoot}google/play/billing/billing_integrate.html#billing-download">
-sample application</a>. For more information, see <a
-href="#billing-interface">In-app Billing Service Interface</a>.</p>
-<h3 id="version_2">In-app Billing version 2</h3>
-
-<p><em>May 2012</em></p>
-
-<ul>
-<li>Adds support for subscriptions. 
-  <ul>
-  <li>Adds a new supported string value, "2", for the <code>API_VERSION</code> key
-  of the Bundle object passed in the <code>sendBillingRequest()</code>.</li>
-  <li>Adds a new JSON field, <code>purchaseToken</code>, to the
-  <code>orders</code> list returned in a <code>PURCHASE_STATE_CHANGED</code>
-  intent. </li> 
-  <li>Adds a new <code>purchaseState</code> value, <code>3</code> (expired), to the
-  <code>orders</code> list returned in a <code>PURCHASE_STATE_CHANGED</code>
-  intent. The value indicates that a subscription has expired and is no longer valid.</li>
-<li>Requires Google Play (Play Store) version 3.5 or higher.</li>
-</ul>
-
-<h3 id="version_1">In-app Billing version 1</h3>
-
-<p><em>March 2011</em></p>
-
-<ul>
-<li>Initial release.</li>
-<li>Requires Google Play/Android Market 2.3.4 or higher.</li>
-</ul>
+<h3 id="getPurchases">The getPurchases() method</h3>
+<p>This method returns the current un-consumed products owned by the user. Table 5 lists the response data that is returned in the {@code Bundle}.</p>
+<p class="table-caption" id="getpurchases-response-table">
+<strong>Table 5.</strong> Response data from a {@code getPurchases} request.</p>
+<table>
+  <tr>
+    <th scope="col">Key</th>
+    <th scope="col">Description</th>
+  </tr>
+  <tr>
+    <td>{@code RESPONSE_CODE}</td>
+    <td>0 if the request was successful, error otherwise.</td>
+  </tr>
+  <tr>
+    <td>{@code INAPP_PURCHASE_ITEM_LIST}</td>
+    <td>{@code StringArrayList} containing the list of productIds of purchases from this app.</td>
+  </tr>
+  <tr>
+    <td>{@code INAPP_PURCHASE_DATA_LIST}</td>
+    <td>{@code StringArrayList} containing the details for purchases from this app. See table 4 for the list of detail information stored in each {@code INAPP_PURCHASE_DATA} item in the list.</td>
+  </tr>
+  <tr>
+    <td>{@code INAPP_DATA_SIGNATURE_LIST}</td>
+    <td>{@code StringArrayList} containing the signatures of purchases from this app.</td>
+  </tr>
+  <tr>
+    <td>{@code INAPP_CONTINUATION_TOKEN}</td>
+    <td>String containing a continuation token to retrieve the next set of in-app products owned by the user. This is only set by the Google Play service if the number of products owned by the user is very large. When a continuation token is present in the response, you must make another call to {@code getPurchases} and pass in the continuation token that you received. The subsequent {@code getPurchases} call returns more purchases and possibly another continuation token.</td>
+  </tr>
+</table>
+</p>
 
diff --git a/docs/html/google/play/billing/billing_testing.jd b/docs/html/google/play/billing/billing_testing.jd
index 4cbcde1..d84814d 100644
--- a/docs/html/google/play/billing/billing_testing.jd
+++ b/docs/html/google/play/billing/billing_testing.jd
@@ -9,53 +9,39 @@
   <ol>
     <li><a href="#billing-testing-static">Testing in-app purchases with static responses</a></li>
     <li><a href="#billing-testing-real">Testing in-app purchases using your own product IDs</a></li>
-
-  </ol>
-  <h2>Downloads</h2>
-  <ol>
-    <li><a href="{@docRoot}google/play/billing/billing_integrate.html#billing-download">Sample
-    Application</a></li>
   </ol>
   <h2>See also</h2>
   <ol>
     <li><a href="{@docRoot}google/play/billing/billing_overview.html">Overview of In-app
     Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_integrate.html">Implementing In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_best_practices.html">Security and
-    Design</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_admin.html">Administering In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_reference.html">In-app Billing
-    Reference</a></li>
-  </ol>
+  <ol>
 </div>
 </div>
 
-<p>The Google Play publisher site provides several tools that help you test your in-app billing
+<p>The Google Play 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
+<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 Google Play application installed. If a device is not running the
-most current Google Play application, your application won't be able to send in-app billing
+most current Google Play application, your application won't be able to send In-app Billing
 requests to Google Play. For general information about how to set up a device for use in
 developing Android applications, see <a href="{@docRoot}tools/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>The following section shows you how to set up and use the In-app Billing test tools.</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
+<p>We recommend that you first test your In-app Billing implementation using static responses from
 Google Play. This enables you to verify that your application is handling the primary Google
 Play 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
+<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 Google Play. No money is transferred when you make in-app billing requests with the
+response from Google Play. 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>
@@ -71,36 +57,34 @@
 install your application on a device, log into the device, and make billing requests using the
 reserved product IDs.</p>
 
-<p>There are four reserved product IDs for testing static in-app billing responses:</p>
+<p>There are four reserved product IDs for testing static In-app Billing responses:</p>
 
 <ul>
   <li><strong>android.test.purchased</strong>
-    <p>When you make an in-app billing request with this product ID, Google Play responds as
+    <p>When you make an In-app Billing request with this product ID, Google Play responds as
     though you successfully purchased an item. The response includes a JSON string, which contains
     fake purchase information (for example, a fake order ID). In some cases, the JSON string is
     signed and the response includes the signature so you can test your signature verification
     implementation using these responses.</p>
   </li>
   <li><strong>android.test.canceled</strong>
-    <p>When you make an in-app billing request with this product ID Google Play responds as
+    <p>When you make an In-app Billing request with this product ID Google Play 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, Google Play responds as
+    <p>When you make an In-app Billing request with this product ID, Google Play responds as
     though the purchase was refunded. Refunds cannot be initiated through Google Play's in-app
     billing service. Refunds must be initiated by you (the merchant). After you process a refund
     request through your Google Checkout account, a refund message is sent to your application by
     Google Play. This occurs only when Google Play gets notification from Google Checkout that
-    a refund has been made. For more information about refunds, see <a
-    href="{@docRoot}google/play/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>
+    a refund has been made. For more information about refunds, see <a href="{@docRoot}google/play/billing/v2/api.html#billing-action-notify">Handling
+IN_APP_NOTIFY messages</a> and <a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&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, Google Play responds as
+    <p>When you make an In-app Billing request with this product ID, Google Play responds as
     though the item being purchased was not listed in your application's product list.</p>
   </li>
 </ul>
@@ -167,7 +151,7 @@
 
 </table>
 
-<p>To make an in-app billing request with a reserved product ID, you simply construct a normal
+<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>
 
@@ -175,8 +159,8 @@
 
 <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>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}tools/building/building-cmdline.html#RunningOnDevice">Running on a
     device</a>.</p>
@@ -187,8 +171,8 @@
   </li>
   <li><strong>Verify that your device is running a supported version of the Google Play
   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
+    <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 Google Play application. To learn how to check the
     version of the Google Play application, see <a
     href="http://market.android.com/support/bin/answer.py?answer=190860">Updating Google
@@ -197,16 +181,16 @@
   <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 Google Play production system. When you send an in-app billing request for a
+<p class="note"><strong>Note</strong>: Making In-app Billing requests with the reserved product IDs
+overrides the usual Google Play 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>
 
 <p>After you finish your static response testing, and you verify that signature verification is
-working in your application, you can test your in-app billing implementation by making actual in-app
-purchases. Testing real in-app purchases enables you to test the end-to-end in-app billing
+working in your application, you can test your In-app Billing implementation by making actual in-app
+purchases. Testing real in-app purchases enables you to test the end-to-end In-app Billing
 experience, including the actual responses from Google Play and the actual checkout flow that
 users will experience in your application.</p>
 
@@ -214,7 +198,7 @@
 testing. You only need to upload your application as a draft application to perform end-to-end
 testing.</p>
 
-<p>To test your in-app billing implementation with actual in-app purchases, you will need to
+<p>To test your In-app Billing implementation with actual in-app purchases, you will need to
 register at least one test account on the Google Play publisher site. You cannot use your
 developer account to test the complete in-app purchase process because Google Checkout does not let
 you buy items from yourself. If you have not set up test accounts before, see <a
@@ -229,7 +213,7 @@
 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>
+<p>To test your In-app Billing implementation with actual purchases, follow these steps:</p>
 
 <ol>
   <li><strong>Upload your application as a draft application to the publisher site.</strong>
@@ -238,7 +222,7 @@
     your application with your release key before you upload it as a draft application. Also, the
     version number of the uploaded application must match the version number of the application you
     load to your device for testing. To learn how to upload an application to Google Play, see
-    <a href="http://market.android.com/support/bin/answer.py?answer=113469">Uploading
+    <a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113469">Uploading
     applications</a>.</p>
   </li>
   <li><strong>Add items to the application's product list.</strong>
@@ -247,14 +231,14 @@
     list</a> to learn how to do this.</p>
   </li>
   <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>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}tools/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
+    <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}google/play/billing/billing_admin.html#billing-testing-setup">test accounts</a>
     that you registered on the Google Play site. If the primary account on your device is not a
@@ -271,8 +255,8 @@
   </li>
   <li><strong>Verify that your device is running a supported version of the Google Play
   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
+    <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 Google Play application. To learn how to check the
     version of the Google Play application, see <a
     href="http://market.android.com/support/bin/answer.py?answer=190860">Updating Google
@@ -284,7 +268,7 @@
 <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>
 
-<p>When you are finished testing your in-app billing implementation, you are ready to
+<p>When you are finished testing your In-app Billing implementation, you are ready to
 publish your application on Google Play. You can follow the normal steps for <a
 href="{@docRoot}tools/publishing/preparing.html">preparing</a>, <a
 href="{@docRoot}tools/publishing/app-signing.html">signing</a>, and <a
diff --git a/docs/html/google/play/billing/index.jd b/docs/html/google/play/billing/index.jd
index c3c7a24..b0d1d13 100644
--- a/docs/html/google/play/billing/index.jd
+++ b/docs/html/google/play/billing/index.jd
@@ -10,8 +10,9 @@
 <div class="sidebox">
   <h2><strong>New in In-App Billing</strong></h2>
   <ul>
-  <li><strong>New order number format</strong>&mdash; Starting 5 December, orders are reported in Merchant Order Number format. See <a href="{@docRoot}google/play/billing/billing_admin.html#orderId">Working with Order Numbers</a> for an example.</li>
-  <li><strong>Free trials</strong>&mdash;You can now offer users a configurable <a href="/google/play/billing/billing_subscriptions.html#trials">free trial period</a> for your in-app subscriptions. You can set up trials with a simple change in the Developer Console&mdash;no change to your app code is needed.</li>
+  <li><strong>In-app Billing Version 3</strong>&mdash;The <a href="{@docRoot}google/play/billing/api.html">latest version</a> of In-app Billing features a synchronous API that is easier to implement and lets you manage products and purchases more effectively.</li>
+  <li><strong>New order number format</strong>&mdash;Starting 5 December, orders are reported in Merchant Order Number format. See <a href="/google/play/billing/billing_admin.html#orderId">Working with Order Numbers</a> for an example.</li>
+  <li><strong>Free trials</strong>&mdash;You can now offer users a configurable <a href="/google/play/billing/v2/billing_subscriptions.html#trials">free trial period</a> for your in-app subscriptions. You can set up trials with a simple change in the Developer Console&mdash;no change to your app code is needed.</li>
  </ul>
 </div>
 </div>
@@ -26,62 +27,35 @@
 handles all checkout details so your application never has to directly process
 any financial transactions. Google Play uses the same checkout backend service as
 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>
+familiar purchase flow.</p>
 
 <p>Any application that you publish through Google Play 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>
+Checkout merchant account.</p>
 
 <p>To help you integrate in-app billing into your application, the Android SDK
 provides a sample application that demonstrates how to sell standard in-app
-products and subscriptions from inside an app. The sample 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>
+products and subscriptions from inside an app.</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}google/play/billing/billing_best_practices.html">Security and Design</a>.</p>
-
-<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). Google Play 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 Google Play's in-app billing service and start integrating it into your
-applications, read the following documents:</p>
+<p>To get started, read the documents below or take the <a href="{@docRoot}training/in-app-billing/index.html">Selling 
+    In-app Products</a> training class.</p>
+</div>
+</div>
 
 <dl>
-  <dt><strong><a href="{@docRoot}google/play/billing/billing_overview.html">In-app
-  Billing Overview</a></strong></dt>
-    <dd>Learn how the service works and what a typical in-app billing implementation looks
-    like.</dd>
-  <dt><strong><a href="{@docRoot}google/play/billing/billing_integrate.html">Implementing
-  In-app Billing</a></strong></dt>
-    <dd>Use this step-by-step guide to start incorporating in-app billing into your
-    application. The instructions apply to both one-time and subscription purchases.</dd>
-    
-    <dt><strong><a href="{@docRoot}google/play/billing/billing_subscriptions.html">Subscriptions</a></strong></dt>
-    <dd>Learn how subscriptions work and how to implement support for them in your app.</dd>
+  <dt><strong><a href="{@docRoot}google/play/billing/billing_overview.html">Overview</a></strong></dt>
+    <dd>Read this document for a description of the underlying concepts in In-app Billing.</dd>
+  <dt><strong><a href="{@docRoot}google/play/billing/api.html">Version 3 API</a></strong></dt>
+    <dd>Read the documents in this section for an overview of the latest version of In-app Billing, as well as implementation details and API reference.</dd>
   <dt><strong><a href="{@docRoot}google/play/billing/billing_best_practices.html">Security
   and Design</a></strong></dt>
-    <dd>Review these best practices to help ensure that your in-app billing implementation is
+    <dd>Review these best practices to help ensure that your In-app Billing implementation is
     secure and well designed.</dd>
   <dt><strong><a href="{@docRoot}google/play/billing/billing_testing.html">Testing In-app
   Billing</a></strong></dt>
-    <dd>Understand how the in-app billing test tools work and learn how to test your in-app billing
+    <dd>Understand how the In-app Billing test tools work and learn how to test your In-app Billing
     implementation.</dd>
   <dt><strong><a href="{@docRoot}google/play/billing/billing_admin.html">Administering
   In-app Billing</a></strong></dt>
     <dd>Learn how to set up your product list, register test accounts, and handle refunds.</dd>
-  <dt><strong><a href="{@docRoot}google/play/billing/billing_reference.html">Reference</a></strong></dt>
-    <dd>Get detailed information about Google Play response codes and the in-app billing
-    interface.</dd>
 </dl>
-
diff --git a/docs/html/google/play/billing/v2/api.jd b/docs/html/google/play/billing/v2/api.jd
new file mode 100644
index 0000000..6b3b758
--- /dev/null
+++ b/docs/html/google/play/billing/v2/api.jd
@@ -0,0 +1,523 @@
+page.title=In-app Billing Version 2
+@jd:body
+
+<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">In-app Billing Version 2 is superseded. Please <a href="{@docRoot}google/play/billing/billing_overview.html#migration">migrate to Version 3</a> at your earliest convenience.</div>
+    <div id="qv-wrapper" style="margin-top:0;">
+<div id="qv">
+
+  <h2>In this document</h2>
+  <ol>
+    <li><a href="#billing-types">Product and Purchase Types</a></li>
+    <li><a href="#billing-arch">Service Architecture</a></li>
+    <li><a href="#billing-msgs">Service Messages</a></li>
+    <ol>
+      <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 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>
+  </ol>
+</div>
+</div>
+
+<p>In-app Billing version 2 is the legacy version of the Google Play In-app
+Billing. Like Version 3, it lets you interact with the Google Play purchase flow
+and payments system indirectly, by means of IPC communication with the Play
+Store app installed on the device. </p>
+
+<p>Unlike Version 3, the Version 2 API is
+asynchronous and uses service messages sent as broadcast intents, so
+it is more complicated than Version 3. </p>
+
+<p>Version 2 supports both unmanaged and managed products, as well as supports
+subscriptions, where Version 3 does not yet offer support for subscriptions. If
+you want to sell subscriptions in your app, you should implement In-app Billing
+Version 2, rather than Version 3. </p>
+
+<p>If you do not need to sell subscriptions, you
+should implement In-app Billing Version 3 instead.</p>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+  <h2>New in In-app Billing V2</h2>
+  <p><strong>Free trials</strong>—You can now offer users a configurable free trial period for
+  your in-app subscriptions. You can set up trials with a simple change in the Developer
+  Console—no change to your app code is needed.</p>
+</div>
+</div>
+
+<h2 id="billing-types">Product Types</h2>
+
+<p>In-app Billing Version supports three different product types
+to give you flexibility in how you monetize your app. In all cases, you define
+your products using the Google Play Developer Console, including product type,
+SKU, price, description, and so on. For more information, see <a
+href="{@docRoot}google/play/billing/billing_admin.html">Administering In-app Billing</a>.</p>
+
+<ul>
+<li><em>Managed per user account</em> &mdash; Items that can be purchased only
+once per user account on Google Play. When a user purchases an item that uses
+the "managed per user account" product type, Google Play permanently stores the
+transaction information for each item on a per-user basis. This enables you to
+later query Google Play to restore the state of the items a specific user has
+purchased. If a user attempts to purchase a managed item that has already been
+purchased, Google Play prevents the user from purchasing the item again and
+displays an "Item already purchased" error.
+
+<p>The "managed" product type is useful if you are selling
+items such as game levels or application features. These items are not transient
+and usually need to be restored whenever a user reinstalls your application,
+wipes the data on their device, or installs your application on a new
+device.</p>
+
+<li><em>Unmanaged</em> &mdash; Items that do not have their transaction
+information stored on Google Play. This means that you cannot later query Google
+Play to retrieve transaction information for those items. For "unmanaged"
+purchases, you are responsible for managing the transaction information. Also,
+Google Play does not attempt to prevent the user from purchasing an item
+multiple times if it uses the "unmanaged" product type. It's up to you to
+control how many times an unmanaged item can be purchased.</p>
+
+<p>The "unmanaged" product type is useful if you are selling consumable items,
+such as fuel or magic spells. These items are consumed within your application
+and are usually purchased multiple times.</p></li>
+
+<li><em>Subscriptions</em> &mdash; Items that are sold with a
+developer-specified, recurring billing interval. When a user purchases a
+subscription, Google Play and its payment processor automatically bill the
+user's account at the specified interval and price, charging the amount to the
+original payment method. Once the user purchases a subscription, Google Play
+continues billing the account indefinitely, without requiring approval or action
+from the user. The user can cancel the subscription at any time. 
+
+<p>Subscriptions can only be sold using the "managed per user account" purchase
+type. As with in-app products, once the user has purchased an in-app product
+there is no refund window. Users desiring refunds must contact the developer
+directly. For more information about subscriptions and how to sell them in your
+apps, see the <a href="{@docRoot}google/play/billing/v2/billing_subscriptions.html">Subscriptions</a>
+document.</p></li>
+</ul>
+
+<h2 id="billing-arch">Service Architecture</h2>
+
+<p>Your app accesses the In-app Billing service using an API that is exposed by
+the Google Play app installed on the device. The Google Play app then uses an
+asynchronous message loop to convey billing requests and responses between your
+application and the Google Play server. In practice, your application never
+directly communicates with the Google Play server (see figure 1). Instead, your
+application sends billing requests to the Google Play application over
+interprocess communication (IPC) and receives purchase responses from the Google
+Play application in the form of asynchronous broadcast intents. Your application
+does not manage any network connections between itself and the Google Play
+server or use any special APIs from the Android platform.</p>
+
+<div class="figure" style="width:440px">
+<img src="/images/billing_arch.png" alt="" height="582" />
+<p class="img-caption">
+  <strong>Figure 1.</strong> Your application sends and receives billing messages through the
+  Google Play application, which handles all communication with the Google Play server.</p>
+</div>
+
+<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>
+
+<p>A typical in-app billing implementation relies on three components:</p>
+<ul>
+  <li>A {@link android.app.Service Service} (named <code>BillingService</code> in the sample application),
+  which processes purchase messages from the application and sends billing requests to the Google
+  Play in-app billing service.</li>
+  <li>A {@link android.content.BroadcastReceiver BroadcastReceiver} (named <code>BillingReceiver</code> in the sample
+  application), which receives all asynchronous billing responses from the Google Play
+  application.</li>
+  <li>A security component (named <code>Security</code> in the sample application), which performs
+  security-related tasks, such as signature verification and nonce generation. For more information
+  about in-app billing security, see <a href="#billing-security">Security controls</a> later in this
+  document.</li>
+</ul>
+
+<p>You may also want to incorporate two other components to support in-app billing:</p>
+<ul>
+  <li>A response {@link android.os.Handler Handler} (named <code>ResponseHandler</code> in the sample
+  application), which provides application-specific processing of purchase notifications, errors,
+  and other status messages.</li>
+  <li>An observer (named <code>PurchaseObserver</code> in the sample application), which is
+  responsible for sending callbacks to your application so you can update your user interface with
+  purchase information and status.</li>
+</ul>
+
+<p>In addition to these components, your application must provide a way to store information about
+users' purchases and some sort of user interface that lets users select items to purchase. You do
+not need to provide a checkout user interface. When a user initiates an in-app purchase, the Google
+Play application presents the checkout user interface to your user. When the user completes the
+checkout process, your application resumes.</p>
+
+<h2 id="billing-msgs">In-app Billing Messages</h2>
+
+<p>When the user initiates a purchase, your application sends billing messages to Google Play's
+in-app billing service (named <code>MarketBillingService</code>) using simple IPC method calls. The
+Google Play application responds to all billing requests synchronously, providing your
+application with status notifications and other information. The Google Play application also
+responds to some billing requests asynchronously, providing your application with error messages and
+detailed transaction information. The following section describes the basic request-response
+messaging that takes place between your application and the Google Play application.</p>
+
+<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/components/aidl.html">Android Interface Definition Language</a> file
+(<code>IMarketBillingService.aidl</code>). You can <a
+href="{@docRoot}google/play/billing/v2/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 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
+its type, 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}google/play/billing/v2/billing_reference.html#billing-interface">In-app Billing
+Service Interface</a>.
+
+<p>One of the most important keys that every request Bundle must have is the
+<code>BILLING_REQUEST</code> key. This key lets you specify the type of billing request you are
+making. Google Play's in-app billing service supports the following five types of billing
+requests:</p>
+
+<ul>
+  <li><code>CHECK_BILLING_SUPPORTED</code>
+    <p>This request verifies that the Google Play application supports in-app billing. You
+    usually send this request when your application first starts up. This request is useful if you
+    want to enable or disable certain UI features that are relevant only to in-app billing.</p>
+  </li>
+  <li><code>REQUEST_PURCHASE</code>
+    <p>This request sends a purchase message to the Google Play application and is the foundation
+    of in-app billing. You send this request when a user indicates that he or she wants to purchase
+    an item in your application. Google Play then handles the financial transaction by displaying
+    the checkout user interface.</p>
+  </li>
+  <li><code>GET_PURCHASE_INFORMATION</code>
+    <p>This request retrieves the details of a purchase state change. A purchase changes state when
+    a requested purchase is billed successfully or when a user cancels a transaction during
+    checkout. It can also occur when a previous purchase is refunded. Google Play notifies your
+    application when a purchase changes state, so you only need to send this request when there is
+    transaction information to retrieve.</p>
+  </li>
+  <li><code>CONFIRM_NOTIFICATIONS</code>
+    <p>This request acknowledges that your application received the details of a purchase state
+    change. Google Play 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 <a
+    href="{@docRoot}google/play/billing/billing_admin.html#billing-purchase-type">managed
+    purchases</a> and <a
+    href="{@docRoot}google/play/billing/billing_admin.html#billing-purchase-type">subscriptions</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>
+
+<h3 id="billing-response">In-app Billing Responses</h3>
+
+<p>The Google Play application responds to in-app billing requests with both synchronous and
+asynchronous responses. The synchronous response is a {@link android.os.Bundle Bundle} with the following
+three keys:</p>
+
+<ul>
+  <li><code>RESPONSE_CODE</code>
+    <p>This key provides status information and error information about a request.</p>
+  </li>
+  <li><code>PURCHASE_INTENT</code>
+    <p>This key provides a {@link android.app.PendingIntent PendingIntent}, which you use to launch the checkout
+    activity.</p>
+  </li>
+  <li><code>REQUEST_ID</code>
+    <p>This key provides you with a request identifier, which you can use to match asynchronous
+    responses with requests.</p>
+  </li>
+</ul>
+<p>Some of these keys are not relevant to every request. For more information, see <a
+href="#billing-message-sequence">Messaging sequence</a> later in this document.</p>
+
+<p>The asynchronous response messages are sent in the form of individual broadcast intents and
+include the following:</p>
+
+<ul>
+    <li><code>com.android.vending.billing.RESPONSE_CODE</code>
+    <p>This response contains a Google Play 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 Google Play 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}google/play/billing/v2/billing_reference.html#billing-codes">Server Response Codes
+    for In-app Billing</a>.</p>
+  </li>
+  <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>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>PURCHASE_STATE_CHANGED</code> intent provides
+your application with the details of one or more billing transactions. An example of this JSON
+string for a subscription item is shown below:</p>
+<pre class="no-pretty-print" style="color:black">{ "nonce" : 1836535032137741465,
+  "orders" :
+    [{ "notificationId" : "android.test.purchased",
+       "orderId" : "transactionId.android.test.purchased",
+       "packageName" : "com.example.dungeons",
+       "productId" : "android.test.purchased",
+       "developerPayload" : "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ",
+       "purchaseTime" : 1290114783411,
+       "purchaseState" : 0,
+       "purchaseToken" : "rojeslcdyyiapnqcynkjyyjh" }]
+}
+</pre>
+
+<p>For more information about the fields in this JSON string, see <a
+href="{@docRoot}google/play/billing/v2/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>, 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 Google Play 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 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.
+    <p class="note"><strong>Note:</strong> You must launch the pending intent from an activity
+    context and not an application context.</p>
+  </li>
+  <li>When the checkout flow finishes (that is, the user successfully purchases the item or cancels
+  the purchase), Google Play 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 Google Play application sends a Bundle with a <code>RESPONSE_CODE</code> key and a 
+  <code>REQUEST_ID</code> key.
+  <li>Google Play 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 Google Play application sends your application a Bundle with a
+  <code>RESPONSE_CODE</code> key and a <code>REQUEST_ID</code> key.</li>
+</ol>
+
+<img src="/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>Keep in mind, you must send a confirmation when you receive transaction information from Google
+Play (step 8 in figure 2). If you don't send a confirmation message, Google Play will
+continue sending <code>IN_APP_NOTIFY</code> messages for the transactions you have not
+confirmed. 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 Google Play indicating
+that you need to deliver the product. Also, as a best practice, your application must be able to
+handle <code>IN_APP_NOTIFY</code> messages that contain multiple orders.</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="/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 Bundle} with a
+<code>RESPONSE_CODE</code> key and a <code>REQUEST_ID</code> key. Next, the Google Play
+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 a
+<code>PURCHASE_STATE_CHANGED</code> broadcast intent, which contains the same type of transaction
+information that is sent during a purchase request. Unlike with a purchase request, however, the transactions
+are given without any associated notification IDs, so you do not need to respond to this
+intent with a <code>CONFIRM_NOTIFICATIONS</code> message. </p>
+
+<p class="note"><strong>Note:</strong> You should use the <code>RESTORE_TRANSACTIONS</code> request
+type only when your application is installed for the first time on a device or when your
+application has been removed from a device and reinstalled.</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="/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 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 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 Google Play server.</p>
+
+<h3 id="billing-action-notify">Handling IN_APP_NOTIFY messages</h3>
+
+<p>Usually, your application receives an <code>IN_APP_NOTIFY</code> broadcast intent from Google
+Play 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. Google Play 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
+Google Play that you have received the purchase state change information.</p>
+
+<p>In some special cases, you may receive multiple <code>IN_APP_NOTIFY</code> messages even though
+you have confirmed receipt of the purchase information, or you may receive
+<code>IN_APP_NOTIFY</code> messages for a purchase change even though you never initiated the
+purchase. Your application must handle both of these special cases.</p>
+
+<h4>Handling multiple IN_APP_NOTIFY messages</h4>
+
+<p>When Google Play receives a <code>CONFIRM_NOTIFICATIONS</code> message for a given
+<code>PURCHASE_STATE_CHANGED</code> message, it usually stops sending <code>IN_APP_NOTIFY</code>
+intents for that <code>PURCHASE_STATE_CHANGED</code> message. Sometimes, however, Google
+Play may send repeated <code>IN_APP_NOTIFY</code> intents for a
+<code>PURCHASE_STATE_CHANGED</code> 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, Google Play
+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
+transaction 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>
+
+<h4>Handling refunds and other unsolicited IN_APP_NOTIFY messages</h4>
+
+<p>There are two cases where your application may 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="/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 may 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, Google Play 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 product type
+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 Google Play receives a refund notification from Google Wallet. In this case, Google
+Play 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>
+
+<p class="caution"><strong>Important:</strong> You cannot use the Google Wallet API to
+issue refunds or cancel in-app billing transactions. You must do this manually through your
+Google Wallet merchant account. However, you can use the Google Wallet API to retrieve order
+information.</p>
+
+<h2 id="billing-security">Security Controls</h2>
+
+<p>To help ensure the integrity of the transaction information that is sent to your application,
+Google Play signs the JSON string that is contained in the <code>PURCHASE_STATE_CHANGED</code>
+broadcast intent. Google Play uses the private key that is associated with the app to create
+this signature. The Developer Console generates an RSA key pair for each app.
+You can find the public key portion of this key pair in the app's publishing details
+in the Developer Console, under <strong>Settings</strong>, in the License Key field.</p>
+
+<p>When Google Play 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 Google Play. 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 Google Play 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}google/play/billing/billing_best_practices.html">Security and Design</a>.</p>
+
+<h2 id="billing-limitations">In-app Billing Requirements and Limitations</h2>
+
+<p>Before you get started with in-app billing, be sure to review the following requirements and
+limitations.</p>
+
+<ul>
+  <li>In-app billing can be implemented only in applications that you publish through Google
+  Play.</li>
+  <li>You must have a Google Wallet Merchant account to use Google Play In-app Billing.</li>
+  <li>In-app billing requires version 2.3.4 (or higher) of the Android Market application.
+  To support subscriptions, version 3.5 or higher of the Google Play app is required. On devices
+  running Android 3.0, version 5.0.12 (or higher) of the MyApps application is required.</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>Google Play 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 Google Play server over
+  the network. </li>
+</ul>
diff --git a/docs/html/google/play/billing/v2/billing_integrate.jd b/docs/html/google/play/billing/v2/billing_integrate.jd
new file mode 100755
index 0000000..7b748a3
--- /dev/null
+++ b/docs/html/google/play/billing/v2/billing_integrate.jd
@@ -0,0 +1,1111 @@
+page.title=Implementing In-app Billing <span style="font-size:16px;">(IAB Version 2)</span>
+@jd:body
+
+<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">In-app Billing Version 2 is superseded. Please <a href="{@docRoot}google/play/billing/billing_overview.html#migration">migrate to Version 3</a> at your earliest convenience.</div>
+    <div id="qv-wrapper" style="margin-top:0;">
+<div id="qv">
+  <h2>In this document</h2>
+  <ol>
+    <li><a href="#billing-download">Downloading the Sample</a></li>
+    <li><a href="#billing-add-aidl">Adding the AIDL file to your project</a></li>
+    <li><a href="#billing-permission">Updating Your Manifest</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-security">Securing Your App</a></li>
+    <li><a href="#billing-implement">Modifying Your Application Code</a></li>
+  </ol>
+  <h2>Downloads</h2>
+  <ol>
+    <li><a href="#billing-download">Sample Application (V2)</a></li>
+  </ol>
+</div>
+</div>
+
+<p>This document helps you implement In-app Billing Version 2 by stepping through the primary
+implementation tasks, using the 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}google/play/billing/v2/api.html">Overview of In-app Billing Version 2</a> and <a
+href="{@docRoot}google/play/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>
+
+<p>To implement in-app billing in your application, you need to do the following:</p>
+<ol>
+  <li><a href="#billing-download">Download the in-app billing sample application</a>.</li>
+  <li><a href="#billing-add-aidl">Add the IMarketBillingService.aidl file</a> to your project.</li>
+  <li><a href="#billing-permission">Update your AndroidManifest.xml file</a>.</li>
+  <li><a href="#billing-service">Create a Service</a> and bind it to the
+  <code>MarketBillingService</code> so your application can send billing requests and receive
+  billing responses from Google Play.</li>
+  <li><a href="#billing-broadcast-receiver">Create a BroadcastReceiver</a> to handle broadcast
+  intents from Google Play.</li>
+  <li><a href="#billing-signatures">Create a security processing component</a> to verify the
+  integrity of the transaction messages that are sent by Google Play.</li>
+  <li><a href="#billing-implement">Modify your application code</a> to support in-app billing.</li>
+</ol>
+
+<h2 id="billing-download">Downloading the Sample Application</h2>
+
+<p>The in-app billing sample application shows you how to perform several tasks that are common to
+all in-app billing implementations, including:</p>
+
+<ul>
+  <li>Sending in-app billing requests to Google Play.</li>
+  <li>Handling synchronous responses from Google Play.</li>
+  <li>Handling broadcast intents (asynchronous responses) from Google Play.</li>
+  <li>Using in-app billing security mechanisms to verify the integrity of billing responses.</li>
+  <li>Creating a user interface that lets users select items for purchase.</li>
+</ul>
+
+<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> In-app billing sample
+application source files.</p>
+
+<table>
+<tr>
+<th>File</th>
+<th>Description</th>
+</tr>
+
+<tr>
+<td>IMarketBillingService.aidl</td>
+<td>Android Interface Definition Library (AIDL) file that defines the IPC interface to Google
+Play's in-app billing service (<code>MarketBillingService</code>).</td>
+</tr>
+
+<tr>
+<td>Dungeons.java</td>
+<td>Sample application file that provides a UI for making purchases and displaying purchase
+history.</td>
+</tr>
+
+<tr>
+<td>PurchaseDatabase.java</td>
+<td>A local database for storing purchase information.</td>
+</tr>
+
+<tr>
+  <td>BillingReceiver.java</td>
+  <td>A {@link android.content.BroadcastReceiver} that receives asynchronous response messages
+  (broadcast intents) from Google Play. Forwards all messages to the
+  <code>BillingService</code>.</td>
+</tr>
+<tr>
+  <td>BillingService.java</td>
+  <td>A {@link android.app.Service} that sends messages to Google Play on behalf of the
+  application by connecting (binding) to the <code>MarketBillingService</code>.</td>
+</tr>
+
+<tr>
+  <td>ResponseHandler.java</td>
+  <td>A {@link android.os.Handler} that contains methods for updating the purchases database and the
+  UI.</td>
+</tr>
+
+<tr>
+  <td>PurchaseObserver.java</td>
+  <td>An abstract class for observing changes related to purchases.</td>
+</tr>
+
+<tr>
+<td>Security.java</td>
+<td>Provides various security-related methods.</td>
+</tr>
+
+<tr>
+<td>Consts.java</td>
+<td>Defines various Google Play constants and sample application constants. All constants that
+are defined by Google Play must be defined the same way in your application.</td>
+</tr>
+
+<tr>
+<td>Base64.java and Base64DecoderException.java</td>
+<td>Provides conversion services from binary to Base64 encoding. The <code>Security</code> class
+relies on these utility classes.</td>
+</tr>
+
+</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 Manager and then
+select the <strong>Google Market Billing package</strong> component (see figure 1), and click <strong>Install
+Selected</strong> to begin the download.</p>
+
+
+<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 Manager saves the component into the
+following directory:</p>
+
+<p><code>&lt;sdk&gt;/extras/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 Google Play.</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 Google Play 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 Google Play. To add your public key to the sample application code, do the
+    following:</p>
+    <ol>
+      <li>Log in to your Google Play <a href="http://play.google.com/apps/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>. Google Play 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}tools/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 Google Play 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 Google Play.</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 Google Play. To learn how to upload an application to Google Play, see <a
+    href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&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}google/play/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 Google Play
+  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}google/play/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 Google Play
+  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 Google Play application. To learn how to check the
+    version of the Google Play application, see <a
+    href="http://market.android.com/support/bin/answer.py?answer=190860">Updating Google
+    Play</a>.</p>
+  </li>
+  <li><strong>Install the application onto your device.</strong>
+    <p>Even though you uploaded the application to Google Play, the application is not published,
+    so you cannot download it from Google Play 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}tools/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}google/play/billing/billing_admin.html#billing-testing-setup">test accounts</a>
+    that you registered on the Google Play publisher 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
+    Wallet 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 Google Play's 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>
+
+<p>If you are using the ADT plug-in with Eclipse, you can just add this file to your
+<code>/src</code> directory. Eclipse will automatically generate the interface file when you build
+your project (which should happen immediately). If you are not using the ADT plug-in, you can put
+the AIDL file into your project and use the Ant tool to build your project so that the
+<code>IMarketBillingService.java</code> file gets generated.</p>
+
+<p>To add the <code>IMarketBillingService.aidl</code> file to your project, do the following:</p>
+
+<ol>
+  <li>Create the following directory in your application's <code>/src</code> directory:
+    <p><code>com/android/vending/billing/</code></p>
+  </li>
+  <li>Copy the <code>IMarketBillingService.aidl</code> file into the
+  <code>sample/src/com/android/vending/billing/</code> directory.</li>
+  <li>Build your application.</li>
+</ol>
+
+<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 Google Play application, which handles all communication between
+your application and the Google Play server. To use the Google Play 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,
+Google Play 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 Google Play, 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 Google
+Play. 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 Google Play 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 Google Play
+application and <code>BillingService</code> is the {@link android.app.Service} that sends requests
+to the Google Play application.</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="com.example.dungeons"
+  android:versionCode="1"
+  android:versionName="1.0"&gt;
+
+  &lt;uses-permission android:name="com.android.vending.BILLING" /&gt;
+
+  &lt;application android:icon="@drawable/icon" android:label="@string/app_name"&gt;
+    &lt;activity android:name=".Dungeons" android:label="@string/app_name"&gt;
+      &lt;intent-filter&gt;
+        &lt;action android:name="android.intent.action.MAIN" /&gt;
+        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
+      &lt;/intent-filter&gt;
+    &lt;/activity&gt;
+
+    &lt;service android:name="BillingService" /&gt;
+
+    &lt;receiver android:name="BillingReceiver"&gt;
+      &lt;intent-filter&gt;
+        &lt;action android:name="com.android.vending.billing.IN_APP_NOTIFY" /&gt;
+        &lt;action android:name="com.android.vending.billing.RESPONSE_CODE" /&gt;
+        &lt;action android:name="com.android.vending.billing.PURCHASE_STATE_CHANGED" /&gt;
+      &lt;/intent-filter&gt;
+    &lt;/receiver&gt;
+
+  &lt;/application&gt;
+&lt;/manifest&gt;
+</pre>
+
+<h2 id="billing-service">Creating a Local Service</h2>
+
+<p>Your application must have a local {@link android.app.Service} to facilitate messaging between
+your application and Google Play. At a minimum, this service must do the following:</p>
+
+<ul>
+  <li>Bind to the <code>MarketBillingService</code>.
+  <li>Send billing requests (as IPC method calls) to the Google Play application. The five types
+  of billing requests include:
+    <ul>
+      <li><code>CHECK_BILLING_SUPPORTED</code> requests</li>
+      <li><code>REQUEST_PURCHASE</code> requests</li>
+      <li><code>GET_PURCHASE_INFORMATION</code> requests</li>
+      <li><code>CONFIRM_NOTIFICATIONS</code> requests</li>
+      <li><code>RESTORE_TRANSACTIONS</code> requests</li>
+    </ul>
+  </li>
+  <li>Handle the synchronous response messages that are returned with each billing request.</li>
+</ul>
+
+<h3>Binding to the MarketBillingService</h3>
+
+<p>Binding to the <code>MarketBillingService</code> is relatively easy if you've already added the
+<code>IMarketBillingService.aidl</code> file to your project. The following code sample shows how to
+use the {@link android.content.Context#bindService bindService()} method to bind a service to the
+<code>MarketBillingService</code>. You could put this code in your service's {@link
+android.app.Activity#onCreate onCreate()} method.</p>
+
+<pre>
+try {
+  boolean bindResult = mContext.bindService(
+    new Intent("com.android.vending.billing.MarketBillingService.BIND"), this,
+    Context.BIND_AUTO_CREATE);
+  if (bindResult) {
+    Log.i(TAG, "Service bind successful.");
+  } else {
+    Log.e(TAG, "Could not bind to the MarketBillingService.");
+  }
+} catch (SecurityException e) {
+  Log.e(TAG, "Security exception: " + e);
+}
+</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>
+
+<pre>
+/**
+  * The Android system calls this when we are connected to the MarketBillingService.
+  */
+  public void onServiceConnected(ComponentName name, IBinder service) {
+    Log.i(TAG, "MarketBillingService connected.");
+    mService = IMarketBillingService.Stub.asInterface(service);
+  }
+</pre>
+
+<p>You can now use the <code>mService</code> reference to invoke the
+<code>sendBillingRequest()</code> method.</p>
+
+<p>For a complete implementation of a service that binds to the <code>MarketBillingService</code>,
+see the <code>BillingService</code> class in the sample application.</p>
+
+<h3>Sending billing requests to the MarketBillingService</h3>
+
+<p>Now that your {@link android.app.Service} has a reference to the
+<code>IMarketBillingService</code> interface, you can use that reference to send billing requests
+(via IPC method calls) to the <code>MarketBillingService</code>. The
+<code>MarketBillingService</code> IPC interface exposes a single public method
+(<code>sendBillingRequest()</code>), which takes a single {@link android.os.Bundle} parameter. The
+Bundle that you deliver with this method specifies the type of request you want to perform, using
+various key-value pairs. For instance, one key indicates the type of request you are making, another
+indicates the item being purchased, and another identifies your application. The
+<code>sendBillingRequest()</code> method immediately returns a Bundle containing an initial response
+code. However, this is not the complete purchase response; the complete response is delivered with
+an asynchronous broadcast intent. For more information about the various Bundle keys that are
+supported by the <code>MarketBillingService</code>, see <a
+href="{@docRoot}google/play/billing/v2/billing_reference.html#billing-interface">In-app Billing
+Service Interface</a>.</p>
+
+<p>You can use the <code>sendBillingRequest()</code> method to send five types of billing requests.
+The five request types are specified using the <code>BILLING_REQUEST</code> Bundle key. This Bundle
+key can have the following five values:</p>
+
+<ul>
+  <li><code>CHECK_BILLING_SUPPORTED</code>&mdash;verifies that the Google Play application
+  supports in-app billing and the version of the In-app Billing API available.</li>
+  <li><code>REQUEST_PURCHASE</code>&mdash;sends a purchase request for an in-app item.</li>
+  <li><code>GET_PURCHASE_INFORMATION</code>&mdash;retrieves transaction information for a purchase
+  or refund.</li>
+  <li><code>CONFIRM_NOTIFICATIONS</code>&mdash;acknowledges that you received the transaction
+  information for a purchase or refund.</li>
+  <li><code>RESTORE_TRANSACTIONS</code>&mdash;retrieves a user's transaction history for <a
+  href="{@docRoot}google/play/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 {@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) {
+  Bundle request = new Bundle();
+  request.putString(BILLING_REQUEST, method);
+  request.putInt(API_VERSION, 1);
+  request.putString(PACKAGE_NAME, getPackageName());
+  return request;
+</pre>
+
+<p>To use this helper method, you pass in a <code>String</code> that corresponds to one of the five
+types of billing requests. The method returns a Bundle that has the three required keys defined. The
+following sections show you how to use this helper method when you send a billing request.</p>
+
+<p class="caution"><strong>Important</strong>: You must make all in-app billing requests from your
+application's main thread.</p>
+
+<h4>Verifying that in-app billing is supported (CHECK_BILLING_SUPPPORTED)</h4>
+
+<p>The following code sample shows how to verify whether the Google Play application supports
+in-app billing and confirm what version of the API it supports. In the sample, <code>mService</code>
+is an instance of the <code>MarketBillingService</code> interface.</p>
+
+<pre>
+/**
+* Request type is CHECK_BILLING_SUPPORTED
+*/
+  Bundle request = makeRequestBundle("CHECK_BILLING_SUPPORTED");
+  Bundle response = mService.sendBillingRequest(request);
+  // 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>. If you are offering subscriptions in
+your app, set the API_VERSION key to a value of "2", to confirm that In-app Billing v2 is
+available. For an examnple, see
+<a href="{@docRoot}google/play/billing/v2/billing_subscriptions.html#version">Subscriptions</a>.</p>
+
+<p>The <code>CHECK_BILLING_SUPPORTED</code> 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;the spedified version of in-app billing is supported.</li>
+  <li><code>RESULT_BILLING_UNAVAILABLE</code>&mdash;in-app billing is not available because the 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 Google Play
+  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 Google Play 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 Google Play</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>
+
+<ul>
+  <li>Send the <code>REQUEST_PURCHASE</code> request.</li>
+  <li>Launch the {@link android.app.PendingIntent} that is returned from the Google Play
+  application.</li>
+  <li>Handle the broadcast intents that are sent by the Google Play application.</li>
+</ul>
+
+<h5>Making the request</h5>
+
+<p>You must specify four keys in the request {@link android.os.Bundle}. The following code sample
+shows how to set these keys and make a purchase request for a single in-app item. In the sample,
+<code>mProductId</code> is the Google Play product ID of an in-app item (which is listed in the
+application's <a href="{@docRoot}google/play/billing/billing_admin.html#billing-list-setup">product
+list</a>), and <code>mService</code> is an instance of the <code>MarketBillingService</code>
+interface.</p>
+
+<pre>
+/**
+* Request type is REQUEST_PURCHASE
+*/
+  Bundle request = makeRequestBundle("REQUEST_PURCHASE");
+  request.putString(ITEM_ID, mProductId);
+  // Request is for a standard in-app product
+  request.putString(ITEM_TYPE, "inapp");
+  // Note that the developer payload is optional.
+  if (mDeveloperPayload != null) {
+    request.putString(DEVELOPER_PAYLOAD, mDeveloperPayload);
+  }
+  Bundle response = mService.sendBillingRequest(request);
+  // 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 <code>ITEM_ID</code> key is then added
+to the Bundle prior to invoking the <code>sendBillingRequest()</code> method.</p>
+
+<p>The request returns a synchronous {@link android.os.Bundle} response, which contains three keys:
+<code>RESPONSE_CODE</code>, <code>PURCHASE_INTENT</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. The
+<code>PURCHASE_INTENT</code> key provides you with a {@link android.app.PendingIntent}, which you
+can use to launch the checkout UI.</p>
+
+<h5>Using 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 <code>PurchaseObserver.java</code> file in the sample
+application.</p>
+
+<pre>
+void startBuyPageActivity(PendingIntent pendingIntent, Intent intent) {
+  if (mStartIntentSender != null) {
+    // This is on Android 2.0 and beyond.  The in-app checkout page activity
+    // will be on the activity stack of the application.
+    try {
+      // This implements the method call:
+      // mActivity.startIntentSender(pendingIntent.getIntentSender(),
+      //     intent, 0, 0, 0);
+      mStartIntentSenderArgs[0] = pendingIntent.getIntentSender();
+      mStartIntentSenderArgs[1] = intent;
+      mStartIntentSenderArgs[2] = Integer.valueOf(0);
+      mStartIntentSenderArgs[3] = Integer.valueOf(0);
+      mStartIntentSenderArgs[4] = Integer.valueOf(0);
+      mStartIntentSender.invoke(mActivity, mStartIntentSenderArgs);
+    } catch (Exception e) {
+      Log.e(TAG, "error starting activity", e);
+      }
+  } else {
+    // This is on Android 1.6. The in-app checkout page activity will be on its
+    // own separate activity stack instead of on the activity stack of
+    // the application.
+    try {
+      pendingIntent.send(mActivity, 0 /* code */, intent);
+    } catch (CanceledException e) {
+      Log.e(TAG, "error starting activity", e);
+      }
+  }
+}
+</pre>
+
+<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 Google Play 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 Google Play application sends a <code>RESPONSE_CODE</code> broadcast intent,
+which provides error information about the request. If the request does not generate an
+error, the <code>RESPONSE_CODE</code> broadcast intent returns <code>RESULT_OK</code>, which
+indicates that the request was successfully sent. (To be clear, a <code>RESULT_OK</code> response
+does not indicate that the requested purchase was successful; it indicates that the request was sent
+successfully to Google Play.)</p>
+
+<p>Next, when the requested transaction changes state (for example, the purchase is successfully
+charged to a credit card or the user cancels the purchase), the Google Play 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 class="note"><strong>Note:</strong> The Google Play application also sends
+an <code>IN_APP_NOTIFY</code> for refunds. For more information, see <a
+href="{@docRoot}google/play/billing/v2/api.html#billing-action-notify">Handling
+IN_APP_NOTIFY messages</a>.</p>
+
+<p>Because the purchase process is not instantaneous and can take several seconds (or more), you
+must assume that a purchase request is pending from the time you receive a <code>RESULT_OK</code>
+message until you receive an <code>IN_APP_NOTIFY</code> message for the transaction. While the
+transaction is pending, the Google Play checkout UI displays an "Authorizing purchase..."
+notification; however, this notification is dismissed after 60 seconds and you should not rely on
+this notification as your primary means of conveying transaction status to users. Instead, we
+recommend that you do the following:</p>
+
+<ul>
+  <li>Add an {@link android.app.Activity} to your application that shows users the status of pending
+and completed in-app purchases.</li>
+  <li>Use a <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">status
+bar notification</a> to keep users informed about the progress of a purchase.</li>
+</ul>
+
+<p>To use these two UI elements, you could invoke a status bar notification with a ticker-text
+message that says "Purchase pending" when your application receives a <code>RESULT_OK</code>
+message. Then, when your application receives an <code>IN_APP_NOTIFY</code> message, you could
+update the notification with a new message that says "Purchase succeeded" or "Purchase failed." When
+a user touches the expanded status bar notification, you could launch the activity that shows the
+status of pending and completed in-app purchases.</p>
+
+<p>If you use some other UI technique to inform users about the state of a pending transaction,
+be sure that your pending status UI does not block your application. For example, you should avoid
+using a hovering progress wheel to convey the status of a pending transaction because a pending
+transaction could last a long time, particularly if a device loses network connectivity and cannot
+receive transaction updates from Google Play.</p>
+
+<p class="caution"><strong>Important:</strong> If a user purchases a managed item, you must prevent
+the user from purchasing the item again while the original transaction is pending. If a user
+attempts to purchase a managed item twice, and the first transaction is still pending, Google
+Play will display an error to the user; however, Google Play will not send an error to your
+application notifying you that the second purchase request was canceled. This might cause your
+application to get stuck in a pending state while it waits for an <code>IN_APP_NOTIFY</code> message
+for the second purchase request.</p>
+
+<h4>Retrieving transaction information for a purchase or refund (GET_PURCHASE_INFORMATION)</h4>
+
+<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>
+
+<pre>
+/**
+* Request type is GET_PURCHASE_INFORMATION
+*/
+  Bundle request = makeRequestBundle("GET_PURCHASE_INFORMATION");
+  request.putLong(REQUEST_NONCE, mNonce);
+  request.putStringArray(NOTIFY_IDS, mNotifyIds);
+  Bundle response = mService.sendBillingRequest(request);
+  // 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 Google Play 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 Google Play 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 Google Play 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>
+
+<p>To acknowledge that you received transaction information you send a
+<code>CONFIRM_NOTIFICATIONS</code> request. You must specify four 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>
+
+<pre>
+/**
+* Request type is CONFIRM_NOTIFICATIONS
+*/
+  Bundle request = makeRequestBundle("CONFIRM_NOTIFICATIONS");
+  request.putStringArray(NOTIFY_IDS, mNotifyIds);
+  Bundle response = mService.sendBillingRequest(request);
+  // 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>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;a
+<code>RESPONSE_CODE</code> broadcast intent. This broadcast intent provides status and error
+information about the request.</p>
+
+<p>You must send a confirmation when you receive transaction information from Google Play. If you
+don't send a confirmation message, Google Play will continue sending
+<code>IN_APP_NOTIFY</code> messages for the transactions you have not confirmed. Also,
+your application must be able to handle <code>IN_APP_NOTIFY</code> messages that contain multiple
+orders.</p>
+
+<p>In addition, 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 Google Play indicating
+that you need to deliver the product.</p>
+
+<h4>Restoring transaction information (RESTORE_TRANSACTIONS)</h4>
+
+<p>To restore a user's transaction information, you send a <code>RESTORE_TRANSACTIONS</code>
+request. You must specify four 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>
+
+<pre>
+/**
+* Request type is RESTORE_TRANSACTIONS
+*/
+  Bundle request = makeRequestBundle("RESTORE_TRANSACTIONS");
+  request.putLong(REQUEST_NONCE, mNonce);
+  Bundle response = mService.sendBillingRequest(request);
+  // 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 Google Play 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 Google Play 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 Google Play 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>
+
+<p class="note"><strong>Note:</strong> You should use the <code>RESTORE_TRANSACTIONS</code>
+request type only when your application is installed for the first time on a device or when your
+application has been removed from a device and reinstalled.</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 Google Play 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}google/play/billing/billing_best_practices.html">Security and Design</a>.</p>
+
+<h2 id="billing-broadcast-receiver">Creating a BroadcastReceiver</h2>
+
+<p>The Google Play 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>com.android.vending.billing.RESPONSE_CODE
+  <p>This broadcast intent contains a Google Play 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}google/play/billing/v2/billing_reference.html#billing-codes">Google Play Response
+  Codes for In-app Billing</a>.</p>
+  </li>
+  <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}google/play/billing/v2/billing_reference.html#billing-intents">In-app Billing
+  Broadcast Intents</a></p>
+  </li>
+  <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}google/play/billing/v2/billing_reference.html#billing-intents">In-app Billing
+  Broadcast Intents</a></p>
+  </li>
+</ul>
+
+<p>Each of these broadcast intents provide intent extras, which your {@link
+android.content.BroadcastReceiver} must handle. The intent extras are listed in the following table
+(see table 1).</p>
+
+<p class="table-caption"><strong>Table 1.</strong> Description of broadcast intent extras that are
+sent in response to billing requests.</p>
+
+<table>
+
+<tr>
+<th>Intent</th>
+<th>Extra</th>
+<th>Description</th>
+</tr>
+<tr>
+  <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 Google Play at the time a request is made.</td>
+</tr>
+<tr>
+  <td><code>com.android.vending.billing.RESPONSE_CODE</code></td>
+  <td><code>response_code</code></td>
+  <td>An <code>int</code> representing the actual Google Play server response code.</td>
+</tr>
+<tr>
+  <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.
+  Google Play 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>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>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>
+
+<p>The following code sample shows how to handle these broadcast intents and intent extras within a
+{@link android.content.BroadcastReceiver}. The BroadcastReceiver in this case is named
+<code>BillingReceiver</code>, just as it is in the sample application.</p>
+
+<pre>
+public class BillingReceiver extends BroadcastReceiver {
+
+  private static final String TAG = "BillingReceiver";
+
+  // Intent actions that we receive in the BillingReceiver from Google Play.
+  // These are defined by Google Play and cannot be changed.
+  // The sample application defines these in the Consts.java file.
+  public static final String ACTION_NOTIFY = "com.android.vending.billing.IN_APP_NOTIFY";
+  public static final String ACTION_RESPONSE_CODE = "com.android.vending.billing.RESPONSE_CODE";
+  public static final String ACTION_PURCHASE_STATE_CHANGED =
+    "com.android.vending.billing.PURCHASE_STATE_CHANGED";
+
+  // The intent extras that are passed in an intent from Google Play.
+  // These are defined by Google Play and cannot be changed.
+  // The sample application defines these in the Consts.java file.
+  public static final String NOTIFICATION_ID = "notification_id";
+  public static final String INAPP_SIGNED_DATA = "inapp_signed_data";
+  public static final String INAPP_SIGNATURE = "inapp_signature";
+  public static final String INAPP_REQUEST_ID = "request_id";
+  public static final String INAPP_RESPONSE_CODE = "response_code";
+
+
+  &#64;Override
+  public void onReceive(Context context, Intent intent) {
+    String action = intent.getAction();
+    if (ACTION_PURCHASE_STATE_CHANGED.equals(action)) {
+      String signedData = intent.getStringExtra(INAPP_SIGNED_DATA);
+      String signature = intent.getStringExtra(INAPP_SIGNATURE);
+      // Do something with the signedData and the signature.
+    } else if (ACTION_NOTIFY.equals(action)) {
+      String notifyId = intent.getStringExtra(NOTIFICATION_ID);
+      // Do something with the notifyId.
+    } else if (ACTION_RESPONSE_CODE.equals(action)) {
+      long requestId = intent.getLongExtra(INAPP_REQUEST_ID, -1);
+      int responseCodeIndex = intent.getIntExtra(INAPP_RESPONSE_CODE,
+        ResponseCode.RESULT_ERROR.ordinal());
+      // Do something with the requestId and the responseCodeIndex.
+    } else {
+      Log.w(TAG, "unexpected action: " + action);
+    }
+  }
+  // Perform other processing here, such as forwarding intent messages to your local service.
+}
+</pre>
+
+<p>In addition to receiving broadcast intents from the Google Play 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}google/play/billing/billing_best_practices.html">Security and Design </a>.</p>
+
+<h2 id="billing-security">Securing Your Application</h2>
+
+<p>To help ensure the integrity of the transaction information that is sent to your application,
+Google Play signs the JSON string that is contained in the <code>PURCHASE_STATE_CHANGED</code>
+broadcast intent. Google Play 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 Google Play licensing.</p>
+
+<p>When Google Play 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 Google Play. 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 Google Play 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}google/play/billing/billing_best_practices.html">Security and Design</a>.</p>
+
+<h3 id="billing-signatures">Verifying signatures and nonces</h3>
+
+<p>Google Play's in-app billing service uses two mechanisms to help verify the integrity of the
+transaction information you receive from Google Play: 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;();
+
+  public static long generateNonce() {
+    long nonce = RANDOM.nextLong();
+    sKnownNonces.add(nonce);
+    return nonce;
+  }
+
+  public static void removeNonce(long nonce) {
+    sKnownNonces.remove(nonce);
+  }
+
+  public static boolean isNonceKnown(long nonce) {
+    return sKnownNonces.contains(nonce);
+  }
+</pre>
+
+<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}google/play/billing/billing_best_practices.html">Security and Design</a> and
+obfuscate your code.</p>
+
+<p>You will need to use your Google Play public key to perform the signature verification. The
+following procedure shows you how to retrieve Base64-encoded public key from the Google Play
+publisher site.</p>
+
+<ol>
+  <li>Log in to your <a href="http://play.google.com/apps/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.</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>
+
+<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>
+
+<p>After you finish adding in-app billing components to your project, you are ready to modify your
+application's code. For a typical implementation, like the one that is demonstrated in the sample
+application, this means you need to write code to do the following: </p>
+
+<ul>
+  <li>Create a storage mechanism for storing users' purchase information.</li>
+  <li>Create a user interface that lets users select items for purchase.</li>
+</ul>
+
+<p>The sample code in <code>Dungeons.java</code> shows you how to do both of these tasks.</p>
+
+<h3>Creating a storage mechanism for storing purchase information</h3>
+
+<p>You must set up a database or some other mechanism for storing users' purchase information. The
+sample application provides an example database (PurchaseDatabase.java); however, the example
+database has been simplified for clarity and does not exhibit the security best practices that we
+recommend. If you have a remote server, we recommend that you store purchase information on your
+server instead of in a local database on a device. For more information about security best
+practices, see <a href="{@docRoot}google/play/billing/billing_best_practices.html">Security and
+Design</a>.</p>
+
+<p class="note"><strong>Note</strong>: If you store any purchase information on a device, be sure to
+encrypt the data and use a device-specific encryption key. Also, if the purchase type for any of
+your items is "unmanaged," we recommend that you back up the purchase information for these items to
+a remote server or use Android's <a href="{@docRoot}guide/topics/data/backup.html">data
+backup</a> framework to back up the purchase information. Backing up purchase information for
+unmanaged items is important because unmanaged items cannot be restored by using the
+<code>RESTORE_TRANSACTIONS</code> request type.</p>
+
+<h3>Creating a user interface for selecting items</h3>
+
+<p>You must provide users with a means for selecting items that they want to purchase. Google
+Play provides the checkout user interface (which is where the user provides a form of payment and
+approves the purchase), but your application must provide a control (widget) that invokes the
+<code>sendBillingRequest()</code> method when a user selects an item for purchase.</p>
+
+<p>You can render the control and trigger the <code>sendBillingRequest()</code> method any way you
+want. The sample application uses a spinner widget and a button to present items to a user and
+trigger a billing request (see <code>Dungeons.java</code>). The user interface also shows a list of
+recently purchased items.</p>
+
diff --git a/docs/html/google/play/billing/v2/billing_reference.jd b/docs/html/google/play/billing/v2/billing_reference.jd
new file mode 100644
index 0000000..fb35685
--- /dev/null
+++ b/docs/html/google/play/billing/v2/billing_reference.jd
@@ -0,0 +1,415 @@
+page.title=In-app Billing Reference <span style="font-size:16px;">(IAB Version 2)</span>
+@jd:body
+
+<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">In-app Billing Version 2 is superseded. Please <a href="{@docRoot}google/play/billing/billing_overview.html#migration">migrate to Version 3</a> at your earliest convenience.</div>
+    <div id="qv-wrapper" style="margin-top:0;">
+<div id="qv">
+<h2>In this document</h2>
+  <ol>
+  <li><a href="#billing-codes">Server Response Codes</a></li>
+  <li><a href="#billing-interface">API Reference</a></li>
+  <li><a href="#billing-intents">Broadcast Intents</a></li>
+  <li><a href="#http-api">REST API for Subscriptions</a></li>
+  </ol>	
+
+<h2>Related Samples</h2>
+  <ol>
+  <li><a href="{@docRoot}google/play/billing/v2/billing_integrate.html#billing-download">Sample
+    Application (V2)</a></li>
+  </ol>  
+
+</div>
+</div>
+<p>This documentation provides technical reference information for using the In-app Billing Version 2 API. </p>
+
+<h2 id="billing-codes">Server Response Codes</h2>
+<p>The following table lists all of the server response codes that are sent from Google Play to
+your application. Google Play 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 6.</strong> Summary of response
+codes returned by Google Play.</p>
+
+<table>
+<tr>
+<th>Response Code</th>
+<th>Value</th>
+<th>Description</th>
+</tr>
+<tr>
+  <td><code>RESULT_OK</code></td>
+  <td>0</td>
+  <td>Indicates that the request was sent to the server successfully. When this code is returned in
+  response to a <code>CHECK_BILLING_SUPPORTED</code> request, indicates that billing is
+  supported.</td>
+</tr>
+<tr>
+  <td><code>RESULT_USER_CANCELED</code></td>
+  <td>1</td>
+  <td>Indicates that the user pressed the back button on the checkout page instead of buying the
+  item.</td>
+</tr>
+<tr>
+  <td><code>RESULT_SERVICE_UNAVAILABLE</code></td>
+  <td>2</td>
+  <td>Indicates that the network connection is down.</td>
+</tr>
+<tr>
+  <td><code>RESULT_BILLING_UNAVAILABLE</code></td>
+  <td>3</td>
+  <td>Indicates that In-app Billing is not available because the <code>API_VERSION</code> that you
+  specified is not recognized by the Google Play 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>
+  <td>4</td>
+  <td>Indicates that Google Play cannot find the requested item in the application's product
+  list. This can happen if the product ID is misspelled in your <code>REQUEST_PURCHASE</code>
+  request or if an item is unpublished in the application's product list.</td>
+</tr>
+<tr>
+  <td><code>RESULT_DEVELOPER_ERROR</code></td>
+  <td>5</td>
+  <td>Indicates that an 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, such as a
+  request with missing Bundle keys or a request that uses an unrecognized request type.</td>
+</tr>
+<tr>
+  <td><code>RESULT_ERROR</code></td>
+  <td>6</td>
+  <td>Indicates an unexpected server error. For example, this error is triggered if you try to
+purchase an item from yourself, which is not allowed by Google Wallet.</td>
+</tr>
+</table>
+</p>
+
+<h3 id="billing-interface">In-app billing Version 2 API reference</h3>
+
+<p>The following section describes the interface for Google Play's 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}google/play/billing/v2/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 7.</p>
+
+<p class="table-caption"><strong>Table 7.</strong> Description of Bundle keys passed in a
+<code>sendBillingRequest()</code> request.</p>
+
+<table>
+
+<tr>
+<th>Key</th>
+<th>Type</th>
+<th>Possible Values</th>
+<th>Required?</th>
+<th>Description</th>
+</tr>
+<tr>
+  <td><code>BILLING_REQUEST</code></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>API_VERSION</code></td>
+  <td><code>int</code></td>
+  <td>  <ul>
+  <li><code>"2"</code> [<a href="#version_2">details</a>]</li>
+  <li><code>"1"</code> [<a href="#version_1">details</a>]</li>
+  </ul></td>
+  <td>Yes</td>
+  <td>The version of Google Play's In-app Billing service you want to use.</td>
+</tr>
+<tr>
+  <td><code>PACKAGE_NAME</code></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><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 Google Play's In-app Billing service must have a unique product ID, which you
+  specify on the Google Play publisher site.</td>
+</tr>
+<tr>
+  <td><code>NONCE</code></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>PURCHASE_STATE_CHANGED</code> broadcast intent, so you can use this value
+  to verify the integrity of transaction responses form Google Play.</td>
+</tr>
+<tr>
+  <td><code>NOTIFY_IDS</code></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>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><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 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>
+
+<p>The <code>BILLING_REQUEST</code> key can have the following values:</p>
+
+<ul>
+  <li><code>CHECK_BILLING_SUPPORTED</code>
+    <p>This request verifies that the Google Play application supports In-app Billing. You
+    usually send this request when your application first starts up. This request is useful if you
+    want to enable or disable certain UI features that are relevant only to In-app Billing.</p>
+  </li>
+  <li><code>REQUEST_PURCHASE</code>
+    <p>This request sends a purchase message to the Google Play application and is the foundation
+    of In-app Billing. You send this request when a user indicates that he or she wants to purchase
+    an item in your application. Google Play then handles the financial transaction by displaying
+    the checkout user interface.</p>
+  </li>
+  <li><code>GET_PURCHASE_INFORMATION</code>
+    <p>This request retrieves the details of a purchase state change. A purchase state change can
+    occur when a purchase request is billed successfully or when a user cancels a transaction during
+    checkout. It can also occur when a previous purchase is refunded. Google Play notifies your
+    application when a purchase changes state, so you only need to send this request when there is
+    transaction information to retrieve.</p>
+  </li>
+  <li><code>CONFIRM_NOTIFICATIONS</code>
+    <p>This request acknowledges that your application received the details of a purchase state
+    change. That is, this message confirms that you sent a <code>GET_PURCHASE_INFORMATION</code>
+    request for a given notification and that you received the purchase information for the
+    notification.</p>
+  </li>
+  <li><code>RESTORE_TRANSACTIONS</code>
+    <p>This request retrieves a user's transaction status for managed purchases (see <a
+    href="{@docRoot}google/play/billing/billing_admin.html#billing-purchase-type">Choosing a
+    Purchase Type</a> for more information). You should send this message 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>
+
+<p>Every In-app Billing request generates a synchronous response. The response is a {@link
+android.os.Bundle} and can include one or more of the following keys:</p>
+
+<ul>
+  <li><code>RESPONSE_CODE</code>
+    <p>This key provides status information and error information about a request.</p>
+  </li>
+  <li><code>PURCHASE_INTENT</code>
+    <p>This key provides a {@link android.app.PendingIntent}, which you use to launch the checkout
+    activity.</p>
+  </li>
+  <li><code>REQUEST_ID</code>
+    <p>This key provides you with a request identifier, which you can use to match asynchronous
+    responses with requests.</p>
+  </li>
+</ul>
+
+<p>Some of these keys are not relevant to certain types of requests. Table 8 shows which keys are
+returned for each request type.</p>
+
+<p class="table-caption"><strong>Table 8.</strong> Description of Bundle keys that are returned with
+each In-app Billing request type.</p>
+
+<table>
+
+<tr>
+<th>Request Type</th>
+<th>Keys Returned</th>
+<th>Possible Response Codes</th>
+</tr>
+<tr>
+  <td><code>CHECK_BILLING_SUPPORTED</code></td>
+  <td><code>RESPONSE_CODE</code></td>
+  <td><code>RESULT_OK</code>, <code>RESULT_BILLING_UNAVAILABLE</code>, <code>RESULT_ERROR</code>,
+  <code>RESULT_DEVELOPER_ERROR</code></td>
+</tr>
+<tr>
+  <td><code>REQUEST_PURCHASE</code></td>
+  <td><code>RESPONSE_CODE</code>, <code>PURCHASE_INTENT</code>, <code>REQUEST_ID</code></td>
+  <td><code>RESULT_OK</code>, <code>RESULT_ERROR</code>, <code>RESULT_DEVELOPER_ERROR</code></td>
+</tr>
+<tr>
+  <td><code>GET_PURCHASE_INFORMATION</code></td>
+  <td><code>RESPONSE_CODE</code>, <code>REQUEST_ID</code></td>
+  <td><code>RESULT_OK</code>, <code>RESULT_ERROR</code>, <code>RESULT_DEVELOPER_ERROR</code></td>
+</tr>
+<tr>
+  <td><code>CONFIRM_NOTIFICATIONS</code></td>
+  <td><code>RESPONSE_CODE</code>, <code>REQUEST_ID</code></td>
+  <td><code>RESULT_OK</code>, <code>RESULT_ERROR</code>, <code>RESULT_DEVELOPER_ERROR</code></td>
+</tr>
+<tr>
+  <td><code>RESTORE_TRANSACTIONS</code></td>
+  <td><code>RESPONSE_CODE</code>, <code>REQUEST_ID</code></td>
+  <td><code>RESULT_OK</code>, <code>RESULT_ERROR</code>, <code>RESULT_DEVELOPER_ERROR</code></td>
+</tr>
+</table>
+
+<h3 id="billing-intents">In-app billing broadcast intents</h3>
+
+<p>The following section describes the In-app Billing broadcast intents that are sent by the Google
+Play 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}google/play/billing/v2/billing_integrate.html#billing-download">sample
+application</a>.</p>
+
+<h4>com.android.vending.billing.RESPONSE_CODE</h4>
+
+<p>This broadcast intent contains a Google Play 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 Google Play 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">Google Play 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>request_id</code>&mdash;a <code>long</code> representing a request ID. A request ID
+  identifies a specific billing request and is returned by Google Play at the time a request is
+  made.</li>
+  <li><code>response_code</code>&mdash;an <code>int</code> representing the Google Play server
+  response code.</li>
+</ul>
+
+<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>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 <code>String</code> representing the notification ID for
+  a given purchase state change. Google Play 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>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. 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 <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 9):</p>
+
+<p class="table-caption"><strong>Table 9.</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. Google Play 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 Google Play server. Your application sends back the <code>notificationId</code> with the
+  <code>GET_PURCHASE_INFORMATION</code> message so Google Play 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 Wallet 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 Google Play 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), 2
+  (refunded), or 3 (expired, for subscription purchases only).</td>
+</tr>
+<tr>
+  <td>purchaseToken</td>
+  <td>A token that uniquely identifies a subscription purchase for a given item and user pair.
+  You can use the token to specify the subscription when querying for subscription validity.
+  
+  <p><br><em>Supported only in In-app Billing API Version 2 and higher.</em></p></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>
+
+<!--<h2 id="other-intents">Other Intents</h2> 
+
+<p>The following Intents related to In-app Billing may be useful in your
+implemention. </p> -->
+
+<h3 id="http-api">REST API for subscriptions</h3>
+<p>Google Play offers an HTTP-based API that you can use to remotely query the validity of a specific subscription at any time or cancel a subscription. The API is designed to be used from your backend servers as a way of securely managing subscriptions, as well as extending and integrating subscriptions with other services. See <a href="{@docRoot}google/play/billing/v2/billing_subscriptions.html#play-dev-api"> Google Play Android Developer API</a> for more information.</p>
diff --git a/docs/html/google/play/billing/billing_subscriptions.jd b/docs/html/google/play/billing/v2/billing_subscriptions.jd
similarity index 96%
rename from docs/html/google/play/billing/billing_subscriptions.jd
rename to docs/html/google/play/billing/v2/billing_subscriptions.jd
index 1217d8a..82a662f 100644
--- a/docs/html/google/play/billing/billing_subscriptions.jd
+++ b/docs/html/google/play/billing/v2/billing_subscriptions.jd
@@ -1,9 +1,8 @@
-page.title=Subscriptions
-parent.title=In-app Billing
-parent.link=index.html
+page.title=Subscriptions  <span style="font-size:16px;">(IAB Version 2)</span>
 @jd:body
 
-<div id="qv-wrapper">
+<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">In-app Billing Version 2 is superseded. Please <a href="{@docRoot}google/play/billing/billing_overview.html#migration">migrate to Version 3</a> at your earliest convenience.</div>
+    <div id="qv-wrapper" style="margin-top:0;">
 <div id="qv">
   <h2>In this document</h2>
   <ol>
@@ -46,26 +45,11 @@
       </ol> -->
     </li>
 </ol>
-  <h2>Downloads</h2>
-  <ol>
-    <li><a href="{@docRoot}google/play/billing/billing_integrate.html#billing-download">Sample Application</a></li>
-  </ol>
-  <h2>See also</h2>
-  <ol>
-    <li><a href="{@docRoot}google/play/billing/billing_overview.html">Overview of In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_best_practices.html">Security and
-    Design</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_testing.html">Testing In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_admin.html">Administering In-app
-    Billing</a></li>
-    <li><a href="{@docRoot}google/play/billing/billing_reference.html">In-app Billing
-    Reference</a></li>
-  </ol>
 </div>
 </div>
 
+<p class="note"><strong>Important:</strong> This documentation describes how to implement subscriptions with the Version 2 API. Subscription support for the in-app billing <a href="{@docRoot}google/play/billing/api.html">Version 3 API</a> is coming soon.</p></li>
+
 <p>Subscriptions let you sell content, services, or features in your app with
 automated, recurring billing. Adding support for subscriptions is
 straightforward and you can easily adapt an existing In-app Billing
@@ -78,13 +62,15 @@
 interactions as for other in-app products.subscriptions. Because the
 implementation of subscriptions follows the same path as for other in-app
 products, details are provided outside of this document, starting with the <a
-href="{@docRoot}google/play/billing/billing_overview.html">In-app Billing
+href="{@docRoot}google/play/billing/v2/api.html">In-app Billing
 Overview</a>. </p>
 
 <p>This document is focused on highlighting implementation details that are
 specific to subscriptions, along with some strategies for the associated billing
 and business models.</p>
 
+<p class="note"><strong>Note:</strong> Subscriptions are supported in In-app Billing Version 2 only. Support for subscriptions will be added to Version 3 in the weeks ahead.</p>
+
 <h2 id="overview">Overview of Subscriptions</h2>
 
 <p>A <em>subscription</em> is a new product type offered in In-app Billing that lets you
@@ -379,7 +365,7 @@
 
 <ul>
   <li>Must run Android 2.2 or higher</li>
-  <li>Google Play Store app, version 3.5 or higher, must be installed</li>
+  <li>Google Play Store app, Version 3.5 or higher, must be installed</li>
 </ul>
 
 <p>Google Play 3.5 and later versions include support for the In-app Billing
@@ -411,7 +397,7 @@
 
 <p>The full implementation details for In-app Billing are provided outside of
 this document, starting with the <a
-href="{@docRoot}google/play/billing/billing_overview.html">In-app Billing
+href="{@docRoot}google/play/billing/v2/api.html">In-app Billing
 Overview</a>. This document is focused on highlighting implementation details
 that are specific to subscriptions, along with some strategies for the
 associated billing and business models.</p>
@@ -420,10 +406,10 @@
 <h3 id="sample">Sample application</h3>
 
 <p>To help you get started with your In-app Billing implementation and
-subscriptions, an updated version of the In-app Billing sample app is available.
+subscriptions, an updated Version of the In-app Billing sample app is available.
 You can download the sample app from the Android SDK repository using the
 Android SDK Manager. For details, see <a
-href="{@docRoot}google/play/billing/billing_integrate.html#billing-download">
+href="{@docRoot}google/play/billing/v2/billing_integrate.html#billing-download">
 Downloading the Sample Application</a>.</p>
 
 <h3 id="model">Application model</h3>
@@ -442,7 +428,7 @@
 errors, and status messages, and an observer for sending callbacks to your
 application as needed. All of these components and their interactions are
 described in full in the <a
-href="{@docRoot}google/play/billing/billing_overview.html">In-app Billing
+href="{@docRoot}google/play/billing/v2/api.html">In-app Billing
 Overview</a> and related documents.</p>
 
 <p>To initiate different types of billing communication with Google Play, your
@@ -494,7 +480,7 @@
 
 <p>Subscriptions support is available only in versions of Google Play that
 support the In-app Billing v2 API (Google Play 3.5 and higher). For your app,
-an essential first step at launch is to check whether the version of Google Play
+an essential first step at launch is to check whether the Version of Google Play
 installed on the device supports the In-app Billing v2 API and
 subscriptions.</p>
 
@@ -571,7 +557,7 @@
 
 <h3 id="purchase">Requesting a subscription purchase</h3>
 
-<p>Once you’ve checked the API version as described above and determined that
+<p>Once you’ve checked the API Version as described above and determined that
 subscriptions are supported, you can present subscription products to the user
 for purchase. When the user has selected a subscription product and initiated a
 purchase, your app handles the purchase just as it would for other in-app
@@ -581,7 +567,7 @@
 
 <p>The REQUEST_PURCHASE includes a Bundle containing the item details, as
 described in the <a
-href="{@docRoot}google/play/billing/billing_overview.html">In-app Billing
+href="{@docRoot}google/play/billing/v2/api.html">In-app Billing
 Overview</a>. For a subscription, the Bundle must also specify:</p>
 
 <ul>
@@ -597,7 +583,7 @@
 <code>RESPONSE_CODE</code>, <code>PURCHASE_INTENT</code>, and
 <code>REQUEST_ID</code>. Your app uses the <code>PURCHASE_INTENT</code> to
 launch the checkout UI and the message flow proceeds exactly as described in <a
-href="{@docRoot}google/play/billing/billing_overview.html#billing-message-
+href="{@docRoot}google/play/billing/v2/api.html#billing-message-
 sequence">Messaging sequence</a>.</p>
 
 <p>Here’s how the sample app initiates a purchase for a subscription, where
@@ -654,7 +640,7 @@
 
 <p>The process for restoring subscriptions transactions is the same as described
 in <a
-href="{@docRoot}google/play/billing/billing_overview.html#billing-message-
+href="{@docRoot}google/play/billing/v2/api.html#billing-message-
 sequence">Messaging sequence</a>. Your app sends a
 <code>RESTORE_TRANSACTIONS</code> request to Google Play. Google Play sends two
 broadcast intents as asynchronous responses &mdash; a <code>RESPONSE_CODE</code>
@@ -804,7 +790,7 @@
 
 <p>For subscriptions, you make the same types of modifications to your app as
 are described in <a
-href="{@docRoot}google/play/billing/billing_integrate.html#billing-implement">
+href="{@docRoot}google/play/billing/v2/billing_integrate.html#billing-implement">
 Modifying your Application Code</a>.</p>
 
 <p>Note that, in your UI that lets users view and select subscriptions for
diff --git a/docs/html/google/play/billing/versions.jd b/docs/html/google/play/billing/versions.jd
new file mode 100644
index 0000000..ac7761f
--- /dev/null
+++ b/docs/html/google/play/billing/versions.jd
@@ -0,0 +1,50 @@
+page.title=In-app Billing Version Notes
+@jd:body
+
+<p>The In-app Billing API is versioned, with each version offering additional features to your app. API support is provided by the Google Play Store app. On most devices, the Google Play Store app is updated automatically to support newer versions of the API. 
+
+<p>The sections below list the supported versions of the In-app Billing API.</p>
+
+<p id="api_check"><strong><em>How to check for In-app Billing version</em></strong></p>
+
+<p>At run time, your app can query the Google Play Store app to determine what version of the API it supports and what features are available. </p>
+
+<ul>
+<li>If you are using in-app  billing version 3, the version information is not directly returned the Google Play. Instead, you can check if Google Play supports the version of the In-app Billing API that you are using by sending a {@code isBillingSupported} request.</li>
+<li>If the In-app Billing API version that you are using is earlier than version 3, the version information is returned in the <code>API_VERSION</code> key of the Bundle object passed in the {@code sendBillingRequest} method. For more information, see <a href="{@docRoot}google/play/billing/v2/billing_reference.html#billing-interface-v2">In-app Billing Service Interface</a>.</li>
+</ul>
+
+<h3 id="version_3">In-app Billing version 3</h3>
+<p><em>December 2012</em></p>
+<ul>
+<li>Requires Google Play client version 3.9.16 or higher.
+<li>Provides a new Android Interface Definition Language (AIDL) file named {@code IInAppBillingService.aidl}. The new interface offers these features:
+<ul>
+<li>Provides a new API to get details of in-app items published for the app including price, type, title and description.</li>
+<li>The purchase flow is synchronous and purchase information is available immediately after it completes.</li>
+<li>Purchase information of in-app purchases is maintained within the Google Play system till the purchase is consumed.</li>
+<li>An API to consume a purchase of an inapp item. All purchases of one-time in-app items are consumable and thereafter can be purchased again.</li>
+<li>An API to get current purchases of the user immediately. This list will not contain any consumed purchases.</li>
+</ul>
+</li>
+<li>Subscriptions are not yet supported in this version of the API.</li>
+</ul>
+
+<h3 id="version_2">In-app Billing version 2</h3>
+<p><em>May 2012</em></p>
+<ul>
+  <li>Adds support for subscriptions, including free trial period.</li>
+  <li>Adds a new supported string value, "2", for the <code>API_VERSION</code> key of the Bundle object passed in the <code>sendBillingRequest()</code>.</li>
+  <li>Adds a new JSON field, <code>purchaseToken</code>, to the <code>orders</code> list returned in a <code>PURCHASE_STATE_CHANGED</code> intent. </li> 
+  <li>Adds a new <code>purchaseState</code> value, <code>3</code> (expired), to the <code>orders</code> list returned in a <code>PURCHASE_STATE_CHANGED</code> intent. The value indicates that a subscription has expired and is no longer valid.</li>
+<li>Requires Google Play (Play Store) version 3.5 or higher.</li>
+</ul>
+
+<h3 id="version_1">In-app Billing version 1</h3>
+<p><em>March 2011</em></p>
+<ul>
+<li>Initial release.</li>
+<li>Requires Google Play/Android Market 2.3.4 or higher.</li>
+</ul>
+
+
diff --git a/docs/html/guide/webapps/webview.jd b/docs/html/guide/webapps/webview.jd
index bdedeff..9ea0a10 100644
--- a/docs/html/guide/webapps/webview.jd
+++ b/docs/html/guide/webapps/webview.jd
@@ -174,8 +174,7 @@
 }
 </pre>
 
-<p class="caution"><strong>Caution:</strong> If you've set either your <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> or <a
+<p class="caution"><strong>Caution:</strong> If you've set your <a
 href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a>
 to 17 or higher, <strong>you
 must add the {@code &#64;JavascriptInterface} annotation</strong> to any method that you want
diff --git a/docs/html/images/billing_arch.png b/docs/html/images/billing_arch.png
index afbc3f0..7bee36a 100644
--- a/docs/html/images/billing_arch.png
+++ b/docs/html/images/billing_arch.png
Binary files differ
diff --git a/docs/html/images/in-app-billing/billing_add.png b/docs/html/images/in-app-billing/billing_add.png
new file mode 100644
index 0000000..1ca448d
--- /dev/null
+++ b/docs/html/images/in-app-billing/billing_add.png
Binary files differ
diff --git a/docs/html/images/in-app-billing/billing_app_key.png b/docs/html/images/in-app-billing/billing_app_key.png
new file mode 100644
index 0000000..bff8500
--- /dev/null
+++ b/docs/html/images/in-app-billing/billing_app_key.png
Binary files differ
diff --git a/docs/html/images/in-app-billing/billing_list_form_2.png b/docs/html/images/in-app-billing/billing_list_form_2.png
new file mode 100644
index 0000000..33f17c9
--- /dev/null
+++ b/docs/html/images/in-app-billing/billing_list_form_2.png
Binary files differ
diff --git a/docs/html/images/in-app-billing/billing_product_list.png b/docs/html/images/in-app-billing/billing_product_list.png
new file mode 100644
index 0000000..dabdcb9
--- /dev/null
+++ b/docs/html/images/in-app-billing/billing_product_list.png
Binary files differ
diff --git a/docs/html/images/in-app-billing/v3/iab_v3_checkout_flow.png b/docs/html/images/in-app-billing/v3/iab_v3_checkout_flow.png
new file mode 100644
index 0000000..6ce8939
--- /dev/null
+++ b/docs/html/images/in-app-billing/v3/iab_v3_checkout_flow.png
Binary files differ
diff --git a/docs/html/images/in-app-billing/v3/iab_v3_consumption_flow.png b/docs/html/images/in-app-billing/v3/iab_v3_consumption_flow.png
new file mode 100644
index 0000000..367851f
--- /dev/null
+++ b/docs/html/images/in-app-billing/v3/iab_v3_consumption_flow.png
Binary files differ
diff --git a/docs/html/images/in-app-billing/v3/iab_v3_flow.png b/docs/html/images/in-app-billing/v3/iab_v3_flow.png
new file mode 100644
index 0000000..096ee98
--- /dev/null
+++ b/docs/html/images/in-app-billing/v3/iab_v3_flow.png
Binary files differ
diff --git a/docs/html/images/in-app-billing/v3/iab_v3_purchase_flow.png b/docs/html/images/in-app-billing/v3/iab_v3_purchase_flow.png
new file mode 100644
index 0000000..fbe2bc4
--- /dev/null
+++ b/docs/html/images/in-app-billing/v3/iab_v3_purchase_flow.png
Binary files differ
diff --git a/docs/html/training/in-app-billing/index.jd b/docs/html/training/in-app-billing/index.jd
new file mode 100644
index 0000000..3d07481
--- /dev/null
+++ b/docs/html/training/in-app-billing/index.jd
@@ -0,0 +1,46 @@
+page.title=Selling In-app Products
+
+trainingnavtop=true
+startpage=true
+next.title=Preparing Your In-app Billing Application
+next.link=preparing-iab-app.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
+<h2>Dependencies and prerequisites</h2>
+<ul>
+  <li>Android 2.2 or higher</li>
+</ul>
+
+<h2>You Should Also Read</h2>
+<ul>
+<li><a href="{@docRoot}google/play/billing/billing_overview.html">In-app Billing
+    Overview</a></li>
+</ul>
+
+</div>
+</div>
+<p>In this class, you'll learn how to perform common In-app Billing operations from Android applications.</p>
+<p>In-app billing is a service hosted on Google Play that lets you charge for digital content or for upgrades in your app.  The In-app Billing API makes it easy for you to integrate In-app Billing into your applications. You can request product details from Google Play, issue orders for in-app products, and quickly retrieve ownership information based on users' purchase history. You can also query the Google Play service for details about in-app products, such as local pricing and availability. Google Play provides a checkout interface that makes user interactions with the In-app Billing service seamless, and provides a more intuitive experience to your users.</p>
+<p>This class describes how to get started with the Version 3 API. To learn how to use the version 2 API, see <a href="{@docRoot}google/play/billing/v2/billing_integrate.html">Implementing In-App Billing (V2)</a>.</p>
+
+<h2>Lessons</h2>
+
+<!-- Create a list of the lessons in this class along with a short description of each lesson.
+These should be short and to the point. It should be clear from reading the summary whether someone
+will want to jump to a lesson or not.-->
+
+<dl>
+  <dt><b><a href="preparing-iab-app.html">Preparing Your In-app Billing Application</a></b></dt>
+    <dd>In this lesson, you will learn how to prepare your application to use the In-app Billing API and communicate with Google Play. You will also learn how to establish a connection to communicate with Google Play and verify that the In-app Billing API version that you are using is supported.</dd>
+  <dt><b><a href="list-iab-products.html">Establishing In-app Billing Products for Sale</a></b></dt>
+    <dd>In this lesson, you will learn how to specify the In-app Billing products for your app in Google Play and query the product details.</dd>
+  <dt><b><a href="purchase-iab-products.html">Purchase In-app Billing Products</a></b></dt>
+    <dd>In this lesson, you will learn how to purchase In-app Billing products, track consumption of purchased items, and query for details of purchased items.</dd>
+  <dt><b><a href="test-iab-app.html">Testing Your In-app Billing Application</a></b></dt>
+    <dd>In this lesson, you will learn how to test your application to ensure that In-app Billing is functioning correctly.</dd>
+</dl>
diff --git a/docs/html/training/in-app-billing/list-iab-products.jd b/docs/html/training/in-app-billing/list-iab-products.jd
new file mode 100644
index 0000000..36ff34a
--- /dev/null
+++ b/docs/html/training/in-app-billing/list-iab-products.jd
@@ -0,0 +1,91 @@
+page.title=Establishing In-app Billing Products for Sale
+parent.title=Selling In-app Products
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Preparing Your In-app Billing Application
+previous.link=preparing-iab-app.html
+next.title=Purchasing In-app Billing Products
+next.link=purchase-iab-products.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#DefineProducts">Specify In-app Products in Google Play</a></li>
+  <li><a href="#QueryDetails">Query In-app Product Details</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+<li><a href="{@docRoot}google/play/billing/billing_overview.html">In-app Billing
+    Overview</a></li>
+</ul>
+
+
+</div>
+</div>
+
+<p>Before publishing your In-app Billing application, you'll need to define the product list of digital goods available for purchase in the <a href="https://play.google.com/apps/publish/">Google Play Developer Console</a>. </p>
+
+<h2 id="DefineProducts">Specify In-app Products in Google Play</h2>
+<p>From the Developer Console, you can define product information for in-app products and associate the product list with your application.</p>
+
+<p>To add new in-app products to your product list:</p>
+<ol>
+<li>Build a signed APK file for your In-app Billing application. To learn how to build and sign your APK, see <a href="{@docRoot}tools/publishing/preparing.html#publishing-build">Building Your Application for Release</a>. Make sure that you are using your final (not debug) certificate and private key to sign your application.  
+</li>
+<li>In the Developer Console, open the application entry that you created earlier.</li>
+<li>Click on the APK tab then click on Upload new APK. Upload the signed APK file to the Developer Console. Don’t publish the app yet!</li>
+<li>Navigate to the uploaded app listing, and click on <strong>In-app Products</strong>.
+<li>Click on the option to add a new product, then complete the form to specify the product information such as the item’s unique product ID (also called its <em>SKU</em>), description, price, and country availability. Note down the product ID since you might need this information to query purchase details in your application later. <p class="note"><strong>Important:</strong> The In-app Billing Version 3 service only supports managed in-app products, so make sure that you specify that the purchase type is 'Managed' when you add new items to your product list in the Developer Console.</p></li>
+<li>Once you have completed the form, activate the product so that your application can purchase it. <p class="note"><strong>Warning:</strong> It may take up to 2-3 hours after uploading the APK for Google Play to recognize your updated APK version. If you try to test your application before your uploaded APK is recognized by Google Play, your application will receive a ‘purchase cancelled’ response with an error message “This version of the application is not enabled for In-app Billing.”</p></li>
+</ol>
+
+<h2 id="QueryDetails">Query Items Available for Purchase</h2>
+<p>You can query Google Play to programmatically retrieve details of the in-app products that are associated with your application (such as the product’s price, title, description, and type).  This is useful, for example, when you want to display a listing of unowned items that are still available for purchase to users.</p>
+<p class="note"><strong>Note:</strong> When making the query, you will need to specify the product IDs for the products explicitly. You can manually find the product IDs from the Developer Console by opening the <strong>In-app Products</strong> tab for your application. The product IDs are listed under the column labeled <strong>Name/ID</strong>.</p>
+<p>To retrieve the product details, call {@code queryInventoryAsync(boolean, List, QueryInventoryFinishedListener)} on your IabHelper instance. 
+<ul>
+<li>The first input argument indicates whether product details should be retrieved (should be set to {@code true}).</li> 
+<li>The {@code List} argument consists of one or more product IDs (also called SKUs) for the products that you want to query.</li>
+<li>Finally, the {@code QueryInventoryFinishedListener} argument specifies a listener is notified when the query operation has completed and handles the query response.</li>
+</ul>
+If you use the the convenience classes provided in the sample, the classes will handle background thread management for In-app Billing requests, so you can safely make queries from the main thread of your application.
+</p>
+<p>The following code shows how you can retrieve the details for two products with IDs {@code SKU_APPLE} and {@code SKU_BANANA} that you previously defined in the Developer Console.</p>
+
+<pre>
+List<String> additionalSkuList = new List<String>();
+additionalSkuList.add(SKU_APPLE);
+additionalSkuList.add(SKU_BANANA);
+mHelper.queryInventoryAsync(true, additionalSkuList,
+   mQueryFinishedListener);
+</pre>
+
+<p>If the query is successful, the query results are stored in an {@code Inventory} object that is passed back to the listener.</p>
+<p>The following code shows how you can retrieve the item prices from the result set.</p>
+
+<pre>
+IabHelper.QueryInventoryFinishedListener 
+   mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
+   public void onQueryInventoryFinished(IabResult result, Inventory inventory)   
+   {
+      if (result.isFailure()) {
+         // handle error
+         return;
+       }
+
+       String applePrice =
+          inventory.getSkuDetails(SKU_APPLE).getPrice();
+       String bananaPrice =
+          inventory.getSkuDetails(SKU_BANANA).getPrice();
+
+       // update the UI 
+   }
+}
+</pre>
+
diff --git a/docs/html/training/in-app-billing/preparing-iab-app.jd b/docs/html/training/in-app-billing/preparing-iab-app.jd
new file mode 100644
index 0000000..ab33ccc
--- /dev/null
+++ b/docs/html/training/in-app-billing/preparing-iab-app.jd
@@ -0,0 +1,144 @@
+page.title=Preparing Your In-app Billing Application
+parent.title=Selling In-app Products
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Establishing In-app Billing Products for Sale
+next.link=list-iab-products.html
+
+@jd:body
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#GetSample">Download the Sample App</a></li>
+  <li><a href="#AddToDevConsole">Add Your App to the Developer Console</a></li>
+  <li><a href="#AddLibrary">Add the In-app Billing Library</a></li>
+  <li><a href="#SetPermission">Set the Billing Permission</a></li>
+  <li><a href="#Connect">Initiate a Connection with Google Play</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+<li><a href="{@docRoot}google/play/billing/billing_overview.html">In-app Billing
+    Overview</a></li>
+</ul>
+
+</div>
+</div>
+
+<p>Before you can start using the In-app Billing service, you'll need to add the library that contains the In-app Billing Version 3 API to your Android project. You also need to setting the permissions for your application to communicate with Google Play. In addition, you'll need to establish a connection between your application and  Google Play. You should also verify that the In-app Billing API version that you are using in your application is supported by Google Play.</p>
+
+<h2 id="GetSample">Download the Sample Application</h2>
+<p>In this training class, you will use a reference implementation for the In-app Billing Version 3 API called the {@code TrivialDrive} sample application. The sample includes convenience classes to quickly set up the In-app Billing service, marshal and unmarshal data types, and handle In-app Billing requests from the main thread of your application.  </p>
+<p>To download the sample application:</p>
+<ol>
+<li>Open the <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>.</li>
+<li>In the SDK Manager, expand the {@code Extras} section.</li>
+<li>Select <strong>Google Play Billing Library</strong>. Make sure to select the download for In-app Billing Version 3 or above.</li>
+<li>Click <strong>Install</strong> to complete the download.</li>
+</ol>
+<p>The sample files will be installed to {@code /your/sdk/location/extras/google/play_billing/in-app-billing-v03}.</p>
+
+<h2 id="AddToDevConsole">Add Your Application to the Developer Console</h2>
+<p>The Google Play Developer Console is where you publish your In-app Billing application and  manage the various digital goods that are available for purchase from your application. When you create a new application entry in the Developer Console, it automatically generates a public license key for your application. You will need this key to establish a trusted connection from your application to the Google Play servers. You only need to generate this key once per application, and don’t need to repeat these steps when you update the APK file for your application.</p>
+<p>To add your application to the Developer Console:</p>
+<ol>
+<li>Go to the <a href="http://play.google.com/apps/publish">Google Play Developer Console</a> site and log in. You will need to register for a new developer account, if you have not registered previously. To sell in-app items, you also need to have a <a href="http://www.google.com/wallet/merchants.html">Google Checkout Merchant</a> account.</li>
+<li>Click on <strong>Try the new design</strong> to access the preview version of the Developer Console, if you are not already logged on to that version. </li>
+<li>In the <strong>All Applications</strong> tab, add a new application entry.
+<ol type="a">
+<li>Click <strong>Add new application</strong>.</li>
+<li>Enter a name for your new In-app Billing application.</li>
+<li>Click <strong>Prepare Store Listing</strong>.</li>
+</ol>
+</li>
+<li>In the <strong>Services & APIs</strong> tab, find and make a note of the public license key that Google Play generated for your application. This is a Base64 string that you will need to include in your application code later.</li>
+</ol>
+<p>Your application should now appear in the list of applications in Developer Console.</p>
+
+<h2 id="AddLibrary">Add the In-app Billing Library</h2>
+<p>To use the In-app Billing Version 3 features, you must add the {@code IInAppBillingService.aidl} file to your Android project. This Android Interface Definition Language (AIDL) file defines the interface to the Google Play service.</p>
+<p>You can find the {@code IInAppBillingService.aidl} file in the provided sample app. Depending on whether you are creating a new application or modifying an existing application, follow the instructions below to add the In-app Billing Library to your project.</p>
+<h3>New Project</h3>
+<p>To add the In-app Billing Version 3 library to your new In-app Billing project:</p>
+<ol>
+<li>Copy the {@code TrivialDrive} sample files into your Android project.</li>
+<li>Modify the package name in the files you copied to use the package name for your project. In Eclipse, you can use this shortcut: right-click the package name, then  select <strong>Refactor</strong> > <strong>Rename</strong>.</li>
+<li>Open the {@code AndroidManifest.xml} file and update the package attribute value to use the package name for your project.</li>
+<li>Fix import statements as needed so that your project compiles correctly.  In Eclipse, you can use this shortcut: press <strong>Ctrl+Shift+O</strong> in each file showing errors.</li>
+<li>Modify the sample to create your own application. Remember to copy the Base64 public license key for your application from the Developer Console over to your {@code MainActivity.java}.</li>
+</ol>
+
+<h3>Existing Project</h3>
+<p>To add the In-app Billing Version 3 library to your existing In-app Billing project:</p>
+<ol>
+<li>Copy the {@code IInAppBillingService.aidl} file to your Android project.
+  <ul>
+  <li>If you are using Eclipse: Import the {@code IInAppBillingService.aidl} file into your {@code /src} directory.</li>
+  <li>If you are developing in a non-Eclipse environment: Create the following directory {@code /src/com/android/vending/billing} and copy the {@code IInAppBillingService.aidl} file into this directory.</li>
+  </ul>
+</li>
+<li>Build your application. You should see a generated file named {@code IInAppBillingService.java} in the {@code /gen} directory of your project.</li>
+<li>Add the helper classes from the {@code /util} directory of the {@code TrivialDrive} sample to your project.  Remember to change the package name declarations in those files accordingly so that your project compiles correctly.</li>
+</ol>
+
+<p>Your project should now contain the In-app Billing Version 3 library.</p>
+
+<h2 id="SetPermission">Set the Billing Permission</h2>
+<p>Your app needs to have permission to communicate request and response messages to the Google Play’s billing service. To give your app the necessary permission, add this line in your {@code AndroidManifest.xml} manifest file:</p>
+<pre>
+&lt;uses-permission android:name="com.android.vending.BILLING" /&gt;
+</pre>
+
+<h2 id="Connect">Initiate a Connection with Google Play</h2>
+<p>You must bind your Activity to Google Play’s In-app Billing service to send In-app Billing requests to Google Play from your application. The convenience classes provided in the sample handles the binding to the In-app Billing service, so you don’t have to manage the network connection directly.</p>
+<p>To set up synchronous communication with Google Play, create an {@code IabHelper} instance in your activity's {@code onCreate} method. In the constructor, pass in the {@code Context} for the activity, along with a string containing the public license key that was generated earlier by the Google Play Developer Console. </p>
+<p class="note"><strong>Security Recommendation:</strong> It is highly recommended that you do not hard-code the exact public license key string value as provided by Google Play. Instead, you can construct the whole public license key string at runtime from substrings, or retrieve it from an encrypted store, before passing it to the constructor. This approach makes it more difficult for malicious third-parties to modify the public license key string in your APK file.</p>
+
+<pre>
+IabHelper mHelper;
+
+&#64;Override
+public void onCreate(Bundle savedInstanceState) {
+   // ...
+   String base64EncodedPublicKey;
+   
+   // compute your public key and store it in base64EncodedPublicKey
+   mHelper = new IabHelper(this, base64EncodedPublicKey);
+}
+</pre>
+
+<p>Next, perform the service binding by calling the {@code startSetup} method on the {@code IabHelper} instance that you created.  Pass the method an {@code OnIabSetupFinishedListener} instance, which is called once the {@code IabHelper} completes the asynchronous setup operation. As part of the setup process, the {@code IabHelper} also checks if the In-app Billing Version 3 API is supported by Google Play. If the API version is not supported, or if an error occured while establishing the service binding, the listener is notified and passed an {@code IabResult} object with the error message.</p>
+
+<pre>
+mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
+   public void onIabSetupFinished(IabResult result) {
+      if (!result.isSuccess()) {
+         // Oh noes, there was a problem.
+         Log.d(TAG, "Problem setting up In-app Billing: " + result);
+      }            
+         // Hooray, IAB is fully set up!  
+   }
+});
+</pre>
+
+<p>If the setup completed successfully, you can now use the {@code mHelper} reference to communicate with the Google Play service. When your application is launched, it is a good practice to query Google Play to find out what in-app items are owned by a user. This is covered further in the <a href="{@docRoot}training/in-app-billing/purchase-iab-products.html#QueryPurchases">Query Purchased Items</a> section.</p>
+
+<p class="note"><strong>Important:</strong> Remember to unbind from the In-app Billing service when you are done with your activity. If you don’t unbind, the open service connection could cause your device’s performance to degrade. To unbind and free your system resources, call the {@code IabHelper}'s {@code dispose} method when your {@code Activity} gets destroyed.</p>
+
+<pre>
+&#64;Override
+public void onDestroy() {
+   if (mHelper != null) mHelper.dispose();
+   mHelper = null;
+}
+</pre>
+
+
+
+
+
diff --git a/docs/html/training/in-app-billing/purchase-iab-products.jd b/docs/html/training/in-app-billing/purchase-iab-products.jd
new file mode 100644
index 0000000..d5f6634
--- /dev/null
+++ b/docs/html/training/in-app-billing/purchase-iab-products.jd
@@ -0,0 +1,138 @@
+page.title=Purchasing In-app Billing Products
+parent.title=Selling In-app Products
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Establishing In-app Billing Products for Sale
+previous.link=list-iab-products.html
+next.title=Testing Your In-app Billing Application
+next.link=test-iab-app.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#Purchase">Purchase an Item</a></li>
+  <li><a href="#QueryPurchases">Query Purchased Items</a></li>
+  <li><a href="#Consume">Consume a Purchase</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+<li><a href="{@docRoot}google/play/billing/billing_overview.html">In-app Billing
+    Overview</a></li>
+</ul>
+</div>
+</div>
+
+<p>Once your application is connected to Google Play, you can initiate purchase requests for in-app products. Google Play provides a checkout interface for users to enter their payment method, so your application does not need to handle payment transactions directly.</p>
+<p>When an item is purchased, Google Play recognizes that the user has ownership of that item and prevents the user from purchasing another item with the same product ID until it is consumed. You can control how the item is consumed in your application, and notify Google Play to make the item available for purchase again.</p>
+<p>You can also query Google Play to quickly retrieve the list of purchases that were made by the user. This is useful, for example, when you want to restore the user's purchases when your user launches your app.</p>
+
+<h2 id="Purchase">Purchase an Item</h2>
+
+<p>To start a purchase request from your app, call {@code launchPurchaseFlow(Activity, String, int, OnIabPurchaseFinishedListener, String)} on your {@code IabHelper} instance. You must make this call from the main thread of your {@code Activity}. Here’s an explaination of the {@code launchPurchaseFlow} method parameters:</p>
+<ul>
+<li>The first argument is the calling {@code Activity}.</li>
+<li>The second argument is the product ID (also called its SKU) of the item to purchase. Make sure that you are providing the ID and not the product name. You must have previously defined and activated the item in the Developer Console, otherwise it won’t be recognized. </li>
+<li>The third argument is a request code value.  This value can be any positive integer. Google Play reurns this request code to the calling {@code Activity}’s {@code onActivityResult} along with the purchase response.</li>
+<li>The fourth argument is a listener that is notified when the purchase operation has completed and handles the purchase response from Google Play.</li>
+<li>The fifth argument contains a ‘developer payload’ string that you can use to send supplemental information about an order (it can be an empty string). Typically, this is used to pass in a string token that uniquely identifies this purchase request. If you specify a string value, Google Play returns this string along with the purchase response. Subsequently, when you make queries about this purchase, Google Play returns this string together with the purchase details. <p class="note"><strong>Security Recommendation:</strong> It’s good practice to pass in a string that helps your application to identify the user who made the purchase, so that you can later verify that this is a legitimate purchase by that user. For consumable items, you can use a randomly generated string, but for non-consumable items you should use a string that uniquely identifies the user.</p></li>
+</ul>
+<p>The following example shows how you can make a purchase request for a product with ID {@code SKU_GAS}, using an arbitrary value of 10001 for the request code, and an encoded developer payload string.</p>
+
+<pre>
+mHelper.launchPurchaseFlow(this, SKU_GAS, 10001,   
+   mPurchaseFinishedListener, "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
+</pre>
+
+<p>If the purchase order is successful, the response data from Google Play is stored in an {@code Purchase} object that is passed back to the listener.</p>
+
+<p>The following example shows how you can handle the purchase response in the listener, depending on whether the purchase order was completed successfully, and whether the user purchased gas or a premium upgrade. In this example, gas is an in-app product that can be purchased multiple times, so you should consume the purchase to allow the user to buy it again.  To learn how to consume purchases, see the <a href="{@docRoot}training/in-app-billing/purchase-iab-products.html#Consume">Consuming Products</a> section. The premium upgrade is a one-time purchase so you don’t need to consume it.  It is good practice to update the UI immediately so that your users can see their newly purchased items.</p>
+
+<pre>
+IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener 
+   = new IabHelper.OnIabPurchaseFinishedListener() {
+   public void onIabPurchaseFinished(IabResult result, Purchase purchase) 
+   {
+      if (result.isFailure()) {
+         Log.d(TAG, "Error purchasing: " + result);
+         return;
+      }      
+      else if (purchase.getSku().equals(SKU_GAS)) {
+         // consume the gas and update the UI
+      }
+      else (purchase.getSku().equals(SKU_PREMIUM)) {
+         // give user access to premium content and update the UI
+      }
+   }
+};
+</pre>
+
+<p class="note"><strong>Security Recommendation:</strong> When you receive the purchase response from Google Play, make sure to check the returned data signature, the {@code orderId}, and the {@code developerPayload} string in the {@code Purchase} object to make sure that you are getting the expected values. You should verify that the {@code orderId} is a unique value that you have not previously processed, and the {@code developerPayload} string matches the token that you sent previously with the purchase request. As a further security precaution, you should perform the verification on your own secure server. </p>
+
+<h2 id="QueryPurchases">Query Purchased Items</h2>
+<p>Upon a successful purchase, the user’s purchase data is cached locally by Google Play’s In-app Billing service. It is good practice to frequently query the In-app Billing service for the user’s purchases, for example whenever the app starts up or resumes, so that the user’s current in-app product ownership information is always reflected in your app.</p>
+
+<p>To retrieve the user’s purchases from your app, call {@code queryInventoryAsync(QueryInventoryFinishedListener)} on your {@code IabHelper} instance.  The {@code QueryInventoryFinishedListener} argument specifies a listener that is notified when the query operation has completed and handles the query response. It is safe to make this call fom your main thread.</p>
+
+<pre>
+mHelper.queryInventoryAsync(mGotInventoryListener);
+</pre>
+
+<p>If the query is successful, the query results are stored in an {@code Inventory} object that is passed back to the listener. The In-app Billing service returns only the purchases made by the user account that is currently logged in to the device.</p>
+
+<pre>
+IabHelper.QueryInventoryFinishedListener mGotInventoryListener 
+   = new IabHelper.QueryInventoryFinishedListener() {
+   public void onQueryInventoryFinished(IabResult result,
+      Inventory inventory) {
+
+      if (result.isFailure()) {
+        // handle error here
+      }
+      else {
+        // does the user have the premium upgrade?
+        mIsPremium = inventory.hasPurchase(SKU_PREMIUM);        
+        // update UI accordingly
+      }
+   }
+};
+</pre>
+
+<h2 id="Consume">Consume a Purchase</h2>
+<p>You can use the In-app Billing Version 3 API to track the ownership of purchased items in Google Play. Once an item is purchased, it is considered to be "owned" and cannot be purchased again from Google Play while in that state. You must send a consumption request for the item before Google Play makes it available for purchase again. All managed in-app products are consumable.  How you use the consumption mechanism in your app is up to you. Typically, you would implement consumption for products with temporary benefits that users may want to purchase multiple times (for example, in-game currency or replensihable game tokens). You would typically not want to implement consumption for products that are purchased once and provide a permanent effect (for example, a premium upgrade).</p>
+<p>It's your responsibility to control and track how the in-app product is provisioned to the user. For example, if the user purchased in-game currency, you should update the player's inventory with the amount of currency purchased.</p>
+<p class="note"><strong>Security Recommendation:</strong> You must send a consumption request before provisioning the benefit of the consumable in-app purchase to the user. Make sure that you have received a successful consumption response from Google Play before you provision the item.</p>
+<p>To record a purchase consumption, call {@code consumeAsync(Purchase, OnConsumeFinishedListener)} on your {@code IabHelper} instance. The first argument that the method takes is the {@code Purchase} object representing the item to consume. The second argument is a {@code OnConsumeFinishedListener} that is notified when the consumption operation has completed and handles the consumption response from Google Play. It is safe to make this call fom your main thread.</p>
+<p>In this example, you want to consume the gas item that the user has previously purchased in your app.</p>
+
+<pre>
+mHelper.consumeAsync(inventory.getPurchase(SKU_GAS), 
+   mConsumeFinishedListener);
+</pre>
+
+<p>The following example shows how to implement the {@code OnConsumeFinishedListener}.</p>
+
+<pre>
+IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =
+   new IabHelper.OnConsumeFinishedListener() {
+   public void onConsumeFinished(Purchase purchase, IabResult result) {
+      if (result.isSuccess()) {
+         // provision the in-app purchase to the user
+         // (for example, credit 50 gold coins to player's character)
+      }
+      else {
+         // handle error
+      }
+   }
+};
+</pre>
+
+<h3>Check for Consumable Items on Startup</h3>
+<p>It’s important to check for consumable items when the user starts up your application. Typically, you would first query the In-app Billing service for the items purchased by the user (via {@code queryInventoryAsync}), then get the consumable {@code Purchase} objects from the Inventory. If your application detects that are any consumable items that are owned by the user, you should send a consumption request to Google Play immediately and provision the item to the user. See the {@code TrivialDrive} sample for an example of how to implement this checking at startup.</p>
+
+
diff --git a/docs/html/training/in-app-billing/test-iab-app.jd b/docs/html/training/in-app-billing/test-iab-app.jd
new file mode 100644
index 0000000..376b981
--- /dev/null
+++ b/docs/html/training/in-app-billing/test-iab-app.jd
@@ -0,0 +1,56 @@
+page.title=Testing Your In-app Billing Application
+parent.title=Selling In-app Products
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Purchasing In-app Billing Products
+previous.link=purchase-iab-products.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#StaticTest">Test with Static Responses</a></li>
+  <li><a href="#PlayItemTest">Test with Your Own Product IDs</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+<li><a href="{@docRoot}google/play/billing/billing_overview.html">In-app Billing
+    Overview</a></li>
+</ul>
+
+</div>
+</div>
+
+<p>To ensure that In-app Billing is functioning correctly in your application, you should test the test the application before you publish it on Google Play. Early testing also helps to ensure that the user flow for purchasing in-app items is not confusing or slow, and that users can see their newly purchased items in a timely way.</p>
+
+<h2 id="StaticTest">Test with Static Responses</h2>
+Test your In-app Billing application with static responses by using Google Play’s reserved product IDs.By using  reserved product IDs instead of actual product IDs, you can test the purchase flow without specifying an actual payment method or transferring money. To learn more about the reserved product IDs, see <a href="{@docRoot}google/play/billing/billing_testing.html">Testing In-app Billing</a>.
+
+<h2 id="PlayItemTest">Test with Your Own Product IDs</h2>
+<p>Because Google Play does not allow you to use your developer account to directly purchase in-app products that you have created yourself, you'll need to create test acccounts under your developer account profile. To create a test account, simply enter a valid Google email address. Users with these test accounts will then be able to make in-app-billing purchases from uploaded, unpublished applications that you manage.</p>
+<p>To test your In-app Billing Version 3 application using your own product IDs:
+<ol>
+<li>In the Developer Console, add one or more tester accounts to the developer account that you are using to publish your application.
+  <ol type="a">
+  <li>Login to the <a href="https://play.google.com/apps/publish/" target="_blank">Developer Console</a> with your developer account.</li>
+  <li>Click <strong>Settings</strong> > <strong>Account</strong> details, then in the <strong>License Testing</strong> section, add the Google email addresses for your tester accounts.</li>
+</ol>
+<li>Build a signed APK file for your In-app Billing application. To learn how to build and sign your APK, see <a href="{@docRoot}tools/publishing/preparing.html#publishing-build">Building Your Application for Release</a>. Make sure that you are using your final (not debug) certificate and private key to sign your application.  
+</li>
+<li>Make sure that you have uploaded the signed APK for your application to the Developer Console, and associated one or more in-app products with your application. You don't need to publish the application on Google Play to test it. <p class="note"><strong>Warning:</strong> It may take up to 2-3 hours after uploading the APK for Google Play to recognize your updated APK version. If you try to test your application before your uploaded APK is recognized by Google Play, your application will receive a ‘purchase cancelled’ response with an error message “This version of the application is not enabled for In-app Billing.”</p></li>
+<li>Install the APK file to your physical test device by using the {@code adb} tool. To learn how to install the application, see <a href="{@docRoot}tools/building/building-cmdline.html#RunningOnDevice">Running on a Device</a>. Make sure that:
+   <ul>
+   <li>Your test device is running on Android SDK Version 2.2 (API level 8) or higher, and is installed with Google Play client Version 3.9.16 or higher.</li>
+   <li>The {@code android:versionCode} and {@code android:versionName} attributes values in the {@code AndroidManifest.xml} of the application that you are installing matches the values of your APK in the Developer Console.</li>
+   <li>Your application is signed with the same certificate that you used for the APK that you uploaded to the Developer Console, before installing it on your device.</li>
+   </ul>
+</li>
+<li>Login to the test device by using a tester account. Test your In-app Billing application by purchasing a few items, and fix any issues that you encounter. Remember to refund the purchases if you don’t want your testers to be actually charged!</li>
+</ol>
+</p>
+
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 203b529..ba9bbcf 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -954,6 +954,30 @@
       </a>
     </div>
     <ul>
+      <li class="nav-section">
+      <div class="nav-section-header"><a href="<?cs var:toroot ?>training/in-app-billing/index.html"
+         description="How to sell in-app products from your application using In-app Billing.">
+            Selling In-app Products
+          </a></div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/in-app-billing/preparing-iab-app.html">
+            <span class="en">Preparing Your App</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/in-app-billing/list-iab-products.html">
+            <span class="en">Establishing Products for Sale</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/in-app-billing/purchase-iab-products.html">
+            <span class="en">Purchasing Products</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/in-app-billing/test-iab-app.html">
+            <span class="en">Testing Your App</span>
+          </a>
+          </li>
+        </ul>
+      </li>
       
       <li class="nav-section">
         <div class="nav-section-header">
diff --git a/docs/image_sources/in-app-billing/v2/billing_arch.graffle b/docs/image_sources/in-app-billing/v2/billing_arch.graffle
new file mode 100644
index 0000000..0debc45
--- /dev/null
+++ b/docs/image_sources/in-app-billing/v2/billing_arch.graffle
Binary files differ
diff --git a/docs/image_sources/in-app-billing/v2/billing_check_supported.graffle b/docs/image_sources/in-app-billing/v2/billing_check_supported.graffle
new file mode 100644
index 0000000..0debc45
--- /dev/null
+++ b/docs/image_sources/in-app-billing/v2/billing_check_supported.graffle
Binary files differ
diff --git a/docs/image_sources/in-app-billing/v2/billing_checkout_flow.graffle b/docs/image_sources/in-app-billing/v2/billing_checkout_flow.graffle
new file mode 100644
index 0000000..1bd1774
--- /dev/null
+++ b/docs/image_sources/in-app-billing/v2/billing_checkout_flow.graffle
Binary files differ
diff --git a/docs/image_sources/in-app-billing/v2/billing_refund.graffle b/docs/image_sources/in-app-billing/v2/billing_refund.graffle
new file mode 100644
index 0000000..0debc45
--- /dev/null
+++ b/docs/image_sources/in-app-billing/v2/billing_refund.graffle
Binary files differ
diff --git a/docs/image_sources/in-app-billing/v2/billing_request_purchase.graffle b/docs/image_sources/in-app-billing/v2/billing_request_purchase.graffle
new file mode 100644
index 0000000..0debc45
--- /dev/null
+++ b/docs/image_sources/in-app-billing/v2/billing_request_purchase.graffle
Binary files differ
diff --git a/docs/image_sources/in-app-billing/v2/billing_restore_transactions.graffle b/docs/image_sources/in-app-billing/v2/billing_restore_transactions.graffle
new file mode 100644
index 0000000..0debc45
--- /dev/null
+++ b/docs/image_sources/in-app-billing/v2/billing_restore_transactions.graffle
Binary files differ
diff --git a/docs/image_sources/in-app-billing/v2/billing_test_flow.graffle b/docs/image_sources/in-app-billing/v2/billing_test_flow.graffle
new file mode 100644
index 0000000..1bd1774
--- /dev/null
+++ b/docs/image_sources/in-app-billing/v2/billing_test_flow.graffle
Binary files differ
diff --git a/docs/image_sources/in-app-billing/v3/iab_v3_checkout_flow.graffle b/docs/image_sources/in-app-billing/v3/iab_v3_checkout_flow.graffle
new file mode 100644
index 0000000..1bd1774
--- /dev/null
+++ b/docs/image_sources/in-app-billing/v3/iab_v3_checkout_flow.graffle
Binary files differ
diff --git a/docs/image_sources/in-app-billing/v3/iab_v3_consumption_flow.graffle b/docs/image_sources/in-app-billing/v3/iab_v3_consumption_flow.graffle
new file mode 100644
index 0000000..e778082
--- /dev/null
+++ b/docs/image_sources/in-app-billing/v3/iab_v3_consumption_flow.graffle
@@ -0,0 +1,1018 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>ActiveLayerIndex</key>
+	<integer>0</integer>
+	<key>ApplicationVersion</key>
+	<array>
+		<string>com.omnigroup.OmniGrafflePro</string>
+		<string>139.16.0.171715</string>
+	</array>
+	<key>AutoAdjust</key>
+	<true/>
+	<key>BackgroundGraphic</key>
+	<dict>
+		<key>Bounds</key>
+		<string>{{0, 0}, {576, 733}}</string>
+		<key>Class</key>
+		<string>SolidGraphic</string>
+		<key>ID</key>
+		<integer>2</integer>
+		<key>Style</key>
+		<dict>
+			<key>shadow</key>
+			<dict>
+				<key>Draws</key>
+				<string>NO</string>
+			</dict>
+			<key>stroke</key>
+			<dict>
+				<key>Draws</key>
+				<string>NO</string>
+			</dict>
+		</dict>
+	</dict>
+	<key>BaseZoom</key>
+	<integer>0</integer>
+	<key>CanvasOrigin</key>
+	<string>{0, 0}</string>
+	<key>ColumnAlign</key>
+	<integer>1</integer>
+	<key>ColumnSpacing</key>
+	<real>36</real>
+	<key>CreationDate</key>
+	<string>2012-10-22 20:20:34 +0000</string>
+	<key>Creator</key>
+	<string>Quddus Chong</string>
+	<key>DisplayScale</key>
+	<string>1 0/72 in = 1.0000 in</string>
+	<key>GraphDocumentVersion</key>
+	<integer>8</integer>
+	<key>GraphicsList</key>
+	<array>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>232</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPoint</key>
+			<string>{0, 0}</string>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{473.50000023841858, 333}</string>
+				<string>{342.75000023841858, 333}</string>
+				<string>{99.750000238418579, 333}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.7</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>4</real>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>Pattern</key>
+					<integer>1</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>231</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPoint</key>
+			<string>{0, 0}</string>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{101, 289}</string>
+				<string>{472, 288}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.7</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>4</real>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>230</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPoint</key>
+			<string>{0, 0}</string>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{102.5, 144.00001525878906}</string>
+				<string>{473.5, 143.00001525878906}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.7</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>4</real>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>217</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPoint</key>
+			<string>{0, 0}</string>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{472.875, 218}</string>
+				<string>{342.125, 218}</string>
+				<string>{99.125, 218}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.7</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>4</real>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>Pattern</key>
+					<integer>1</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{136.25, 264}, {305.5, 24}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>Vertical</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>a</key>
+					<string>0.65</string>
+					<key>w</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>220</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>RTFD</key>
+				<data>
+				BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+				ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+				bmcBlIQBKxFjb25zdW1lUHVyY2hhc2UoKYaEAmlJARGS
+				hISEDE5TRGljdGlvbmFyeQCUhAFpBJKElpYQTlNQYXJh
+				Z3JhcGhTdHlsZYaShISEEE5TUGFyYWdyYXBoU3R5bGUA
+				lIQEQ0NAUwIAhISEB05TQXJyYXkAlJkMkoSEhAlOU1Rl
+				eHRUYWIAlIQCQ2YAHIaShJ+eADiGkoSfngBUhpKEn54A
+				cIaShJ+eAIGMAIaShJ+eAIGoAIaShJ+eAIHEAIaShJ+e
+				AIHgAIaShJ+eAIH8AIaShJ+eAIEYAYaShJ+eAIE0AYaS
+				hJ+eAIFQAYaGgQAIhARbMWZdg83MTD2GkoSWlgdOU0Nv
+				bG9yhpKEhIQHTlNDb2xvcgCUhAFjA4QCZmYAg2ZmJj+G
+				koSWlgZOU0ZvbnSGkoSEhAZOU0ZvbnQelJkohAVbNDBj
+				XQYAAAAeAAAA//5IAGUAbAB2AGUAdABpAGMAYQAtAEIA
+				bwBsAGQAAACEAWYMoQChAaEAoQCGkoSWlg5OU09yaWdp
+				bmFsRm9udIaSr4aG
+				</data>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\b\fs24 \cf2 consumePurchase()}</string>
+				<key>alpha</key>
+				<array>
+					<array>
+						<integer>0</integer>
+						<integer>17</integer>
+						<real>0.64999997615814209</real>
+					</array>
+				</array>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{123.25, 309}, {331.5, 24}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>Vertical</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>a</key>
+					<string>0.65</string>
+					<key>w</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>218</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>RTFD</key>
+				<data>
+				BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+				ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+				bmcBlIQBKw9TVUNDRVNTL0ZBSUxVUkWGhAJpSQEPkoSE
+				hAxOU0RpY3Rpb25hcnkAlIQBaQOShJaWB05TQ29sb3KG
+				koSEhAdOU0NvbG9yAJSEAWMDhAJmZgCDZmYmP4aShJaW
+				EE5TUGFyYWdyYXBoU3R5bGWGkoSEhBBOU1BhcmFncmFw
+				aFN0eWxlAJSEBENDQFMCAISEhAdOU0FycmF5AJSZDJKE
+				hIQJTlNUZXh0VGFiAJSEAkNmAByGkoSioQA4hpKEoqEA
+				VIaShKKhAHCGkoSioQCBjACGkoSioQCBqACGkoSioQCB
+				xACGkoSioQCB4ACGkoSioQCB/ACGkoSioQCBGAGGkoSi
+				oQCBNAGGkoSioQCBUAGGhoEACIQEWzFmXYPNzEw9hpKE
+				lpYGTlNGb250hpKEhIQGTlNGb250HpSZHIQFWzI4Y10G
+				AAAAFAAAAP/+SABlAGwAdgBlAHQAaQBjAGEAhAFmDJsA
+				mwGbAJsAhoaG
+				</data>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf2 SUCCESS/FAILURE}</string>
+				<key>alpha</key>
+				<array>
+					<array>
+						<integer>0</integer>
+						<integer>15</integer>
+						<real>0.64999997615814209</real>
+					</array>
+				</array>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{99.75, 153}, {373.75, 66}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>Vertical</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>a</key>
+					<string>0.65</string>
+					<key>w</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>203</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>RTFD</key>
+				<data>
+				BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+				ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+				bmcBlIQBK35CdW5kbGUoUkVTUE9OU0VfQ09ERSwgSU5B
+				UFBfUFVSQ0hBU0VfSVRFTV9MSVNULCBJTkFQUF9QVVJD
+				SEFTRV9EQVRBX0xJU1QsIElOQVBQX0RBVEFfU0lHTkFU
+				VVJFX0xJU1QsIElOQVBQX0NPTlRJTlVBVElPTl9UT0tF
+				TimGhAJpSQF+koSEhAxOU0RpY3Rpb25hcnkAlIQBaQOS
+				hJaWB05TQ29sb3KGkoSEhAdOU0NvbG9yAJSEAWMDhAJm
+				ZgCDZmYmP4aShJaWEE5TUGFyYWdyYXBoU3R5bGWGkoSE
+				hBBOU1BhcmFncmFwaFN0eWxlAJSEBENDQFMCAISEhAdO
+				U0FycmF5AJSZDJKEhIQJTlNUZXh0VGFiAJSEAkNmAByG
+				koSioQA4hpKEoqEAVIaShKKhAHCGkoSioQCBjACGkoSi
+				oQCBqACGkoSioQCBxACGkoSioQCB4ACGkoSioQCB/ACG
+				koSioQCBGAGGkoSioQCBNAGGkoSioQCBUAGGhoEACIQE
+				WzFmXYPNzEw9hpKElpYGTlNGb250hpKEhIQGTlNGb250
+				HpSZHIQFWzI4Y10GAAAAFAAAAP/+SABlAGwAdgBlAHQA
+				aQBjAGEAhAFmDJsAmwGbAJsAhoaG
+				</data>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf2 Bundle(RESPONSE_CODE, INAPP_PURCHASE_ITEM_LIST, INAPP_PURCHASE_DATA_LIST, INAPP_DATA_SIGNATURE_LIST, INAPP_CONTINUATION_TOKEN)}</string>
+				<key>alpha</key>
+				<array>
+					<array>
+						<integer>0</integer>
+						<integer>126</integer>
+						<real>0.64999997615814209</real>
+					</array>
+				</array>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{238.00002503395081, 119.00001525878906}, {97, 24}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>a</key>
+					<string>0.65</string>
+					<key>w</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>199</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>RTFD</key>
+				<data>
+				BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+				ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+				bmcBlIQBKw5nZXRQdXJjaGFzZXMoKYaEAmlJAQ6ShISE
+				DE5TRGljdGlvbmFyeQCUhAFpBJKElpYQTlNQYXJhZ3Jh
+				cGhTdHlsZYaShISEEE5TUGFyYWdyYXBoU3R5bGUAlIQE
+				Q0NAUwIAhISEB05TQXJyYXkAlJkMkoSEhAlOU1RleHRU
+				YWIAlIQCQ2YAHIaShJ+eADiGkoSfngBUhpKEn54AcIaS
+				hJ+eAIGMAIaShJ+eAIGoAIaShJ+eAIHEAIaShJ+eAIHg
+				AIaShJ+eAIH8AIaShJ+eAIEYAYaShJ+eAIE0AYaShJ+e
+				AIFQAYaGgQAIhARbMWZdg83MTD2GkoSWlgdOU0NvbG9y
+				hpKEhIQHTlNDb2xvcgCUhAFjA4QCZmYAg2ZmJj+GkoSW
+				lgZOU0ZvbnSGkoSEhAZOU0ZvbnQelJkohAVbNDBjXQYA
+				AAAeAAAA//5IAGUAbAB2AGUAdABpAGMAYQAtAEIAbwBs
+				AGQAAACEAWYMoQChAaEAoQCGkoSWlg5OU09yaWdpbmFs
+				Rm9udIaSr4aG
+				</data>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\b\fs24 \cf2 getPurchases()}</string>
+				<key>alpha</key>
+				<array>
+					<array>
+						<integer>0</integer>
+						<integer>14</integer>
+						<real>0.64999997615814209</real>
+					</array>
+				</array>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{472.875, 103}, {80.185199999999995, 284}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>b</key>
+					<string>0</string>
+					<key>g</key>
+					<string>0</string>
+					<key>r</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans-Bold</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>200</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{1, 1}</string>
+				<string>{1, -1}</string>
+				<string>{-1, -1}</string>
+				<string>{-1, 1}</string>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+				<string>{-0.5, -0.233518}</string>
+				<string>{-0.49144199999999999, 0.26006299999999999}</string>
+				<string>{0.50711799999999996, -0.22408600000000001}</string>
+				<string>{0.50711799999999996, 0.267179}</string>
+				<string>{-0.27431, -0.474028}</string>
+				<string>{0.27977999999999997, -0.47847800000000001}</string>
+				<string>{0.29393799999999998, 0.54304399999999997}</string>
+				<string>{-0.28623199999999999, 0.55380399999999996}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>1</string>
+						<key>g</key>
+						<string>0.874135</string>
+						<key>r</key>
+						<string>0.71718</string>
+					</dict>
+					<key>FillType</key>
+					<integer>2</integer>
+					<key>GradientAngle</key>
+					<real>90</real>
+					<key>GradientColor</key>
+					<dict>
+						<key>b</key>
+						<string>1</string>
+						<key>g</key>
+						<string>0.662438</string>
+						<key>r</key>
+						<string>0.464468</string>
+					</dict>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.35</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>Fuzziness</key>
+					<real>2.3972222805023193</real>
+					<key>ShadowVector</key>
+					<string>{0, 1}</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.93512</string>
+						<key>g</key>
+						<string>0.472602</string>
+						<key>r</key>
+						<string>0.333854</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>3</real>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\b\fs24 \cf0 Google\
+Play App}</string>
+				<key>VerticalPad</key>
+				<integer>0</integer>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{20.814800000000005, 103}, {80.185199999999995, 284}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>b</key>
+					<string>0</string>
+					<key>g</key>
+					<string>0</string>
+					<key>r</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans-Bold</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>157</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{1, 1}</string>
+				<string>{1, -1}</string>
+				<string>{-1, -1}</string>
+				<string>{-1, 1}</string>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+				<string>{-0.5, -0.233518}</string>
+				<string>{-0.49144199999999999, 0.26006299999999999}</string>
+				<string>{0.50711799999999996, -0.22408600000000001}</string>
+				<string>{0.50711799999999996, 0.267179}</string>
+				<string>{-0.27431, -0.474028}</string>
+				<string>{0.27977999999999997, -0.47847800000000001}</string>
+				<string>{0.29393799999999998, 0.54304399999999997}</string>
+				<string>{-0.28623199999999999, 0.55380399999999996}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>1</string>
+						<key>g</key>
+						<string>0.874135</string>
+						<key>r</key>
+						<string>0.71718</string>
+					</dict>
+					<key>FillType</key>
+					<integer>2</integer>
+					<key>GradientAngle</key>
+					<real>90</real>
+					<key>GradientColor</key>
+					<dict>
+						<key>b</key>
+						<string>1</string>
+						<key>g</key>
+						<string>0.662438</string>
+						<key>r</key>
+						<string>0.464468</string>
+					</dict>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.35</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>Fuzziness</key>
+					<real>2.3972222805023193</real>
+					<key>ShadowVector</key>
+					<string>{0, 1}</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.93512</string>
+						<key>g</key>
+						<string>0.472602</string>
+						<key>r</key>
+						<string>0.333854</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>3</real>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\b\fs24 \cf0 Your In-app\
+Billing Application}</string>
+				<key>VerticalPad</key>
+				<integer>0</integer>
+			</dict>
+		</dict>
+	</array>
+	<key>GridInfo</key>
+	<dict>
+		<key>ShowsGrid</key>
+		<string>YES</string>
+	</dict>
+	<key>GuidesLocked</key>
+	<string>NO</string>
+	<key>GuidesVisible</key>
+	<string>YES</string>
+	<key>HPages</key>
+	<integer>1</integer>
+	<key>ImageCounter</key>
+	<integer>1</integer>
+	<key>KeepToScale</key>
+	<false/>
+	<key>Layers</key>
+	<array>
+		<dict>
+			<key>Lock</key>
+			<string>NO</string>
+			<key>Name</key>
+			<string>Layer 1</string>
+			<key>Print</key>
+			<string>YES</string>
+			<key>View</key>
+			<string>YES</string>
+		</dict>
+	</array>
+	<key>LayoutInfo</key>
+	<dict>
+		<key>Animate</key>
+		<string>NO</string>
+		<key>circoMinDist</key>
+		<real>18</real>
+		<key>circoSeparation</key>
+		<real>0.0</real>
+		<key>layoutEngine</key>
+		<string>dot</string>
+		<key>neatoSeparation</key>
+		<real>0.0</real>
+		<key>twopiSeparation</key>
+		<real>0.0</real>
+	</dict>
+	<key>LinksVisible</key>
+	<string>NO</string>
+	<key>MagnetsVisible</key>
+	<string>NO</string>
+	<key>MasterSheets</key>
+	<array/>
+	<key>ModificationDate</key>
+	<string>2012-11-16 02:03:40 +0000</string>
+	<key>Modifier</key>
+	<string>Quddus Chong</string>
+	<key>NotesVisible</key>
+	<string>NO</string>
+	<key>Orientation</key>
+	<integer>2</integer>
+	<key>OriginVisible</key>
+	<string>NO</string>
+	<key>PageBreaks</key>
+	<string>YES</string>
+	<key>PrintInfo</key>
+	<dict>
+		<key>NSBottomMargin</key>
+		<array>
+			<string>float</string>
+			<string>41</string>
+		</array>
+		<key>NSHorizonalPagination</key>
+		<array>
+			<string>coded</string>
+			<string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG</string>
+		</array>
+		<key>NSLeftMargin</key>
+		<array>
+			<string>float</string>
+			<string>18</string>
+		</array>
+		<key>NSPaperSize</key>
+		<array>
+			<string>size</string>
+			<string>{612, 792}</string>
+		</array>
+		<key>NSPrintReverseOrientation</key>
+		<array>
+			<string>int</string>
+			<string>0</string>
+		</array>
+		<key>NSRightMargin</key>
+		<array>
+			<string>float</string>
+			<string>18</string>
+		</array>
+		<key>NSTopMargin</key>
+		<array>
+			<string>float</string>
+			<string>18</string>
+		</array>
+	</dict>
+	<key>PrintOnePage</key>
+	<false/>
+	<key>ReadOnly</key>
+	<string>NO</string>
+	<key>RowAlign</key>
+	<integer>1</integer>
+	<key>RowSpacing</key>
+	<real>36</real>
+	<key>SheetTitle</key>
+	<string>Canvas 1</string>
+	<key>SmartAlignmentGuidesActive</key>
+	<string>YES</string>
+	<key>SmartDistanceGuidesActive</key>
+	<string>YES</string>
+	<key>UniqueID</key>
+	<integer>1</integer>
+	<key>UseEntirePage</key>
+	<false/>
+	<key>VPages</key>
+	<integer>1</integer>
+	<key>WindowInfo</key>
+	<dict>
+		<key>CurrentSheet</key>
+		<integer>0</integer>
+		<key>ExpandedCanvases</key>
+		<array>
+			<dict>
+				<key>name</key>
+				<string>Canvas 1</string>
+			</dict>
+		</array>
+		<key>Frame</key>
+		<string>{{301, 4}, {1093, 874}}</string>
+		<key>ListView</key>
+		<true/>
+		<key>OutlineWidth</key>
+		<integer>142</integer>
+		<key>RightSidebar</key>
+		<false/>
+		<key>ShowRuler</key>
+		<true/>
+		<key>Sidebar</key>
+		<true/>
+		<key>SidebarWidth</key>
+		<integer>120</integer>
+		<key>VisibleRegion</key>
+		<string>{{-184, 14}, {944, 719}}</string>
+		<key>Zoom</key>
+		<real>1</real>
+		<key>ZoomValues</key>
+		<array>
+			<array>
+				<string>Canvas 1</string>
+				<real>1</real>
+				<real>1</real>
+			</array>
+		</array>
+	</dict>
+</dict>
+</plist>
diff --git a/docs/image_sources/in-app-billing/v3/iab_v3_purchase_flow.graffle b/docs/image_sources/in-app-billing/v3/iab_v3_purchase_flow.graffle
new file mode 100644
index 0000000..3624b07
--- /dev/null
+++ b/docs/image_sources/in-app-billing/v3/iab_v3_purchase_flow.graffle
@@ -0,0 +1,1879 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>ActiveLayerIndex</key>
+	<integer>0</integer>
+	<key>ApplicationVersion</key>
+	<array>
+		<string>com.omnigroup.OmniGrafflePro</string>
+		<string>139.16.0.171715</string>
+	</array>
+	<key>AutoAdjust</key>
+	<true/>
+	<key>BackgroundGraphic</key>
+	<dict>
+		<key>Bounds</key>
+		<string>{{0, 0}, {576, 733}}</string>
+		<key>Class</key>
+		<string>SolidGraphic</string>
+		<key>ID</key>
+		<integer>2</integer>
+		<key>Style</key>
+		<dict>
+			<key>shadow</key>
+			<dict>
+				<key>Draws</key>
+				<string>NO</string>
+			</dict>
+			<key>stroke</key>
+			<dict>
+				<key>Draws</key>
+				<string>NO</string>
+			</dict>
+		</dict>
+	</dict>
+	<key>BaseZoom</key>
+	<integer>0</integer>
+	<key>CanvasOrigin</key>
+	<string>{0, 0}</string>
+	<key>ColumnAlign</key>
+	<integer>1</integer>
+	<key>ColumnSpacing</key>
+	<real>36</real>
+	<key>CreationDate</key>
+	<string>2012-10-22 20:20:34 +0000</string>
+	<key>Creator</key>
+	<string>Quddus Chong</string>
+	<key>DisplayScale</key>
+	<string>1 0/72 in = 1.0000 in</string>
+	<key>GraphDocumentVersion</key>
+	<integer>8</integer>
+	<key>GraphicsList</key>
+	<array>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>233</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPoint</key>
+			<string>{0, 0}</string>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{103.6875, 163.71327209472656}</string>
+				<string>{474.6875, 162.71327209472656}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.7</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>4</real>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>232</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPoint</key>
+			<string>{0, 0}</string>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{474.0625, 237.7132568359375}</string>
+				<string>{343.3125, 237.7132568359375}</string>
+				<string>{100.3125, 237.7132568359375}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.7</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>4</real>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>Pattern</key>
+					<integer>1</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{100.9375, 172.7132568359375}, {373.75, 66}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>Vertical</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>a</key>
+					<string>0.65</string>
+					<key>w</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>203</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>RTFD</key>
+				<data>
+				BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+				ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+				bmcBlIQBK35CdW5kbGUoUkVTUE9OU0VfQ09ERSwgSU5B
+				UFBfUFVSQ0hBU0VfSVRFTV9MSVNULCBJTkFQUF9QVVJD
+				SEFTRV9EQVRBX0xJU1QsIElOQVBQX0RBVEFfU0lHTkFU
+				VVJFX0xJU1QsIElOQVBQX0NPTlRJTlVBVElPTl9UT0tF
+				TimGhAJpSQF+koSEhAxOU0RpY3Rpb25hcnkAlIQBaQOS
+				hJaWB05TQ29sb3KGkoSEhAdOU0NvbG9yAJSEAWMDhAJm
+				ZgCDZmYmP4aShJaWEE5TUGFyYWdyYXBoU3R5bGWGkoSE
+				hBBOU1BhcmFncmFwaFN0eWxlAJSEBENDQFMCAISEhAdO
+				U0FycmF5AJSZDJKEhIQJTlNUZXh0VGFiAJSEAkNmAByG
+				koSioQA4hpKEoqEAVIaShKKhAHCGkoSioQCBjACGkoSi
+				oQCBqACGkoSioQCBxACGkoSioQCB4ACGkoSioQCB/ACG
+				koSioQCBGAGGkoSioQCBNAGGkoSioQCBUAGGhoEACIQE
+				WzFmXYPNzEw9hpKElpYGTlNGb250hpKEhIQGTlNGb250
+				HpSZHIQFWzI4Y10GAAAAFAAAAP/+SABlAGwAdgBlAHQA
+				aQBjAGEAhAFmDJsAmwGbAJsAhoaG
+				</data>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf2 Bundle(RESPONSE_CODE, INAPP_PURCHASE_ITEM_LIST, INAPP_PURCHASE_DATA_LIST, INAPP_DATA_SIGNATURE_LIST, INAPP_CONTINUATION_TOKEN)}</string>
+				<key>alpha</key>
+				<array>
+					<array>
+						<integer>0</integer>
+						<integer>126</integer>
+						<real>0.64999997615814209</real>
+					</array>
+				</array>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{239.18752503395081, 138.71327209472656}, {97, 24}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>a</key>
+					<string>0.65</string>
+					<key>w</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>199</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>RTFD</key>
+				<data>
+				BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+				ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+				bmcBlIQBKw5nZXRQdXJjaGFzZXMoKYaEAmlJAQ6ShISE
+				DE5TRGljdGlvbmFyeQCUhAFpA5KElpYHTlNDb2xvcoaS
+				hISEB05TQ29sb3IAlIQBYwOEAmZmAINmZiY/hpKElpYQ
+				TlNQYXJhZ3JhcGhTdHlsZYaShISEEE5TUGFyYWdyYXBo
+				U3R5bGUAlIQEQ0NAUwIAhISEB05TQXJyYXkAlJkMkoSE
+				hAlOU1RleHRUYWIAlIQCQ2YAHIaShKKhADiGkoSioQBU
+				hpKEoqEAcIaShKKhAIGMAIaShKKhAIGoAIaShKKhAIHE
+				AIaShKKhAIHgAIaShKKhAIH8AIaShKKhAIEYAYaShKKh
+				AIE0AYaShKKhAIFQAYaGgQAIhARbMWZdg83MTD2GkoSW
+				lgZOU0ZvbnSGkoSEhAZOU0ZvbnQelJkohAVbNDBjXQYA
+				AAAeAAAA//5IAGUAbAB2AGUAdABpAGMAYQAtAEIAbwBs
+				AGQAAACEAWYMmwCbAZsAmwCGhoY=
+				</data>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\b\fs24 \cf2 getPurchases()}</string>
+				<key>alpha</key>
+				<array>
+					<array>
+						<integer>0</integer>
+						<integer>14</integer>
+						<real>0.64999997615814209</real>
+					</array>
+				</array>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>231</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPoint</key>
+			<string>{0, 0}</string>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{103, 504}</string>
+				<string>{474, 503}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.7</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>4</real>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>230</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPoint</key>
+			<string>{0, 0}</string>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{103, 76.2867431640625}</string>
+				<string>{474, 75.2867431640625}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.7</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>4</real>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>229</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPoint</key>
+			<string>{0, 0}</string>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{471.0000031888485, 112}</string>
+				<string>{341.9117077589035, 112}</string>
+				<string>{102, 112}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.7</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>4</real>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>Pattern</key>
+					<integer>1</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>228</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPoint</key>
+			<string>{0, 0}</string>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{472.0000031888485, 326.77316284179688}</string>
+				<string>{342.9117077589035, 326.77316284179688}</string>
+				<string>{103, 326.77316284179688}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.7</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>4</real>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>Pattern</key>
+					<integer>1</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>227</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPoint</key>
+			<string>{0, 0}</string>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{474.75, 428.573486328125}</string>
+				<string>{344, 428.573486328125}</string>
+				<string>{101, 428.573486328125}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.7</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>4</real>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>Pattern</key>
+					<integer>1</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{193, 89}, {195, 24}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>a</key>
+					<string>0.65</string>
+					<key>w</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>224</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>RTFD</key>
+				<data>
+				BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+				ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+				bmcBlIQBKxdTVVBQT1JURUQvTk9UX1NVUFBPUlRFRIaE
+				AmlJAReShISEDE5TRGljdGlvbmFyeQCUhAFpA5KElpYH
+				TlNDb2xvcoaShISEB05TQ29sb3IAlIQBYwOEAmZmAINm
+				ZiY/hpKElpYQTlNQYXJhZ3JhcGhTdHlsZYaShISEEE5T
+				UGFyYWdyYXBoU3R5bGUAlIQEQ0NAUwIAhISEB05TQXJy
+				YXkAlJkMkoSEhAlOU1RleHRUYWIAlIQCQ2YAHIaShKKh
+				ADiGkoSioQBUhpKEoqEAcIaShKKhAIGMAIaShKKhAIGo
+				AIaShKKhAIHEAIaShKKhAIHgAIaShKKhAIH8AIaShKKh
+				AIEYAYaShKKhAIE0AYaShKKhAIFQAYaGgQAIhARbMWZd
+				g83MTD2GkoSWlgZOU0ZvbnSGkoSEhAZOU0ZvbnQelJkc
+				hAVbMjhjXQYAAAAUAAAA//5IAGUAbAB2AGUAdABpAGMA
+				YQCEAWYMmwCbAZsAmwCGhoY=
+				</data>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf2 SUPPORTED/NOT_SUPPORTED}</string>
+				<key>alpha</key>
+				<array>
+					<array>
+						<integer>0</integer>
+						<integer>23</integer>
+						<real>0.64999997615814209</real>
+					</array>
+				</array>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{117.6875, 51.2867431640625}, {339, 24}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>Vertical</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>a</key>
+					<string>0.65</string>
+					<key>w</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>222</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>RTFD</key>
+				<data>
+				BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+				ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+				bmcBlIQBKxRpc0JpbGxpbmdTdXBwb3J0ZWQoKYaEAmlJ
+				ARSShISEDE5TRGljdGlvbmFyeQCUhAFpBJKElpYQTlNQ
+				YXJhZ3JhcGhTdHlsZYaShISEEE5TUGFyYWdyYXBoU3R5
+				bGUAlIQEQ0NAUwIAhISEB05TQXJyYXkAlJkMkoSEhAlO
+				U1RleHRUYWIAlIQCQ2YAHIaShJ+eADiGkoSfngBUhpKE
+				n54AcIaShJ+eAIGMAIaShJ+eAIGoAIaShJ+eAIHEAIaS
+				hJ+eAIHgAIaShJ+eAIH8AIaShJ+eAIEYAYaShJ+eAIE0
+				AYaShJ+eAIFQAYaGgQAIhARbMWZdg83MTD2GkoSWlgdO
+				U0NvbG9yhpKEhIQHTlNDb2xvcgCUhAFjA4QCZmYAg2Zm
+				Jj+GkoSWlgZOU0ZvbnSGkoSEhAZOU0ZvbnQelJkohAVb
+				NDBjXQYAAAAeAAAA//5IAGUAbAB2AGUAdABpAGMAYQAt
+				AEIAbwBsAGQAAACEAWYMoQChAaEAoQCGkoSWlg5OU09y
+				aWdpbmFsRm9udIaSr4aG
+				</data>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\b\fs24 \cf2 isBillingSupported()}</string>
+				<key>alpha</key>
+				<array>
+					<array>
+						<integer>0</integer>
+						<integer>20</integer>
+						<real>0.64999997615814209</real>
+					</array>
+				</array>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>217</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPoint</key>
+			<string>{0, 0}</string>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{476.125, 548.6573486328125}</string>
+				<string>{345.375, 548.6573486328125}</string>
+				<string>{102.375, 548.6573486328125}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.7</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>4</real>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>Pattern</key>
+					<integer>1</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{202.25, 480}, {174, 24}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>a</key>
+					<string>0.65</string>
+					<key>w</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>216</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>RTFD</key>
+				<data>
+				BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+				ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+				bmcBlIQBKxxzdGFydEludGVudFNlbmRlckZvclJlc3Vs
+				dCgphoQCaUkBG5KEhIQMTlNEaWN0aW9uYXJ5AJSEAWkE
+				koSWlhBOU1BhcmFncmFwaFN0eWxlhpKEhIQQTlNQYXJh
+				Z3JhcGhTdHlsZQCUhARDQ0BTAgCEhIQHTlNBcnJheQCU
+				mQyShISECU5TVGV4dFRhYgCUhAJDZgAchpKEn54AOIaS
+				hJ+eAFSGkoSfngBwhpKEn54AgYwAhpKEn54AgagAhpKE
+				n54AgcQAhpKEn54AgeAAhpKEn54AgfwAhpKEn54AgRgB
+				hpKEn54AgTQBhpKEn54AgVABhoaBAAiEBFsxZl2DzcxM
+				PYaShJaWB05TQ29sb3KGkoSEhAdOU0NvbG9yAJSEAWMD
+				hAJmZgCDZmYmP4aShJaWBk5TRm9udIaShISEBk5TRm9u
+				dB6UmSiEBVs0MGNdBgAAAB4AAAD//kgAZQBsAHYAZQB0
+				AGkAYwBhAC0AQgBvAGwAZAAAAIQBZgyhAKEBoQChAIaS
+				hJaWDk5TT3JpZ2luYWxGb250hpKvhpcCAZKEmJkDkquS
+				rJKZkpqSrpKEsJkchAVbMjhjXQYAAAAUAAAA//5IAGUA
+				bAB2AGUAdABpAGMAYQClDKEAoQGhAKEAhoaG
+				</data>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\b\fs24 \cf2 startIntentSenderForResult(
+\b0 )}</string>
+				<key>alpha</key>
+				<array>
+					<array>
+						<integer>0</integer>
+						<integer>27</integer>
+						<real>0.64999997615814209</real>
+					</array>
+					<array>
+						<integer>27</integer>
+						<integer>1</integer>
+						<real>0.64999997615814209</real>
+					</array>
+				</array>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{111.75, 510.6573486328125}, {352.25, 38}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>Vertical</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>a</key>
+					<string>0.65</string>
+					<key>w</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>214</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>RTFD</key>
+				<data>
+				BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+				ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+				bmcBlIQBK0BCdW5kbGUoUkVTUE9OU0VfQ09ERSwgSU5B
+				UFBfUFVSQ0hBU0VfREFUQSwgSU5BUFBfREFUQV9TSUdO
+				QVRVUkUphoQCaUkBQJKEhIQMTlNEaWN0aW9uYXJ5AJSE
+				AWkDkoSWlgdOU0NvbG9yhpKEhIQHTlNDb2xvcgCUhAFj
+				A4QCZmYAg2ZmJj+GkoSWlhBOU1BhcmFncmFwaFN0eWxl
+				hpKEhIQQTlNQYXJhZ3JhcGhTdHlsZQCUhARDQ0BTAgCE
+				hIQHTlNBcnJheQCUmQyShISECU5TVGV4dFRhYgCUhAJD
+				ZgAchpKEoqEAOIaShKKhAFSGkoSioQBwhpKEoqEAgYwA
+				hpKEoqEAgagAhpKEoqEAgcQAhpKEoqEAgeAAhpKEoqEA
+				gfwAhpKEoqEAgRgBhpKEoqEAgTQBhpKEoqEAgVABhoaB
+				AAiEBFsxZl2DzcxMPYaShJaWBk5TRm9udIaShISEBk5T
+				Rm9udB6UmRyEBVsyOGNdBgAAABQAAAD//kgAZQBsAHYA
+				ZQB0AGkAYwBhAIQBZgybAJsBmwCbAIaGhg==
+				</data>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf2 Bundle(RESPONSE_CODE, INAPP_PURCHASE_DATA, INAPP_DATA_SIGNATURE)}</string>
+				<key>alpha</key>
+				<array>
+					<array>
+						<integer>0</integer>
+						<integer>64</integer>
+						<real>0.64999997615814209</real>
+					</array>
+				</array>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{120.75, 405.57347106933594}, {331.5, 24}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>Vertical</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>a</key>
+					<string>0.65</string>
+					<key>w</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>212</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>RTFD</key>
+				<data>
+				BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+				ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+				bmcBlIQBKyFCdW5kbGUoUkVTUE9OU0VfQ09ERSwgQlVZ
+				X0lOVEVOVCmGhAJpSQEhkoSEhAxOU0RpY3Rpb25hcnkA
+				lIQBaQOShJaWB05TQ29sb3KGkoSEhAdOU0NvbG9yAJSE
+				AWMDhAJmZgCDZmYmP4aShJaWEE5TUGFyYWdyYXBoU3R5
+				bGWGkoSEhBBOU1BhcmFncmFwaFN0eWxlAJSEBENDQFMC
+				AISEhAdOU0FycmF5AJSZDJKEhIQJTlNUZXh0VGFiAJSE
+				AkNmAByGkoSioQA4hpKEoqEAVIaShKKhAHCGkoSioQCB
+				jACGkoSioQCBqACGkoSioQCBxACGkoSioQCB4ACGkoSi
+				oQCB/ACGkoSioQCBGAGGkoSioQCBNAGGkoSioQCBUAGG
+				hoEACIQEWzFmXYPNzEw9hpKElpYGTlNGb250hpKEhIQG
+				TlNGb250HpSZHIQFWzI4Y10GAAAAFAAAAP/+SABlAGwA
+				dgBlAHQAaQBjAGEAhAFmDJsAmwGbAJsAhoaG
+				</data>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf2 Bundle(RESPONSE_CODE, BUY_INTENT)}</string>
+				<key>alpha</key>
+				<array>
+					<array>
+						<integer>0</integer>
+						<integer>33</integer>
+						<real>0.64999997615814209</real>
+					</array>
+				</array>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>211</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPoint</key>
+			<string>{0, 0}</string>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{102.5, 386.685302734375}</string>
+				<string>{473.5, 385.685302734375}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.7</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>4</real>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{169.75, 362.685302734375}, {239, 24}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>Vertical</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>a</key>
+					<string>0.65</string>
+					<key>w</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>210</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>RTFD</key>
+				<data>
+				BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+				ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+				bmcBlIQBKw5nZXRCdXlJbnRlbnQoKYaEAmlJAQ6ShISE
+				DE5TRGljdGlvbmFyeQCUhAFpBJKElpYQTlNQYXJhZ3Jh
+				cGhTdHlsZYaShISEEE5TUGFyYWdyYXBoU3R5bGUAlIQE
+				Q0NAUwIAhISEB05TQXJyYXkAlJkMkoSEhAlOU1RleHRU
+				YWIAlIQCQ2YAHIaShJ+eADiGkoSfngBUhpKEn54AcIaS
+				hJ+eAIGMAIaShJ+eAIGoAIaShJ+eAIHEAIaShJ+eAIHg
+				AIaShJ+eAIH8AIaShJ+eAIEYAYaShJ+eAIE0AYaShJ+e
+				AIFQAYaGgQAIhARbMWZdg83MTD2GkoSWlgdOU0NvbG9y
+				hpKEhIQHTlNDb2xvcgCUhAFjA4QCZmYAg2ZmJj+GkoSW
+				lgZOU0ZvbnSGkoSEhAZOU0ZvbnQelJkohAVbNDBjXQYA
+				AAAeAAAA//5IAGUAbAB2AGUAdABpAGMAYQAtAEIAbwBs
+				AGQAAACEAWYMoQChAaEAoQCGkoSWlg5OU09yaWdpbmFs
+				Rm9udIaSr4aG
+				</data>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\b\fs24 \cf2 getBuyIntent()}</string>
+				<key>alpha</key>
+				<array>
+					<array>
+						<integer>0</integer>
+						<integer>14</integer>
+						<real>0.64999997615814209</real>
+					</array>
+				</array>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{161.5, 307.5}, {252, 24}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>a</key>
+					<string>0.65</string>
+					<key>w</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>208</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>RTFD</key>
+				<data>
+				BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+				ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+				bmcBlIQBKyNCdW5kbGUoUkVTUE9OU0VfQ09ERSwgREVU
+				QUlMU19MSVNUKYaEAmlJASOShISEDE5TRGljdGlvbmFy
+				eQCUhAFpA5KElpYHTlNDb2xvcoaShISEB05TQ29sb3IA
+				lIQBYwOEAmZmAINmZiY/hpKElpYQTlNQYXJhZ3JhcGhT
+				dHlsZYaShISEEE5TUGFyYWdyYXBoU3R5bGUAlIQEQ0NA
+				UwIAhISEB05TQXJyYXkAlJkMkoSEhAlOU1RleHRUYWIA
+				lIQCQ2YAHIaShKKhADiGkoSioQBUhpKEoqEAcIaShKKh
+				AIGMAIaShKKhAIGoAIaShKKhAIHEAIaShKKhAIHgAIaS
+				hKKhAIH8AIaShKKhAIEYAYaShKKhAIE0AYaShKKhAIFQ
+				AYaGgQAIhARbMWZdg83MTD2GkoSWlgZOU0ZvbnSGkoSE
+				hAZOU0ZvbnQelJkchAVbMjhjXQYAAAAUAAAA//5IAGUA
+				bAB2AGUAdABpAGMAYQCEAWYMmwCbAZsAmwCGhoY=
+				</data>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf2 Bundle(RESPONSE_CODE, DETAILS_LIST)}</string>
+				<key>alpha</key>
+				<array>
+					<array>
+						<integer>0</integer>
+						<integer>35</integer>
+						<real>0.64999997615814209</real>
+					</array>
+				</array>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>206</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPoint</key>
+			<string>{0, 0}</string>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{103, 289.64337158203125}</string>
+				<string>{474, 288.64337158203125}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.7</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>4</real>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{117.6875, 267.86102294921875}, {339, 24}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>Vertical</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>a</key>
+					<string>0.65</string>
+					<key>w</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>205</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>RTFD</key>
+				<data>
+				BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+				ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+				bmcBlIQBKw9nZXRTa3VEZXRhaWxzKCmGhAJpSQEPkoSE
+				hAxOU0RpY3Rpb25hcnkAlIQBaQSShJaWEE5TUGFyYWdy
+				YXBoU3R5bGWGkoSEhBBOU1BhcmFncmFwaFN0eWxlAJSE
+				BENDQFMCAISEhAdOU0FycmF5AJSZDJKEhIQJTlNUZXh0
+				VGFiAJSEAkNmAByGkoSfngA4hpKEn54AVIaShJ+eAHCG
+				koSfngCBjACGkoSfngCBqACGkoSfngCBxACGkoSfngCB
+				4ACGkoSfngCB/ACGkoSfngCBGAGGkoSfngCBNAGGkoSf
+				ngCBUAGGhoEACIQEWzFmXYPNzEw9hpKElpYHTlNDb2xv
+				coaShISEB05TQ29sb3IAlIQBYwOEAmZmAINmZiY/hpKE
+				lpYGTlNGb250hpKEhIQGTlNGb250HpSZKIQFWzQwY10G
+				AAAAHgAAAP/+SABlAGwAdgBlAHQAaQBjAGEALQBCAG8A
+				bABkAAAAhAFmDKEAoQGhAKEAhpKElpYOTlNPcmlnaW5h
+				bEZvbnSGkq+Ghg==
+				</data>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\b\fs24 \cf2 getSkuDetails()}</string>
+				<key>alpha</key>
+				<array>
+					<array>
+						<integer>0</integer>
+						<integer>15</integer>
+						<real>0.64999997615814209</real>
+					</array>
+				</array>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{475.49999999999994, 47}, {80.185199999999995, 530}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>b</key>
+					<string>0</string>
+					<key>g</key>
+					<string>0</string>
+					<key>r</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans-Bold</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>200</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{1, 1}</string>
+				<string>{1, -1}</string>
+				<string>{-1, -1}</string>
+				<string>{-1, 1}</string>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+				<string>{-0.5, -0.233518}</string>
+				<string>{-0.49144199999999999, 0.26006299999999999}</string>
+				<string>{0.50711799999999996, -0.22408600000000001}</string>
+				<string>{0.50711799999999996, 0.267179}</string>
+				<string>{-0.27431, -0.474028}</string>
+				<string>{0.27977999999999997, -0.47847800000000001}</string>
+				<string>{0.29393799999999998, 0.54304399999999997}</string>
+				<string>{-0.28623199999999999, 0.55380399999999996}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>1</string>
+						<key>g</key>
+						<string>0.874135</string>
+						<key>r</key>
+						<string>0.71718</string>
+					</dict>
+					<key>FillType</key>
+					<integer>2</integer>
+					<key>GradientAngle</key>
+					<real>90</real>
+					<key>GradientColor</key>
+					<dict>
+						<key>b</key>
+						<string>1</string>
+						<key>g</key>
+						<string>0.662438</string>
+						<key>r</key>
+						<string>0.464468</string>
+					</dict>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.35</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>Fuzziness</key>
+					<real>2.3972222805023193</real>
+					<key>ShadowVector</key>
+					<string>{0, 1}</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.93512</string>
+						<key>g</key>
+						<string>0.472602</string>
+						<key>r</key>
+						<string>0.333854</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>3</real>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\b\fs24 \cf0 Google\
+Play App}</string>
+				<key>VerticalPad</key>
+				<integer>0</integer>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{22.814800000000005, 47}, {80.185199999999995, 530}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>b</key>
+					<string>0</string>
+					<key>g</key>
+					<string>0</string>
+					<key>r</key>
+					<string>0</string>
+				</dict>
+				<key>Font</key>
+				<string>DroidSans-Bold</string>
+				<key>Size</key>
+				<real>10</real>
+			</dict>
+			<key>ID</key>
+			<integer>157</integer>
+			<key>Magnets</key>
+			<array>
+				<string>{1, 1}</string>
+				<string>{1, -1}</string>
+				<string>{-1, -1}</string>
+				<string>{-1, 1}</string>
+				<string>{0, 1}</string>
+				<string>{0, -1}</string>
+				<string>{1, 0}</string>
+				<string>{-1, 0}</string>
+				<string>{-0.5, -0.233518}</string>
+				<string>{-0.49144199999999999, 0.26006299999999999}</string>
+				<string>{0.50711799999999996, -0.22408600000000001}</string>
+				<string>{0.50711799999999996, 0.267179}</string>
+				<string>{-0.27431, -0.474028}</string>
+				<string>{0.27977999999999997, -0.47847800000000001}</string>
+				<string>{0.29393799999999998, 0.54304399999999997}</string>
+				<string>{-0.28623199999999999, 0.55380399999999996}</string>
+			</array>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>1</string>
+						<key>g</key>
+						<string>0.874135</string>
+						<key>r</key>
+						<string>0.71718</string>
+					</dict>
+					<key>FillType</key>
+					<integer>2</integer>
+					<key>GradientAngle</key>
+					<real>90</real>
+					<key>GradientColor</key>
+					<dict>
+						<key>b</key>
+						<string>1</string>
+						<key>g</key>
+						<string>0.662438</string>
+						<key>r</key>
+						<string>0.464468</string>
+					</dict>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>a</key>
+						<string>0.35</string>
+						<key>b</key>
+						<string>0</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0</string>
+					</dict>
+					<key>Fuzziness</key>
+					<real>2.3972222805023193</real>
+					<key>ShadowVector</key>
+					<string>{0, 1}</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.93512</string>
+						<key>g</key>
+						<string>0.472602</string>
+						<key>r</key>
+						<string>0.333854</string>
+					</dict>
+					<key>CornerRadius</key>
+					<real>3</real>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\b\fs24 \cf0 Your \
+In-app Billing\
+Application}</string>
+				<key>VerticalPad</key>
+				<integer>0</integer>
+			</dict>
+		</dict>
+	</array>
+	<key>GridInfo</key>
+	<dict>
+		<key>ShowsGrid</key>
+		<string>YES</string>
+	</dict>
+	<key>GuidesLocked</key>
+	<string>NO</string>
+	<key>GuidesVisible</key>
+	<string>YES</string>
+	<key>HPages</key>
+	<integer>1</integer>
+	<key>ImageCounter</key>
+	<integer>1</integer>
+	<key>KeepToScale</key>
+	<false/>
+	<key>Layers</key>
+	<array>
+		<dict>
+			<key>Lock</key>
+			<string>NO</string>
+			<key>Name</key>
+			<string>Layer 1</string>
+			<key>Print</key>
+			<string>YES</string>
+			<key>View</key>
+			<string>YES</string>
+		</dict>
+	</array>
+	<key>LayoutInfo</key>
+	<dict>
+		<key>Animate</key>
+		<string>NO</string>
+		<key>circoMinDist</key>
+		<real>18</real>
+		<key>circoSeparation</key>
+		<real>0.0</real>
+		<key>layoutEngine</key>
+		<string>dot</string>
+		<key>neatoSeparation</key>
+		<real>0.0</real>
+		<key>twopiSeparation</key>
+		<real>0.0</real>
+	</dict>
+	<key>LinksVisible</key>
+	<string>NO</string>
+	<key>MagnetsVisible</key>
+	<string>NO</string>
+	<key>MasterSheets</key>
+	<array/>
+	<key>ModificationDate</key>
+	<string>2012-11-16 02:31:19 +0000</string>
+	<key>Modifier</key>
+	<string>Quddus Chong</string>
+	<key>NotesVisible</key>
+	<string>NO</string>
+	<key>Orientation</key>
+	<integer>2</integer>
+	<key>OriginVisible</key>
+	<string>NO</string>
+	<key>PageBreaks</key>
+	<string>YES</string>
+	<key>PrintInfo</key>
+	<dict>
+		<key>NSBottomMargin</key>
+		<array>
+			<string>float</string>
+			<string>41</string>
+		</array>
+		<key>NSHorizonalPagination</key>
+		<array>
+			<string>coded</string>
+			<string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG</string>
+		</array>
+		<key>NSLeftMargin</key>
+		<array>
+			<string>float</string>
+			<string>18</string>
+		</array>
+		<key>NSPaperSize</key>
+		<array>
+			<string>size</string>
+			<string>{612, 792}</string>
+		</array>
+		<key>NSPrintReverseOrientation</key>
+		<array>
+			<string>int</string>
+			<string>0</string>
+		</array>
+		<key>NSRightMargin</key>
+		<array>
+			<string>float</string>
+			<string>18</string>
+		</array>
+		<key>NSTopMargin</key>
+		<array>
+			<string>float</string>
+			<string>18</string>
+		</array>
+	</dict>
+	<key>PrintOnePage</key>
+	<false/>
+	<key>ReadOnly</key>
+	<string>NO</string>
+	<key>RowAlign</key>
+	<integer>1</integer>
+	<key>RowSpacing</key>
+	<real>36</real>
+	<key>SheetTitle</key>
+	<string>Canvas 1</string>
+	<key>SmartAlignmentGuidesActive</key>
+	<string>YES</string>
+	<key>SmartDistanceGuidesActive</key>
+	<string>YES</string>
+	<key>UniqueID</key>
+	<integer>1</integer>
+	<key>UseEntirePage</key>
+	<false/>
+	<key>VPages</key>
+	<integer>1</integer>
+	<key>WindowInfo</key>
+	<dict>
+		<key>CurrentSheet</key>
+		<integer>0</integer>
+		<key>ExpandedCanvases</key>
+		<array>
+			<dict>
+				<key>name</key>
+				<string>Canvas 1</string>
+			</dict>
+		</array>
+		<key>Frame</key>
+		<string>{{122, 4}, {1093, 874}}</string>
+		<key>ListView</key>
+		<true/>
+		<key>OutlineWidth</key>
+		<integer>142</integer>
+		<key>RightSidebar</key>
+		<false/>
+		<key>ShowRuler</key>
+		<true/>
+		<key>Sidebar</key>
+		<true/>
+		<key>SidebarWidth</key>
+		<integer>120</integer>
+		<key>VisibleRegion</key>
+		<string>{{-184, 14}, {944, 719}}</string>
+		<key>Zoom</key>
+		<real>1</real>
+		<key>ZoomValues</key>
+		<array>
+			<array>
+				<string>Canvas 1</string>
+				<real>1</real>
+				<real>1</real>
+			</array>
+		</array>
+	</dict>
+</dict>
+</plist>
diff --git a/location/lib/Android.mk b/location/lib/Android.mk
deleted file mode 100644
index 62f5677..0000000
--- a/location/lib/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-#
-# Copyright (C) 2010 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)
-
-# the library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= com.android.location.provider
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
-            $(call all-subdir-java-files) \
-            $(call all-aidl-files-under, java)
-
-include $(BUILD_JAVA_LIBRARY)
-
-
-# ====  com.google.location.xml lib def  ========================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := com.android.location.provider.xml
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_CLASS := ETC
-
-# This will install the file in /system/etc/permissions
-#
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
-
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-
-include $(BUILD_PREBUILT)
diff --git a/location/lib/README.txt b/location/lib/README.txt
deleted file mode 100644
index 400a7dd..0000000
--- a/location/lib/README.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-This library (com.android.location.provider.jar) is a shared java library
-containing classes required by unbundled location providers.
-
---- Rules of this library ---
-o This library is effectively a PUBLIC API for unbundled location providers
-  that may be distributed outside the system image. So it MUST BE API STABLE.
-  You can add but not remove. The rules are the same as for the
-  public platform SDK API.
-o This library can see and instantiate internal platform classes (such as
-  ProviderRequest.java), but it must not expose them in any public method
-  (or by extending them via inheritance). This would break clients of the
-  library because they cannot see the internal platform classes.
-
-This library is distributed in the system image, and loaded as
-a shared library. So you can change the implementation, but not
-the interface. In this way it is like framework.jar.
-
---- Why does this library exists? ---
-
-Unbundled location providers (such as the NetworkLocationProvider)
-can not use internal platform classes.
-
-So ideally all of these classes would be part of the public platform SDK API,
-but that doesn't seem like a great idea when only applications with a special
-signature can implement this API.
-
-The compromise is this library.
-
-It wraps internal platform classes (like ProviderRequest) with a stable
-API that does not leak the internal classes.
diff --git a/location/lib/com.android.location.provider.xml b/location/lib/com.android.location.provider.xml
deleted file mode 100644
index 000e68f..0000000
--- a/location/lib/com.android.location.provider.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.
--->
-
-<permissions>
-    <library name="com.android.location.provider"
-            file="/system/framework/com.android.location.provider.jar" />
-</permissions>
diff --git a/location/lib/java/com/android/location/provider/GeocodeProvider.java b/location/lib/java/com/android/location/provider/GeocodeProvider.java
deleted file mode 100644
index d7a34af..0000000
--- a/location/lib/java/com/android/location/provider/GeocodeProvider.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2010 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.location.provider;
-
-import android.os.IBinder;
-
-import android.location.Address;
-import android.location.GeocoderParams;
-import android.location.IGeocodeProvider;
-
-import java.util.List;
-
-/**
- * Base class for geocode providers implemented as unbundled services.
- *
- * <p>Geocode providers can be implemented as services and return the result of
- * {@link GeocodeProvider#getBinder()} in its getBinder() method.
- *
- * <p>IMPORTANT: This class is effectively a public API for unbundled
- * applications, and must remain API stable. See README.txt in the root
- * of this package for more information.
- */
-public abstract class GeocodeProvider {
-
-    private IGeocodeProvider.Stub mProvider = new IGeocodeProvider.Stub() {
-        public String getFromLocation(double latitude, double longitude, int maxResults,
-                GeocoderParams params, List<Address> addrs) {
-            return GeocodeProvider.this.onGetFromLocation(latitude, longitude, maxResults,
-                    params, addrs);
-        }
-
-        public String getFromLocationName(String locationName,
-                double lowerLeftLatitude, double lowerLeftLongitude,
-                double upperRightLatitude, double upperRightLongitude, int maxResults,
-                GeocoderParams params, List<Address> addrs) {
-            return GeocodeProvider.this.onGetFromLocationName(locationName, lowerLeftLatitude,
-                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
-                    maxResults, params, addrs);
-        }
-    };
-
-    /**
-     * This method is overridden to implement the
-     * {@link android.location.Geocoder#getFromLocation(double, double, int)} method.
-     * Classes implementing this method should not hold a reference to the params parameter.
-     */
-    public abstract String onGetFromLocation(double latitude, double longitude, int maxResults,
-            GeocoderParams params, List<Address> addrs);
-
-    /**
-     * This method is overridden to implement the
-     * {@link android.location.Geocoder#getFromLocationName(String, int, double, double, double, double)} method.
-     * Classes implementing this method should not hold a reference to the params parameter.
-     */
-    public abstract String onGetFromLocationName(String locationName,
-            double lowerLeftLatitude, double lowerLeftLongitude,
-            double upperRightLatitude, double upperRightLongitude, int maxResults,
-            GeocoderParams params, List<Address> addrs);
-
-    /**
-     * Returns the Binder interface for the geocode provider.
-     * This is intended to be used for the onBind() method of
-     * a service that implements a geocoder service.
-     *
-     * @return the IBinder instance for the provider
-     */
-    public IBinder getBinder() {
-        return mProvider;
-    }
-}
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
deleted file mode 100644
index 8a5a739..0000000
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2010 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.location.provider;
-
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-
-import android.content.Context;
-import android.location.ILocationManager;
-import android.location.Location;
-import android.location.LocationManager;
-import android.location.LocationRequest;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.WorkSource;
-import android.util.Log;
-
-import com.android.internal.location.ILocationProvider;
-import com.android.internal.location.ProviderProperties;
-import com.android.internal.location.ProviderRequest;
-
-/**
- * Base class for location providers implemented as unbundled services.
- *
- * <p>The network location provider must export a service with action
- * "com.android.location.service.v2.NetworkLocationProvider"
- * and a valid minor version in a meta-data field on the service, and
- * then return the result of {@link #getBinder()} on service binding.
- *
- * <p>The fused location provider must export a service with action
- * "com.android.location.service.FusedLocationProvider"
- * and a valid minor version in a meta-data field on the service, and
- * then return the result of {@link #getBinder()} on service binding.
- *
- * <p>IMPORTANT: This class is effectively a public API for unbundled
- * applications, and must remain API stable. See README.txt in the root
- * of this package for more information.
- */
-public abstract class LocationProviderBase {
-    private final String TAG;
-
-    protected final ILocationManager mLocationManager;
-    private final ProviderProperties mProperties;
-    private final IBinder mBinder;
-
-    /**
-     * Bundle key for a version of the location containing no GPS data.
-     * Allows location providers to flag locations as being safe to
-     * feed to LocationFudger.
-     */
-    public static final String EXTRA_NO_GPS_LOCATION = Location.EXTRA_NO_GPS_LOCATION;
-
-    /**
-     * Name of the Fused location provider.
-     *
-     * <p>This provider combines inputs for all possible location sources
-     * to provide the best possible Location fix.
-     */
-    public static final String FUSED_PROVIDER = LocationManager.FUSED_PROVIDER;
-
-    private final class Service extends ILocationProvider.Stub {
-        @Override
-        public void enable() {
-            onEnable();
-        }
-        @Override
-        public void disable() {
-            onDisable();
-        }
-        @Override
-        public void setRequest(ProviderRequest request, WorkSource ws) {
-            onSetRequest(new ProviderRequestUnbundled(request), ws);
-        }
-        @Override
-        public ProviderProperties getProperties() {
-            return mProperties;
-        }
-        @Override
-        public int getStatus(Bundle extras) {
-            return onGetStatus(extras);
-        }
-        @Override
-        public long getStatusUpdateTime() {
-            return onGetStatusUpdateTime();
-        }
-        @Override
-        public boolean sendExtraCommand(String command, Bundle extras) {
-            return onSendExtraCommand(command, extras);
-        }
-        @Override
-        public void dump(FileDescriptor fd, String[] args) {
-            PrintWriter pw = new PrintWriter(new FileOutputStream(fd));
-            onDump(fd, pw, args);
-            pw.flush();
-        }
-    }
-
-    public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) {
-        TAG = tag;
-        IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
-        mLocationManager = ILocationManager.Stub.asInterface(b);
-        mProperties = properties.getProviderProperties();
-        mBinder = new Service();
-    }
-
-    public IBinder getBinder() {
-        return mBinder;
-    }
-
-    /**
-     * Used by the location provider to report new locations.
-     *
-     * @param location new Location to report
-     *
-     * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
-     */
-    public final void reportLocation(Location location) {
-        try {
-            mLocationManager.reportLocation(location, false);
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException", e);
-        } catch (Exception e) {
-            // never crash provider, might be running in a system process
-            Log.e(TAG, "Exception", e);
-        }
-    }
-
-    /**
-     * Enable the location provider.
-     * <p>The provider may initialize resources, but does
-     * not yet need to report locations.
-     */
-    public abstract void onEnable();
-
-    /**
-     * Disable the location provider.
-     * <p>The provider must release resources, and stop
-     * performing work. It may no longer report locations.
-     */
-    public abstract void onDisable();
-
-    /**
-     * Set the {@link ProviderRequest} requirements for this provider.
-     * <p>Each call to this method overrides all previous requests.
-     * <p>This method might trigger the provider to start returning
-     * locations, or to stop returning locations, depending on the
-     * parameters in the request.
-     */
-    public abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source);
-
-    /**
-     * Dump debug information.
-     */
-    public void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {
-    }
-
-    /**
-     * Returns a information on the status of this provider.
-     * <p>{@link android.location.LocationProvider#OUT_OF_SERVICE} is returned if the provider is
-     * out of service, and this is not expected to change in the near
-     * future; {@link android.location.LocationProvider#TEMPORARILY_UNAVAILABLE} is returned if
-     * the provider is temporarily unavailable but is expected to be
-     * available shortly; and {@link android.location.LocationProvider#AVAILABLE} is returned
-     * if the provider is currently available.
-     *
-     * <p>If extras is non-null, additional status information may be
-     * added to it in the form of provider-specific key/value pairs.
-     */
-    public abstract int onGetStatus(Bundle extras);
-
-    /**
-     * Returns the time at which the status was last updated. It is the
-     * responsibility of the provider to appropriately set this value using
-     * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}.
-     * there is a status update that it wishes to broadcast to all its
-     * listeners. The provider should be careful not to broadcast
-     * the same status again.
-     *
-     * @return time of last status update in millis since last reboot
-     */
-    public abstract long onGetStatusUpdateTime();
-
-    /**
-     * Implements addditional location provider specific additional commands.
-     *
-     * @param command name of the command to send to the provider.
-     * @param extras optional arguments for the command (or null).
-     * The provider may optionally fill the extras Bundle with results from the command.
-     *
-     * @return true if the command succeeds.
-     */
-    public boolean onSendExtraCommand(String command, Bundle extras) {
-        // default implementation
-        return false;
-    }
-}
diff --git a/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java b/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
deleted file mode 100644
index 41fd769..0000000
--- a/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2012 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.location.provider;
-
-import android.location.LocationRequest;
-
-/**
- * This class is an interface to LocationRequests for unbundled applications.
- *
- * <p>IMPORTANT: This class is effectively a public API for unbundled
- * applications, and must remain API stable. See README.txt in the root
- * of this package for more information.
- */
-public final class LocationRequestUnbundled {
-    /**
-     * Returned by {@link #getQuality} when requesting the most accurate locations available.
-     *
-     * <p>This may be up to 1 meter accuracy, although this is implementation dependent.
-     */
-    public static final int ACCURACY_FINE = LocationRequest.ACCURACY_FINE;
-
-    /**
-     * Returned by {@link #getQuality} when requesting "block" level accuracy.
-     *
-     * <p>Block level accuracy is considered to be about 100 meter accuracy,
-     * although this is implementation dependent. Using a coarse accuracy
-     * such as this often consumes less power.
-     */
-    public static final int ACCURACY_BLOCK = LocationRequest.ACCURACY_BLOCK;
-
-    /**
-     * Returned by {@link #getQuality} when requesting "city" level accuracy.
-     *
-     * <p>City level accuracy is considered to be about 10km accuracy,
-     * although this is implementation dependent. Using a coarse accuracy
-     * such as this often consumes less power.
-     */
-    public static final int ACCURACY_CITY = LocationRequest.ACCURACY_CITY;
-
-    /**
-     * Returned by {@link #getQuality} when requiring no direct power impact (passive locations).
-     *
-     * <p>This location request will not trigger any active location requests,
-     * but will receive locations triggered by other applications. Your application
-     * will not receive any direct power blame for location work.
-     */
-    public static final int POWER_NONE = LocationRequest.POWER_NONE;
-
-    /**
-     * Returned by {@link #getQuality} when requesting low power impact.
-     *
-     * <p>This location request will avoid high power location work where
-     * possible.
-     */
-    public static final int POWER_LOW = LocationRequest.POWER_LOW;
-
-    /**
-     * Returned by {@link #getQuality} when allowing high power consumption for location.
-     *
-     * <p>This location request will allow high power location work.
-     */
-    public static final int POWER_HIGH = LocationRequest.POWER_HIGH;
-
-    private final LocationRequest delegate;
-
-    LocationRequestUnbundled(LocationRequest delegate) {
-        this.delegate = delegate;
-    }
-
-    /**
-     * Get the desired interval of this request, in milliseconds.
-     *
-     * @return desired interval in milliseconds, inexact
-     */
-    public long getInterval() {
-        return delegate.getInterval();
-    }
-
-    /**
-     * Get the fastest interval of this request, in milliseconds.
-     *
-     * <p>The system will never provide location updates faster
-     * than the minimum of {@link #getFastestInterval} and
-     * {@link #getInterval}.
-     *
-     * @return fastest interval in milliseconds, exact
-     */
-    public long getFastestInterval() {
-        return delegate.getFastestInterval();
-    }
-
-    /**
-     * Get the quality of the request.
-     *
-     * @return an accuracy or power constant
-     */
-    public int getQuality() {
-        return delegate.getQuality();
-    }
-
-    /**
-     * Get the minimum distance between location updates, in meters.
-     *
-     * @return minimum distance between location updates in meters
-     */
-    public float getSmallestDisplacement() {
-        return delegate.getSmallestDisplacement();
-    }
-
-    @Override
-    public String toString() {
-      return delegate.toString();
-    }
-}
diff --git a/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java b/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java
deleted file mode 100644
index 9ee4df2..0000000
--- a/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2012 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.location.provider;
-
-import com.android.internal.location.ProviderProperties;
-
-/**
- * This class is an interface to Provider Properties for unbundled applications.
- *
- * <p>IMPORTANT: This class is effectively a public API for unbundled
- * applications, and must remain API stable. See README.txt in the root
- * of this package for more information.
- */
-public final class ProviderPropertiesUnbundled {
-    private final ProviderProperties mProperties;
-
-    public static ProviderPropertiesUnbundled create(boolean requiresNetwork,
-            boolean requiresSatellite, boolean requiresCell, boolean hasMonetaryCost,
-            boolean supportsAltitude, boolean supportsSpeed, boolean supportsBearing,
-            int powerRequirement, int accuracy) {
-        return new ProviderPropertiesUnbundled(new ProviderProperties(requiresNetwork,
-                requiresSatellite, requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed,
-                supportsBearing, powerRequirement, accuracy));
-    }
-
-    private ProviderPropertiesUnbundled(ProviderProperties properties) {
-        mProperties = properties;
-    }
-
-    public ProviderProperties getProviderProperties() {
-        return mProperties;
-    }
-
-    @Override
-    public String toString() {
-        return mProperties.toString();
-    }
-}
diff --git a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
deleted file mode 100644
index ad3d1df..0000000
--- a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2012 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.location.provider;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.location.LocationRequest;
-
-import com.android.internal.location.ProviderRequest;
-
-/**
- * This class is an interface to Provider Requests for unbundled applications.
- *
- * <p>IMPORTANT: This class is effectively a public API for unbundled
- * applications, and must remain API stable. See README.txt in the root
- * of this package for more information.
- */
-public final class ProviderRequestUnbundled {
-    private final ProviderRequest mRequest;
-
-    public ProviderRequestUnbundled(ProviderRequest request) {
-        mRequest = request;
-    }
-
-    public boolean getReportLocation() {
-        return mRequest.reportLocation;
-    }
-
-    public long getInterval() {
-        return mRequest.interval;
-    }
-
-    /**
-     * Never null.
-     */
-    public List<LocationRequestUnbundled> getLocationRequests() {
-        List<LocationRequestUnbundled> result = new ArrayList<LocationRequestUnbundled>(
-                mRequest.locationRequests.size());
-        for (LocationRequest r : mRequest.locationRequests) {
-          result.add(new LocationRequestUnbundled(r));
-        }
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return mRequest.toString();
-    }
-}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 4e4a1faa..772cb4c 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -30,12 +30,12 @@
  * The AudioRecord class manages the audio resources for Java applications
  * to record audio from the audio input hardware of the platform. This is
  * achieved by "pulling" (reading) the data from the AudioRecord object. The
- * application is responsible for polling the AudioRecord object in time using one of 
+ * application is responsible for polling the AudioRecord object in time using one of
  * the following three methods:  {@link #read(byte[],int, int)}, {@link #read(short[], int, int)}
- * or {@link #read(ByteBuffer, int)}. The choice of which method to use will be based 
+ * or {@link #read(ByteBuffer, int)}. The choice of which method to use will be based
  * on the audio data storage format that is the most convenient for the user of AudioRecord.
  * <p>Upon creation, an AudioRecord object initializes its associated audio buffer that it will
- * fill with the new audio data. The size of this buffer, specified during the construction, 
+ * fill with the new audio data. The size of this buffer, specified during the construction,
  * determines how long an AudioRecord can record before "over-running" data that has not
  * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to
  * the total recording buffer size.
@@ -46,20 +46,20 @@
     // Constants
     //--------------------
     /**
-     *  indicates AudioRecord state is not successfully initialized. 
+     *  indicates AudioRecord state is not successfully initialized.
      */
     public static final int STATE_UNINITIALIZED = 0;
     /**
-     *  indicates AudioRecord state is ready to be used 
+     *  indicates AudioRecord state is ready to be used
      */
     public static final int STATE_INITIALIZED   = 1;
 
     /**
-     * indicates AudioRecord recording state is not recording 
+     * indicates AudioRecord recording state is not recording
      */
     public static final int RECORDSTATE_STOPPED = 1;  // matches SL_RECORDSTATE_STOPPED
     /**
-     * indicates AudioRecord recording state is recording 
+     * indicates AudioRecord recording state is recording
      */
     public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING
 
@@ -81,15 +81,15 @@
      * Denotes a failure due to the improper use of a method.
      */
     public static final int ERROR_INVALID_OPERATION = -3;
-    
+
     private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT      = -16;
     private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK  = -17;
     private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT       = -18;
     private static final int AUDIORECORD_ERROR_SETUP_INVALIDSOURCE       = -19;
     private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED    = -20;
-    
+
     // Events:
-    // to keep in sync with frameworks/base/include/media/AudioRecord.h 
+    // to keep in sync with frameworks/base/include/media/AudioRecord.h
     /**
      * Event id denotes when record head has reached a previously set marker.
      */
@@ -98,29 +98,29 @@
      * Event id denotes when previously set update period has elapsed during recording.
      */
     private static final int NATIVE_EVENT_NEW_POS = 3;
-    
+
     private final static String TAG = "AudioRecord-Java";
 
 
     //---------------------------------------------------------
     // Used exclusively by native code
     //--------------------
-    /** 
-     * Accessed by native methods: provides access to C++ AudioRecord object 
+    /**
+     * Accessed by native methods: provides access to C++ AudioRecord object
      */
     @SuppressWarnings("unused")
     private int mNativeRecorderInJavaObj;
 
-    /** 
+    /**
      * Accessed by native methods: provides access to the callback data.
      */
     @SuppressWarnings("unused")
     private int mNativeCallbackCookie;
-    
+
 
     //---------------------------------------------------------
     // Member variables
-    //--------------------    
+    //--------------------
     /**
      * The audio data sampling rate in Hz.
      */
@@ -197,26 +197,26 @@
      * @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only
      *   rate that is guaranteed to work on all devices, but other rates such as 22050,
      *   16000, and 11025 may work on some devices.
-     * @param channelConfig describes the configuration of the audio channels. 
+     * @param channelConfig describes the configuration of the audio channels.
      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
      *   {@link AudioFormat#CHANNEL_IN_STEREO}.  {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed
      *   to work on all devices.
-     * @param audioFormat the format in which the audio data is represented. 
-     *   See {@link AudioFormat#ENCODING_PCM_16BIT} and 
+     * @param audioFormat the format in which the audio data is represented.
+     *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
      *   {@link AudioFormat#ENCODING_PCM_8BIT}
      * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
-     *   to during the recording. New audio data can be read from this buffer in smaller chunks 
+     *   to during the recording. New audio data can be read from this buffer in smaller chunks
      *   than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
      *   required buffer size for the successful creation of an AudioRecord instance. Using values
      *   smaller than getMinBufferSize() will result in an initialization failure.
      * @throws java.lang.IllegalArgumentException
      */
-    public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, 
+    public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
             int bufferSizeInBytes)
-    throws IllegalArgumentException {   
+    throws IllegalArgumentException {
         mState = STATE_UNINITIALIZED;
         mRecordingState = RECORDSTATE_STOPPED;
-        
+
         // remember which looper is associated with the AudioRecord instanciation
         if ((mInitializationLooper = Looper.myLooper()) == null) {
             mInitializationLooper = Looper.getMainLooper();
@@ -231,7 +231,7 @@
         session[0] = 0;
         //TODO: update native initialization when information about hardware init failure
         //      due to capture device already open is available.
-        int initResult = native_setup( new WeakReference<AudioRecord>(this), 
+        int initResult = native_setup( new WeakReference<AudioRecord>(this),
                 mRecordSource, mSampleRate, mChannels, mAudioFormat, mNativeBufferSizeInBytes,
                 session);
         if (initResult != SUCCESS) {
@@ -253,7 +253,7 @@
     //    mChannels is valid
     //    mAudioFormat is valid
     //    mSampleRate is valid
-    private void audioParamCheck(int audioSource, int sampleRateInHz, 
+    private void audioParamCheck(int audioSource, int sampleRateInHz,
                                  int channelConfig, int audioFormat) {
 
         //--------------
@@ -264,13 +264,13 @@
         } else {
             mRecordSource = audioSource;
         }
-        
+
         //--------------
         // sample rate
         if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
             throw (new IllegalArgumentException(sampleRateInHz
                     + "Hz is not a supported sample rate."));
-        } else { 
+        } else {
             mSampleRate = sampleRateInHz;
         }
 
@@ -309,7 +309,7 @@
             break;
         default:
             mAudioFormat = AudioFormat.ENCODING_INVALID;
-        throw (new IllegalArgumentException("Unsupported sample encoding." 
+        throw (new IllegalArgumentException("Unsupported sample encoding."
                 + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT."));
         }
     }
@@ -322,16 +322,16 @@
     // postcondition:
     //    mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
     private void audioBuffSizeCheck(int audioBufferSize) {
-        // NB: this section is only valid with PCM data. 
+        // NB: this section is only valid with PCM data.
         // To update when supporting compressed formats
-        int frameSizeInBytes = mChannelCount 
+        int frameSizeInBytes = mChannelCount
             * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
         if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
             throw (new IllegalArgumentException("Invalid audio buffer size."));
         }
 
         mNativeBufferSizeInBytes = audioBufferSize;
-    }    
+    }
 
 
 
@@ -343,7 +343,7 @@
     public void release() {
         try {
             stop();
-        } catch(IllegalStateException ise) { 
+        } catch(IllegalStateException ise) {
             // don't raise an exception, we're releasing the resources.
         }
         native_release();
@@ -354,7 +354,7 @@
     @Override
     protected void finalize() {
         native_finalize();
-    } 
+    }
 
 
     //--------------------------------------------------------------------------
@@ -366,9 +366,9 @@
     public int getSampleRate() {
         return mSampleRate;
     }
-    
+
     /**
-     * Returns the audio recording source. 
+     * Returns the audio recording source.
      * @see MediaRecorder.AudioSource
      */
     public int getAudioSource() {
@@ -384,7 +384,7 @@
     }
 
     /**
-     * Returns the configured channel configuration. 
+     * Returns the configured channel configuration.
      * See {@link AudioFormat#CHANNEL_IN_MONO}
      * and {@link AudioFormat#CHANNEL_IN_STEREO}.
      */
@@ -401,7 +401,7 @@
 
     /**
      * Returns the state of the AudioRecord instance. This is useful after the
-     * AudioRecord instance has been created to check if it was initialized 
+     * AudioRecord instance has been created to check if it was initialized
      * properly. This ensures that the appropriate hardware resources have been
      * acquired.
      * @see AudioRecord#STATE_INITIALIZED
@@ -441,22 +441,22 @@
      * should be chosen according to the expected frequency at which the AudioRecord instance
      * will be polled for new data.
      * @param sampleRateInHz the sample rate expressed in Hertz.
-     * @param channelConfig describes the configuration of the audio channels. 
+     * @param channelConfig describes the configuration of the audio channels.
      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
      *   {@link AudioFormat#CHANNEL_IN_STEREO}
-     * @param audioFormat the format in which the audio data is represented. 
+     * @param audioFormat the format in which the audio data is represented.
      *   See {@link AudioFormat#ENCODING_PCM_16BIT}.
-     * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the 
+     * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the
      *  hardware, or an invalid parameter was passed,
-     *  or {@link #ERROR} if the implementation was unable to query the hardware for its 
-     *  output properties, 
+     *  or {@link #ERROR} if the implementation was unable to query the hardware for its
+     *  output properties,
      *   or the minimum buffer size expressed in bytes.
      * @see #AudioRecord(int, int, int, int, int) for more information on valid
      *   configuration values.
      */
     static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
         int channelCount = 0;
-        switch(channelConfig) {
+        switch (channelConfig) {
         case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
         case AudioFormat.CHANNEL_IN_MONO:
         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
@@ -471,17 +471,17 @@
             loge("getMinBufferSize(): Invalid channel configuration.");
             return AudioRecord.ERROR_BAD_VALUE;
         }
-        
+
         // PCM_8BIT is not supported at the moment
         if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) {
             loge("getMinBufferSize(): Invalid audio format.");
             return AudioRecord.ERROR_BAD_VALUE;
         }
-        
+
         int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
         if (size == 0) {
             return AudioRecord.ERROR_BAD_VALUE;
-        } 
+        }
         else if (size == -1) {
             return AudioRecord.ERROR;
         }
@@ -503,7 +503,7 @@
     // Transport control methods
     //--------------------
     /**
-     * Starts recording from the AudioRecord instance. 
+     * Starts recording from the AudioRecord instance.
      * @throws IllegalStateException
      */
     public void startRecording()
@@ -573,13 +573,13 @@
      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
      *    the parameters don't resolve to valid data and indexes.
      *    The number of bytes will not exceed sizeInBytes.
-     */    
+     */
     public int read(byte[] audioData, int offsetInBytes, int sizeInBytes) {
         if (mState != STATE_INITIALIZED) {
             return ERROR_INVALID_OPERATION;
         }
-        
-        if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0) 
+
+        if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
                 || (offsetInBytes + sizeInBytes > audioData.length)) {
             return ERROR_BAD_VALUE;
         }
@@ -597,13 +597,13 @@
      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
      *    the parameters don't resolve to valid data and indexes.
      *    The number of shorts will not exceed sizeInShorts.
-     */    
+     */
     public int read(short[] audioData, int offsetInShorts, int sizeInShorts) {
         if (mState != STATE_INITIALIZED) {
             return ERROR_INVALID_OPERATION;
         }
-        
-        if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0) 
+
+        if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
                 || (offsetInShorts + sizeInShorts > audioData.length)) {
             return ERROR_BAD_VALUE;
         }
@@ -615,18 +615,20 @@
     /**
      * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
      * is not a direct buffer, this method will always return 0.
+     * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
+     * unchanged after a call to this method.
      * @param audioBuffer the direct buffer to which the recorded audio data is written.
      * @param sizeInBytes the number of requested bytes.
      * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
      *    the parameters don't resolve to valid data and indexes.
      *    The number of bytes will not exceed sizeInBytes.
-     */    
+     */
     public int read(ByteBuffer audioBuffer, int sizeInBytes) {
         if (mState != STATE_INITIALIZED) {
             return ERROR_INVALID_OPERATION;
         }
-        
+
         if ( (audioBuffer == null) || (sizeInBytes < 0) ) {
             return ERROR_BAD_VALUE;
         }
@@ -637,7 +639,7 @@
 
     //--------------------------------------------------------------------------
     // Initialization / configuration
-    //--------------------  
+    //--------------------
     /**
      * Sets the listener the AudioRecord notifies when a previously set marker is reached or
      * for each periodic record head position update.
@@ -655,12 +657,12 @@
      * @param listener
      * @param handler the Handler that will receive the event notification messages.
      */
-    public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, 
+    public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener,
                                                     Handler handler) {
         synchronized (mPositionListenerLock) {
-            
+
             mPositionListener = listener;
-            
+
             if (listener != null) {
                 if (handler != null) {
                     mEventHandler = new NativeEventHandler(this, handler.getLooper());
@@ -672,17 +674,17 @@
                 mEventHandler = null;
             }
         }
-        
+
     }
 
 
     /**
-     * Sets the marker position at which the listener is called, if set with 
-     * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or 
+     * Sets the marker position at which the listener is called, if set with
+     * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
      * @param markerInFrames marker position expressed in frames
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
-     *  {@link #ERROR_INVALID_OPERATION} 
+     *  {@link #ERROR_INVALID_OPERATION}
      */
     public int setNotificationMarkerPosition(int markerInFrames) {
         return native_set_marker_pos(markerInFrames);
@@ -691,7 +693,7 @@
 
     /**
      * Sets the period at which the listener is called, if set with
-     * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or 
+     * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
      * @param periodInFrames update period expressed in frames
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
@@ -716,7 +718,7 @@
          * by the recording head.
          */
         void onMarkerReached(AudioRecord recorder);
-        
+
         /**
          * Called on the listener to periodically notify it that the record head has reached
          * a multiple of the notification period.
@@ -729,13 +731,13 @@
     //---------------------------------------------------------
     // Inner classes
     //--------------------
-      
+
     /**
      * Helper class to handle the forwarding of native events to the appropriate listener
      * (potentially) handled in a different thread
-     */  
+     */
     private class NativeEventHandler extends Handler {
-        
+
         private final AudioRecord mAudioRecord;
 
         NativeEventHandler(AudioRecord recorder, Looper looper) {
@@ -749,8 +751,8 @@
             synchronized (mPositionListenerLock) {
                 listener = mAudioRecord.mPositionListener;
             }
-            
-            switch(msg.what) {
+
+            switch (msg.what) {
             case NATIVE_EVENT_MARKER:
                 if (listener != null) {
                     listener.onMarkerReached(mAudioRecord);
@@ -768,8 +770,8 @@
             }
         }
     };
-    
-    
+
+
     //---------------------------------------------------------
     // Java methods called from the native side
     //--------------------
@@ -781,50 +783,50 @@
         if (recorder == null) {
             return;
         }
-        
+
         if (recorder.mEventHandler != null) {
-            Message m = 
+            Message m =
                 recorder.mEventHandler.obtainMessage(what, arg1, arg2, obj);
             recorder.mEventHandler.sendMessage(m);
         }
 
     }
-    
+
 
     //---------------------------------------------------------
     // Native methods called from the Java side
     //--------------------
 
-    private native final int native_setup(Object audiorecord_this, 
+    private native final int native_setup(Object audiorecord_this,
             int recordSource, int sampleRate, int nbChannels, int audioFormat,
             int buffSizeInBytes, int[] sessionId);
 
     private native final void native_finalize();
-    
+
     private native final void native_release();
 
     private native final int native_start(int syncEvent, int sessionId);
 
     private native final void native_stop();
 
-    private native final int native_read_in_byte_array(byte[] audioData, 
+    private native final int native_read_in_byte_array(byte[] audioData,
             int offsetInBytes, int sizeInBytes);
 
-    private native final int native_read_in_short_array(short[] audioData, 
+    private native final int native_read_in_short_array(short[] audioData,
             int offsetInShorts, int sizeInShorts);
 
     private native final int native_read_in_direct_buffer(Object jBuffer, int sizeInBytes);
-    
+
     private native final int native_set_marker_pos(int marker);
     private native final int native_get_marker_pos();
-    
+
     private native final int native_set_pos_update_period(int updatePeriod);
     private native final int native_get_pos_update_period();
-    
+
     static private native final int native_get_min_buff_size(
             int sampleRateInHz, int channelCount, int audioFormat);
 
-    
+
     //---------------------------------------------------------
     // Utility methods
     //------------------
@@ -838,4 +840,3 @@
     }
 
 }
-
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 4a156db..653081d 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -438,6 +438,11 @@
 
     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
 
+    // Used when safe volume warning message display is requested by setStreamVolume(). In this
+    // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
+    // and used later when/if disableSafeMediaVolume() is called.
+    private StreamVolumeCommand mPendingVolumeCommand;
+
     ///////////////////////////////////////////////////////////////////////////
     // Construction
     ///////////////////////////////////////////////////////////////////////////
@@ -830,6 +835,11 @@
         int index;
         int oldIndex;
 
+        // reset any pending volume command
+        synchronized (mSafeMediaVolumeState) {
+            mPendingVolumeCommand = null;
+        }
+
         flags &= ~AudioManager.FLAG_FIXED_VOLUME;
         if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
                ((device & mFixedVolumeDevices) != 0)) {
@@ -857,6 +867,7 @@
             index = mStreamStates[streamType].getIndex(device,
                                                  (streamState.muteCount() != 0)  /* lastAudible */);
             oldIndex = index;
+            mVolumePanel.postDisplaySafeVolumeWarning(flags);
         } else {
             // If either the client forces allowing ringer modes for this adjustment,
             // or the stream type is one that is affected by ringer modes
@@ -928,39 +939,23 @@
         setMasterVolume(volume, flags);
     }
 
-    /** @see AudioManager#setStreamVolume(int, int, int) */
-    public void setStreamVolume(int streamType, int index, int flags) {
-        ensureValidStreamType(streamType);
-        VolumeStreamState streamState = mStreamStates[mStreamVolumeAlias[streamType]];
+    // StreamVolumeCommand contains the information needed to defer the process of
+    // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
+    class StreamVolumeCommand {
+        public final int mStreamType;
+        public final int mIndex;
+        public final int mFlags;
+        public final int mDevice;
 
-        final int device = getDeviceForStream(streamType);
-        int oldIndex;
-
-        // get last audible index if stream is muted, current index otherwise
-        oldIndex = streamState.getIndex(device,
-                                        (streamState.muteCount() != 0) /* lastAudible */);
-
-        index = rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]);
-
-        flags &= ~AudioManager.FLAG_FIXED_VOLUME;
-        if ((mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
-                ((device & mFixedVolumeDevices) != 0)) {
-            flags |= AudioManager.FLAG_FIXED_VOLUME;
-            // volume is either 0 or max allowed for fixed volume devices
-            if (index != 0) {
-                if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
-                        (device & mSafeMediaVolumeDevices) != 0) {
-                    index = mSafeMediaVolumeIndex;
-                } else {
-                    index = streamState.getMaxIndex();
-                }
-            }
+        StreamVolumeCommand(int streamType, int index, int flags, int device) {
+            mStreamType = streamType;
+            mIndex = index;
+            mFlags = flags;
+            mDevice = device;
         }
+    };
 
-        if (!checkSafeMediaVolume(mStreamVolumeAlias[streamType], index, device)) {
-            return;
-        }
-
+    private void onSetStreamVolume(int streamType, int index, int flags, int device) {
         // setting volume on master stream type also controls silent mode
         if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
                 (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
@@ -980,9 +975,53 @@
         }
 
         setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false, true);
-        // get last audible index if stream is muted, current index otherwise
-        index = mStreamStates[streamType].getIndex(device,
-                                (mStreamStates[streamType].muteCount() != 0) /* lastAudible */);
+    }
+
+    /** @see AudioManager#setStreamVolume(int, int, int) */
+    public void setStreamVolume(int streamType, int index, int flags) {
+        ensureValidStreamType(streamType);
+        VolumeStreamState streamState = mStreamStates[mStreamVolumeAlias[streamType]];
+
+        final int device = getDeviceForStream(streamType);
+        int oldIndex;
+
+        synchronized (mSafeMediaVolumeState) {
+            // reset any pending volume command
+            mPendingVolumeCommand = null;
+
+            // get last audible index if stream is muted, current index otherwise
+            oldIndex = streamState.getIndex(device,
+                                            (streamState.muteCount() != 0) /* lastAudible */);
+
+            index = rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]);
+
+            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
+            if ((mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
+                    ((device & mFixedVolumeDevices) != 0)) {
+                flags |= AudioManager.FLAG_FIXED_VOLUME;
+
+                // volume is either 0 or max allowed for fixed volume devices
+                if (index != 0) {
+                    if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
+                            (device & mSafeMediaVolumeDevices) != 0) {
+                        index = mSafeMediaVolumeIndex;
+                    } else {
+                        index = streamState.getMaxIndex();
+                    }
+                }
+            }
+
+            if (!checkSafeMediaVolume(mStreamVolumeAlias[streamType], index, device)) {
+                mVolumePanel.postDisplaySafeVolumeWarning(flags);
+                mPendingVolumeCommand = new StreamVolumeCommand(
+                                                    streamType, index, flags, device);
+            } else {
+                onSetStreamVolume(streamType, index, flags, device);
+                // get last audible index if stream is muted, current index otherwise
+                index = mStreamStates[streamType].getIndex(device,
+                                    (mStreamStates[streamType].muteCount() != 0) /* lastAudible */);
+            }
+        }
         sendVolumeUpdate(streamType, oldIndex, index, flags);
     }
 
@@ -2316,7 +2355,6 @@
                         if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
                             setSafeMediaVolumeEnabled(true);
                             mMusicActiveMs = 0;
-                            mVolumePanel.postDisplaySafeVolumeWarning();
                         }
                     }
                 }
@@ -5992,7 +6030,6 @@
                     (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
                     ((device & mSafeMediaVolumeDevices) != 0) &&
                     (index > mSafeMediaVolumeIndex)) {
-                mVolumePanel.postDisplaySafeVolumeWarning();
                 return false;
             }
             return true;
@@ -6002,6 +6039,13 @@
     public void disableSafeMediaVolume() {
         synchronized (mSafeMediaVolumeState) {
             setSafeMediaVolumeEnabled(false);
+            if (mPendingVolumeCommand != null) {
+                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
+                                  mPendingVolumeCommand.mIndex,
+                                  mPendingVolumeCommand.mFlags,
+                                  mPendingVolumeCommand.mDevice);
+                mPendingVolumeCommand = null;
+            }
         }
     }
 
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index ac9bb5d..ad05fcf 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -140,7 +140,7 @@
      */
     private static final int NATIVE_EVENT_NEW_POS = 4;
 
-    private final static String TAG = "AudioTrack-Java";
+    private final static String TAG = "android.media.AudioTrack";
 
 
     //--------------------------------------------------------------------------
@@ -307,7 +307,7 @@
     public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
             int bufferSizeInBytes, int mode, int sessionId)
     throws IllegalArgumentException {
-        mState = STATE_UNINITIALIZED;
+        // mState already == STATE_UNINITIALIZED
 
         // remember which looper is associated with the AudioTrack instantiation
         Looper looper;
@@ -450,7 +450,7 @@
     private static boolean isMultichannelConfigSupported(int channelConfig) {
         // check for unsupported channels
         if ((channelConfig & SUPPORTED_OUT_CHANNELS) != channelConfig) {
-            Log.e(TAG, "Channel configuration features unsupported channels");
+            loge("Channel configuration features unsupported channels");
             return false;
         }
         // check for unsupported multichannel combinations:
@@ -459,14 +459,14 @@
         final int frontPair =
                 AudioFormat.CHANNEL_OUT_FRONT_LEFT | AudioFormat.CHANNEL_OUT_FRONT_RIGHT;
         if ((channelConfig & frontPair) != frontPair) {
-                Log.e(TAG, "Front channels must be present in multichannel configurations");
+                loge("Front channels must be present in multichannel configurations");
                 return false;
         }
         final int backPair =
                 AudioFormat.CHANNEL_OUT_BACK_LEFT | AudioFormat.CHANNEL_OUT_BACK_RIGHT;
         if ((channelConfig & backPair) != 0) {
             if ((channelConfig & backPair) != backPair) {
-                Log.e(TAG, "Rear channels can't be used independently");
+                loge("Rear channels can't be used independently");
                 return false;
             }
         }
@@ -695,7 +695,7 @@
         }
 
         int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
-        if ((size == -1) || (size == 0)) {
+        if (size <= 0) {
             loge("getMinBufferSize(): error querying hardware");
             return ERROR;
         }
@@ -758,7 +758,7 @@
      *    {@link #ERROR_INVALID_OPERATION}
      */
     public int setStereoVolume(float leftVolume, float rightVolume) {
-        if (mState != STATE_INITIALIZED) {
+        if (mState == STATE_UNINITIALIZED) {
             return ERROR_INVALID_OPERATION;
         }
 
@@ -803,7 +803,7 @@
      *    {@link #ERROR_INVALID_OPERATION}
      */
     public int setPlaybackRate(int sampleRateInHz) {
-        if (mState != STATE_INITIALIZED) {
+        if (mState == STATE_UNINITIALIZED) {
             return ERROR_INVALID_OPERATION;
         }
         if (sampleRateInHz <= 0) {
@@ -820,7 +820,7 @@
      *  {@link #ERROR_INVALID_OPERATION}
      */
     public int setNotificationMarkerPosition(int markerInFrames) {
-        if (mState != STATE_INITIALIZED) {
+        if (mState == STATE_UNINITIALIZED) {
             return ERROR_INVALID_OPERATION;
         }
         return native_set_marker_pos(markerInFrames);
@@ -833,7 +833,7 @@
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
      */
     public int setPositionNotificationPeriod(int periodInFrames) {
-        if (mState != STATE_INITIALIZED) {
+        if (mState == STATE_UNINITIALIZED) {
             return ERROR_INVALID_OPERATION;
         }
         return native_set_pos_update_period(periodInFrames);
@@ -841,23 +841,26 @@
 
 
     /**
-     * Sets the playback head position. The track must be stopped for the position to be changed.
+     * Sets the playback head position.
+     * The track must be stopped or paused for the position to be changed,
+     * and must use the {@link #MODE_STATIC} mode.
      * @param positionInFrames playback head position expressed in frames
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
      *    {@link #ERROR_INVALID_OPERATION}
      */
     public int setPlaybackHeadPosition(int positionInFrames) {
-        synchronized(mPlayStateLock) {
-            if ((mPlayState == PLAYSTATE_STOPPED) || (mPlayState == PLAYSTATE_PAUSED)) {
-                return native_set_position(positionInFrames);
-            } else {
-                return ERROR_INVALID_OPERATION;
-            }
+        if (mDataLoadMode == MODE_STREAM || mState != STATE_INITIALIZED ||
+                getPlayState() == PLAYSTATE_PLAYING) {
+            return ERROR_INVALID_OPERATION;
         }
+        return native_set_position(positionInFrames);
     }
 
     /**
      * Sets the loop points and the loop count. The loop can be infinite.
+     * Similarly to setPlaybackHeadPosition,
+     * the track must be stopped or paused for the position to be changed,
+     * and must use the {@link #MODE_STATIC} mode.
      * @param startInFrames loop start marker expressed in frames
      * @param endInFrames loop end marker expressed in frames
      * @param loopCount the number of times the loop is looped.
@@ -866,7 +869,8 @@
      *    {@link #ERROR_INVALID_OPERATION}
      */
     public int setLoopPoints(int startInFrames, int endInFrames, int loopCount) {
-        if (mDataLoadMode == MODE_STREAM) {
+        if (mDataLoadMode == MODE_STREAM || mState != STATE_INITIALIZED ||
+                getPlayState() == PLAYSTATE_PLAYING) {
             return ERROR_INVALID_OPERATION;
         }
         return native_set_loop(startInFrames, endInFrames, loopCount);
@@ -978,22 +982,27 @@
      */
 
     public int write(byte[] audioData, int offsetInBytes, int sizeInBytes) {
-        if ((mDataLoadMode == MODE_STATIC)
-                && (mState == STATE_NO_STATIC_DATA)
-                && (sizeInBytes > 0)) {
-            mState = STATE_INITIALIZED;
-        }
 
-        if (mState != STATE_INITIALIZED) {
+        if (mState == STATE_UNINITIALIZED) {
             return ERROR_INVALID_OPERATION;
         }
 
         if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
+                || (offsetInBytes + sizeInBytes < 0)    // detect integer overflow
                 || (offsetInBytes + sizeInBytes > audioData.length)) {
             return ERROR_BAD_VALUE;
         }
 
-        return native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat);
+        int ret = native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat);
+
+        if ((mDataLoadMode == MODE_STATIC)
+                && (mState == STATE_NO_STATIC_DATA)
+                && (ret > 0)) {
+            // benign race with respect to other APIs that read mState
+            mState = STATE_INITIALIZED;
+        }
+
+        return ret;
     }
 
 
@@ -1014,22 +1023,27 @@
      */
 
     public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {
-        if ((mDataLoadMode == MODE_STATIC)
-                && (mState == STATE_NO_STATIC_DATA)
-                && (sizeInShorts > 0)) {
-            mState = STATE_INITIALIZED;
-        }
 
-        if (mState != STATE_INITIALIZED) {
+        if (mState == STATE_UNINITIALIZED) {
             return ERROR_INVALID_OPERATION;
         }
 
         if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
+                || (offsetInShorts + sizeInShorts < 0)  // detect integer overflow
                 || (offsetInShorts + sizeInShorts > audioData.length)) {
             return ERROR_BAD_VALUE;
         }
 
-        return native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat);
+        int ret = native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat);
+
+        if ((mDataLoadMode == MODE_STATIC)
+                && (mState == STATE_NO_STATIC_DATA)
+                && (ret > 0)) {
+            // benign race with respect to other APIs that read mState
+            mState = STATE_INITIALIZED;
+        }
+
+        return ret;
     }
 
 
@@ -1041,7 +1055,7 @@
      *  {@link #ERROR_INVALID_OPERATION}
      */
     public int reloadStaticData() {
-        if (mDataLoadMode == MODE_STREAM) {
+        if (mDataLoadMode == MODE_STREAM || mState != STATE_INITIALIZED) {
             return ERROR_INVALID_OPERATION;
         }
         return native_reload_static();
@@ -1069,7 +1083,7 @@
      *    {@link #ERROR_INVALID_OPERATION}, {@link #ERROR_BAD_VALUE}
      */
     public int attachAuxEffect(int effectId) {
-        if (mState != STATE_INITIALIZED) {
+        if (mState == STATE_UNINITIALIZED) {
             return ERROR_INVALID_OPERATION;
         }
         return native_attachAuxEffect(effectId);
@@ -1091,7 +1105,7 @@
      *    {@link #ERROR_INVALID_OPERATION}
      */
     public int setAuxEffectSendLevel(float level) {
-        if (mState != STATE_INITIALIZED) {
+        if (mState == STATE_UNINITIALIZED) {
             return ERROR_INVALID_OPERATION;
         }
         // clamp the level
@@ -1174,8 +1188,7 @@
                             }
                             break;
                         default:
-                            Log.e(TAG, "[ android.media.AudioTrack.NativeEventHandler ] " +
-                                    "Unknown event type: " + msg.what);
+                            loge("Unknown native event type: " + msg.what);
                             break;
                         }
                     }
@@ -1262,8 +1275,6 @@
     static private native final int native_get_min_buff_size(
             int sampleRateInHz, int channelConfig, int audioFormat);
 
-    private native final int native_get_session_id();
-
     private native final int native_attachAuxEffect(int effectId);
     private native final void native_setAuxEffectSendLevel(float level);
 
@@ -1272,11 +1283,11 @@
     //------------------
 
     private static void logd(String msg) {
-        Log.d(TAG, "[ android.media.AudioTrack ] " + msg);
+        Log.d(TAG, msg);
     }
 
     private static void loge(String msg) {
-        Log.e(TAG, "[ android.media.AudioTrack ] " + msg);
+        Log.e(TAG, msg);
     }
 
 }
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 94e2286..82627c0 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -43,8 +43,6 @@
     -->
     <string name="def_location_providers_allowed" translatable="false">gps</string>
     <bool name="assisted_gps_enabled">true</bool>
-    <!--  0 == mobile, 1 == wifi. -->
-    <integer name="def_network_preference">1</integer>
     <bool name="def_netstats_enabled">true</bool>
     <bool name="def_usb_mass_storage_enabled">true</bool>
     <bool name="def_wifi_on">false</bool>
@@ -75,6 +73,8 @@
     <integer name="def_lockscreen_sounds_enabled">1</integer>
     <string name="def_lock_sound" translatable="false">/system/media/audio/ui/Lock.ogg</string>
     <string name="def_unlock_sound" translatable="false">/system/media/audio/ui/Unlock.ogg</string>
+    <string name="def_wireless_charging_started_sound" translatable="false">/system/media/audio/ui/WirelessChargingStarted.ogg</string>
+
     <bool name="def_lockscreen_disabled">false</bool>
     <bool name="def_device_provisioned">false</bool>
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 4e5fc37..b2f1d3f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -71,7 +71,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 94;
+    private static final int DATABASE_VERSION = 95;
 
     private Context mContext;
     private int mUserHandle;
@@ -1505,6 +1505,23 @@
             upgradeVersion = 94;
         }
 
+        if (upgradeVersion == 94) {
+            // Add wireless charging started sound setting
+            db.beginTransaction();
+            SQLiteStatement stmt = null;
+            try {
+                stmt = db.compileStatement("INSERT OR REPLACE INTO global(name,value)"
+                        + " VALUES(?,?);");
+                loadStringSetting(stmt, Settings.Global.WIRELESS_CHARGING_STARTED_SOUND,
+                        R.string.def_wireless_charging_started_sound);
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+                if (stmt != null) stmt.close();
+            }
+            upgradeVersion = 95;
+        }
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
@@ -2161,9 +2178,6 @@
             loadBooleanSetting(stmt, Settings.Global.INSTALL_NON_MARKET_APPS,
                     R.bool.def_install_non_market_apps);
 
-            loadIntegerSetting(stmt, Settings.Global.NETWORK_PREFERENCE,
-                    R.integer.def_network_preference);
-
             loadBooleanSetting(stmt, Settings.Global.USB_MASS_STORAGE_ENABLED,
                     R.bool.def_usb_mass_storage_enabled);
 
@@ -2191,6 +2205,8 @@
                     R.string.def_car_dock_sound);
             loadStringSetting(stmt, Settings.Global.CAR_UNDOCK_SOUND,
                     R.string.def_car_undock_sound);
+            loadStringSetting(stmt, Settings.Global.WIRELESS_CHARGING_STARTED_SOUND,
+                    R.string.def_wireless_charging_started_sound);
 
             loadSetting(stmt, Settings.Global.SET_INSTALL_LOCATION, 0);
             loadSetting(stmt, Settings.Global.DEFAULT_INSTALL_LOCATION,
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index c454bb1..fff1aa0 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -157,14 +157,14 @@
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm ustawiony na <xliff:g id="TIME">%s</xliff:g>."</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Wyłączono transmisję danych 2G/3G"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Wyłączono transmisję danych 4G"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Wyłączono komórkową transmisję danych"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Transmisja danych została wyłączona"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Wyłączono transmisję danych"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Osiągnięto określony limit wykorzystania transmisji danych."\n\n"Jeśli ponownie włączysz przesyłanie danych, operator może naliczyć opłaty."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Ustawiony limit transmisji danych został osiągnięty."\n\n"Jeśli ponownie włączysz przesyłanie danych, operator może naliczyć dodatkowe opłaty."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Włącz transmisję danych"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Brak internetu"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: połączono"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Wyszukiwanie sygnału GPS"</string>
-    <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokalizacja ustawiona według GPS"</string>
+    <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokalizacja z GPSa"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Usuń wszystkie powiadomienia."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"O aplikacji"</string>
     <string name="close_universe" msgid="3736513750241754348">"Zamknij"</string>
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
index 13d8019..7a1e66c 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -66,7 +66,7 @@
                     getString(R.string.prompt, app.loadLabel(pm)));
             ((CompoundButton) view.findViewById(R.id.check)).setOnCheckedChangeListener(this);
 
-            mAlertParams.mIconId = android.R.drawable.ic_dialog_alert;
+            mAlertParams.mIconAttrId = android.R.attr.alertDialogIcon;
             mAlertParams.mTitle = getText(android.R.string.dialog_alert_title);
             mAlertParams.mPositiveButtonText = getText(android.R.string.ok);
             mAlertParams.mPositiveButtonListener = this;
diff --git a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
index f436cb4..305ee37 100644
--- a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
+++ b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
@@ -27,10 +27,10 @@
 import android.test.ServiceTestCase;
 import android.util.Log;
 
-import com.android.internal.telephony.IccUtils;
 import com.android.internal.telephony.IWapPushManager;
 import com.android.internal.telephony.WapPushManagerParams;
 import com.android.internal.telephony.WspTypeDecoder;
+import com.android.internal.telephony.uicc.IccUtils;
 import com.android.internal.util.HexDump;
 import com.android.smspush.WapPushManager;
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 801b627..b05d111 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -80,7 +80,6 @@
     private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView
     private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
     private int mAppWidgetToShow;
-    private int mPreviousWidgetPage = -1;
 
     private boolean mCheckAppWidgetConsistencyOnBootCompleted = false;
     private boolean mCleanupAppWidgetsOnBootCompleted = false;
@@ -288,11 +287,6 @@
 
         showPrimarySecurityScreen(false);
         updateSecurityViews();
-
-        // Make sure at least this view is focusable in case nothing below it is. Otherwise,
-        // requestFocus() on this view will fail and allow events, such as volume keys, to be
-        // handled by the fallback handler.  See bug 7546960 for details.
-        setFocusableInTouchMode(true);
     }
 
     private boolean shouldEnableAddWidget() {
@@ -913,7 +907,6 @@
 
     public void clearAppWidgetToShow() {
         mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
-        mPreviousWidgetPage = -1;
     }
 
     @Override
@@ -1301,22 +1294,10 @@
            showAppropriateWidgetPage();
         }
     };
-    Runnable mOnRestoreUpdatePageRunnable = new Runnable() {
-        @Override
-        public void run() {
-            mSwitchPageRunnable.run();
-
-            // We need to update the alpha's of the hints and content after setting the current page
-            mViewStateManager.showUsabilityHints();
-        };
-    };
-
 
     static class SavedState extends BaseSavedState {
         int transportState;
         int appWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
-        // Note the appWidgetContainerPage is only used if the appWidgetToShow is invalid
-        int appWidgetContainerPage = -1;
 
         SavedState(Parcelable superState) {
             super(superState);
@@ -1326,7 +1307,6 @@
             super(in);
             this.transportState = in.readInt();
             this.appWidgetToShow = in.readInt();
-            this.appWidgetContainerPage = in.readInt();
         }
 
         @Override
@@ -1334,7 +1314,6 @@
             super.writeToParcel(out, flags);
             out.writeInt(this.transportState);
             out.writeInt(this.appWidgetToShow);
-            out.writeInt(this.appWidgetContainerPage);
         }
 
         public static final Parcelable.Creator<SavedState> CREATOR
@@ -1356,7 +1335,6 @@
         SavedState ss = new SavedState(superState);
         ss.transportState = mViewStateManager.getTransportState();
         ss.appWidgetToShow = mAppWidgetToShow;
-        ss.appWidgetContainerPage = mAppWidgetContainer.getCurrentPage();
         return ss;
     }
 
@@ -1371,8 +1349,7 @@
         super.onRestoreInstanceState(ss.getSuperState());
         mViewStateManager.setTransportState(ss.transportState);
         mAppWidgetToShow = ss.appWidgetToShow;
-        mPreviousWidgetPage = ss.appWidgetContainerPage;
-        post(mOnRestoreUpdatePageRunnable);
+        post(mSwitchPageRunnable);
     }
 
     @Override
@@ -1429,9 +1406,6 @@
             }
             mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
         }
-        if (mPreviousWidgetPage > -1) {
-            return mPreviousWidgetPage;
-        }
         // if music playing, show transport
         if (isMusicPlaying) {
             if (DEBUG) Log.d(TAG, "Music playing, show transport");
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
index 0a69d57..ff136b1 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
@@ -146,11 +146,18 @@
 
         @Override
         public boolean dispatchKeyEvent(KeyEvent event) {
-            if (event.getAction() == KeyEvent.ACTION_DOWN && mKeyguardView != null) {
-                int keyCode = event.getKeyCode();
-                if (keyCode == KeyEvent.KEYCODE_BACK && mKeyguardView.handleBackKey()) {
-                    return true;
-                } else if (keyCode == KeyEvent.KEYCODE_MENU && mKeyguardView.handleMenuKey()) {
+            if (mKeyguardView != null) {
+                // Always process back and menu keys, regardless of focus
+                if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                    int keyCode = event.getKeyCode();
+                    if (keyCode == KeyEvent.KEYCODE_BACK && mKeyguardView.handleBackKey()) {
+                        return true;
+                    } else if (keyCode == KeyEvent.KEYCODE_MENU && mKeyguardView.handleMenuKey()) {
+                        return true;
+                    }
+                }
+                // Always process media keys, regardless of focus
+                if (mKeyguardView.dispatchKeyEvent(event)) {
                     return true;
                 }
             }
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 4c22ae8..8c5ff04 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -412,8 +412,6 @@
                 ConnectivityManager.MAX_NETWORK_TYPE+1];
         mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
 
-        mNetworkPreference = getPersistedNetworkPreference();
-
         mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
         mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
 
@@ -495,6 +493,21 @@
             }
         }
 
+        // Update mNetworkPreference according to user mannually first then overlay config.xml
+        mNetworkPreference = getPersistedNetworkPreference();
+        if (mNetworkPreference == -1) {
+            for (int n : mPriorityList) {
+                if (mNetConfigs[n].isDefault() && ConnectivityManager.isNetworkTypeValid(n)) {
+                    mNetworkPreference = n;
+                    break;
+                }
+            }
+            if (mNetworkPreference == -1) {
+                throw new IllegalStateException(
+                        "You should set at least one default Network in config.xml!");
+            }
+        }
+
         mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
         for (int i : mPriorityList) {
             mNetRequestersPids[i] = new ArrayList();
@@ -726,11 +739,8 @@
 
         final int networkPrefSetting = Settings.Global
                 .getInt(cr, Settings.Global.NETWORK_PREFERENCE, -1);
-        if (networkPrefSetting != -1) {
-            return networkPrefSetting;
-        }
 
-        return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
+        return networkPrefSetting;
     }
 
     /**
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 88f5533..91ac1de 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -602,12 +602,12 @@
         mHandler = new Handler(this);
         mIWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService(Context.WINDOW_SERVICE));
-        mCaller = new HandlerCaller(context, new HandlerCaller.Callback() {
+        mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
             @Override
             public void executeMessage(Message msg) {
                 handleMessage(msg);
             }
-        });
+        }, true /*asyncHandler*/);
         mWindowManagerService = windowManager;
         mHardKeyboardListener = new HardKeyboardListener();
 
diff --git a/core/java/com/android/internal/widget/LockSettingsService.java b/services/java/com/android/server/LockSettingsService.java
similarity index 98%
rename from core/java/com/android/internal/widget/LockSettingsService.java
rename to services/java/com/android/server/LockSettingsService.java
index 4ecbd16..e20a21f 100644
--- a/core/java/com/android/internal/widget/LockSettingsService.java
+++ b/services/java/com/android/server/LockSettingsService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.widget;
+package com.android.server;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -32,6 +32,9 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
+import com.android.internal.widget.ILockSettings;
+import com.android.internal.widget.LockPatternUtils;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/java/com/android/server/NativeDaemonEvent.java
index f11ae1d..2095152 100644
--- a/services/java/com/android/server/NativeDaemonEvent.java
+++ b/services/java/com/android/server/NativeDaemonEvent.java
@@ -223,8 +223,8 @@
                 current++;  // skip the trailing quote
             }
             // unescape stuff within the word
-            word.replace("\\\\", "\\");
-            word.replace("\\\"", "\"");
+            word = word.replace("\\\\", "\\");
+            word = word.replace("\\\"", "\"");
 
             if (DEBUG_ROUTINE) Slog.e(LOGTAG, "found '" + word + "'");
             parsed.add(word);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 55885e6..a7b502a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -16,12 +16,10 @@
 
 package com.android.server;
 
-import android.accounts.AccountManagerService;
 import android.app.ActivityManagerNative;
 import android.bluetooth.BluetoothAdapter;
 import android.content.ComponentName;
 import android.content.ContentResolver;
-import android.content.ContentService;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
@@ -32,13 +30,11 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.RemoteException;
-import android.os.SchedulingPolicyService;
 import android.os.ServiceManager;
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.server.search.SearchManagerService;
 import android.service.dreams.DreamService;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
@@ -48,20 +44,23 @@
 
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.SamplingProfilerIntegration;
-import com.android.internal.widget.LockSettingsService;
 import com.android.server.accessibility.AccessibilityManagerService;
+import com.android.server.accounts.AccountManagerService;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.BatteryStatsService;
+import com.android.server.content.ContentService;
 import com.android.server.display.DisplayManagerService;
 import com.android.server.dreams.DreamManagerService;
 import com.android.server.input.InputManagerService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
+import com.android.server.os.SchedulingPolicyService;
 import com.android.server.pm.Installer;
 import com.android.server.pm.PackageManagerService;
 import com.android.server.pm.UserManagerService;
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
+import com.android.server.search.SearchManagerService;
 import com.android.server.usb.UsbService;
 import com.android.server.wm.WindowManagerService;
 
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 3e2540d..1d0e3a3 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1144,7 +1144,7 @@
                 return;
             }
             mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext)
-                .setIcon(android.R.drawable.ic_dialog_alert)
+                .setIconAttribute(android.R.attr.alertDialogIcon)
                 .setPositiveButton(android.R.string.ok, new OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
diff --git a/core/java/android/accounts/AccountAuthenticatorCache.java b/services/java/com/android/server/accounts/AccountAuthenticatorCache.java
similarity index 95%
rename from core/java/android/accounts/AccountAuthenticatorCache.java
rename to services/java/com/android/server/accounts/AccountAuthenticatorCache.java
index f937cde..7552368 100644
--- a/core/java/android/accounts/AccountAuthenticatorCache.java
+++ b/services/java/com/android/server/accounts/AccountAuthenticatorCache.java
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
-package android.accounts;
+package com.android.server.accounts;
 
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorDescription;
+import android.accounts.IAccountAuthenticator;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.RegisteredServicesCache;
diff --git a/core/java/android/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java
similarity index 99%
rename from core/java/android/accounts/AccountManagerService.java
rename to services/java/com/android/server/accounts/AccountManagerService.java
index 2b1a2b2..150df9e 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/services/java/com/android/server/accounts/AccountManagerService.java
@@ -14,9 +14,19 @@
  * limitations under the License.
  */
 
-package android.accounts;
+package com.android.server.accounts;
 
 import android.Manifest;
+import android.accounts.Account;
+import android.accounts.AccountAndUser;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorDescription;
+import android.accounts.GrantCredentialsPermissionActivity;
+import android.accounts.IAccountAuthenticator;
+import android.accounts.IAccountAuthenticatorResponse;
+import android.accounts.IAccountManager;
+import android.accounts.IAccountManagerResponse;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.Notification;
diff --git a/core/java/android/accounts/IAccountAuthenticatorCache.java b/services/java/com/android/server/accounts/IAccountAuthenticatorCache.java
similarity index 96%
rename from core/java/android/accounts/IAccountAuthenticatorCache.java
rename to services/java/com/android/server/accounts/IAccountAuthenticatorCache.java
index 06c2106..bb09687 100644
--- a/core/java/android/accounts/IAccountAuthenticatorCache.java
+++ b/services/java/com/android/server/accounts/IAccountAuthenticatorCache.java
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package android.accounts;
+package com.android.server.accounts;
 
+import android.accounts.AuthenticatorDescription;
 import android.content.pm.RegisteredServicesCache;
 import android.content.pm.RegisteredServicesCacheListener;
 import android.os.Handler;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 60b208d..8728976 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -115,6 +115,7 @@
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UpdateLock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.format.Time;
@@ -191,6 +192,7 @@
     static final boolean DEBUG_POWER = localLOGV || false;
     static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
     static final boolean DEBUG_MU = localLOGV || false;
+    static final boolean DEBUG_IMMERSIVE = localLOGV || false;
     static final boolean VALIDATE_TOKENS = false;
     static final boolean SHOW_ACTIVITY_START_TIME = true;
     
@@ -827,6 +829,12 @@
     long mLastWriteTime = 0;
 
     /**
+     * Used to retain an update lock when the foreground activity is in
+     * immersive mode.
+     */
+    final UpdateLock mUpdateLock = new UpdateLock("immersive");
+
+    /**
      * Set to true after the system has finished booting.
      */
     boolean mBooted = false;
@@ -895,6 +903,7 @@
     static final int REPORT_USER_SWITCH_MSG = 34;
     static final int CONTINUE_USER_SWITCH_MSG = 35;
     static final int USER_SWITCH_TIMEOUT_MSG = 36;
+    static final int IMMERSIVE_MODE_LOCK_MSG = 37;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1356,6 +1365,21 @@
                 timeoutUserSwitch((UserStartedState)msg.obj, msg.arg1, msg.arg2);
                 break;
             }
+            case IMMERSIVE_MODE_LOCK_MSG: {
+                final boolean nextState = (msg.arg1 != 0);
+                if (mUpdateLock.isHeld() != nextState) {
+                    if (DEBUG_IMMERSIVE) {
+                        final ActivityRecord r = (ActivityRecord) msg.obj;
+                        Slog.d(TAG, "Applying new update lock state '" + nextState + "' for " + r);
+                    }
+                    if (nextState) {
+                        mUpdateLock.acquire();
+                    } else {
+                        mUpdateLock.release();
+                    }
+                }
+                break;
+            }
             }
         }
     };
@@ -1824,9 +1848,20 @@
             if (r != null) {
                 mWindowManager.setFocusedApp(r.appToken, true);
             }
+            applyUpdateLockStateLocked(r);
         }
     }
 
+    final void applyUpdateLockStateLocked(ActivityRecord r) {
+        // Modifications to the UpdateLock state are done on our handler, outside
+        // the activity manager's locks.  The new state is determined based on the
+        // state *now* of the relevant activity record.  The object is passed to
+        // the handler solely for logging detail, not to be consulted/modified.
+        final boolean nextState = r != null && r.immersive;
+        mHandler.sendMessage(
+                mHandler.obtainMessage(IMMERSIVE_MODE_LOCK_MSG, (nextState) ? 1 : 0, 0, r));
+    }
+
     private final void updateLruProcessInternalLocked(ProcessRecord app, int bestPos) {
         // put it on the LRU to keep track of when it should be exited.
         int lrui = mLruProcesses.indexOf(app);
@@ -7423,11 +7458,19 @@
 
     public void setImmersive(IBinder token, boolean immersive) {
         synchronized(this) {
-            ActivityRecord r = mMainStack.isInStackLocked(token);
+            final ActivityRecord r = mMainStack.isInStackLocked(token);
             if (r == null) {
                 throw new IllegalArgumentException();
             }
             r.immersive = immersive;
+
+            // update associated state if we're frontmost
+            if (r == mFocusedActivity) {
+                if (DEBUG_IMMERSIVE) {
+                    Slog.d(TAG, "Frontmost changed immersion: "+ r);
+                }
+                applyUpdateLockStateLocked(r);
+            }
         }
     }
 
diff --git a/core/java/android/content/ContentService.java b/services/java/com/android/server/content/ContentService.java
similarity index 98%
rename from core/java/android/content/ContentService.java
rename to services/java/com/android/server/content/ContentService.java
index 8bac888..3b92338 100644
--- a/core/java/android/content/ContentService.java
+++ b/services/java/com/android/server/content/ContentService.java
@@ -14,10 +14,19 @@
  * limitations under the License.
  */
 
-package android.content;
+package com.android.server.content;
 
+import android.Manifest;
 import android.accounts.Account;
 import android.app.ActivityManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.IContentService;
+import android.content.ISyncStatusObserver;
+import android.content.PeriodicSync;
+import android.content.SyncAdapterType;
+import android.content.SyncInfo;
+import android.content.SyncStatusInfo;
 import android.database.IContentObserver;
 import android.database.sqlite.SQLiteException;
 import android.net.Uri;
@@ -30,7 +39,6 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseIntArray;
-import android.Manifest;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/core/java/android/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java
similarity index 98%
rename from core/java/android/content/SyncManager.java
rename to services/java/com/android/server/content/SyncManager.java
index e428968..cd66cf2 100644
--- a/core/java/android/content/SyncManager.java
+++ b/services/java/com/android/server/content/SyncManager.java
@@ -14,18 +14,32 @@
  * limitations under the License.
  */
 
-package android.content;
+package com.android.server.content;
 
 import android.accounts.Account;
 import android.accounts.AccountAndUser;
 import android.accounts.AccountManager;
-import android.accounts.AccountManagerService;
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.content.SyncStorageEngine.OnSyncRequestListener;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ISyncAdapter;
+import android.content.ISyncContext;
+import android.content.ISyncStatusObserver;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.SyncActivityTooManyDeletes;
+import android.content.SyncAdapterType;
+import android.content.SyncAdaptersCache;
+import android.content.SyncInfo;
+import android.content.SyncResult;
+import android.content.SyncStatusInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
@@ -55,11 +69,12 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Pair;
-import android.util.Slog;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.accounts.AccountManagerService;
+import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 import com.google.android.collect.Sets;
diff --git a/core/java/android/content/SyncOperation.java b/services/java/com/android/server/content/SyncOperation.java
similarity index 98%
rename from core/java/android/content/SyncOperation.java
rename to services/java/com/android/server/content/SyncOperation.java
index a4c2cff..eaad982 100644
--- a/core/java/android/content/SyncOperation.java
+++ b/services/java/com/android/server/content/SyncOperation.java
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-package android.content;
+package com.android.server.content;
 
 import android.accounts.Account;
 import android.content.pm.PackageManager;
+import android.content.ContentResolver;
 import android.os.Bundle;
 import android.os.SystemClock;
 
diff --git a/core/java/android/content/SyncQueue.java b/services/java/com/android/server/content/SyncQueue.java
similarity index 98%
rename from core/java/android/content/SyncQueue.java
rename to services/java/com/android/server/content/SyncQueue.java
index c09703c..951e92c 100644
--- a/core/java/android/content/SyncQueue.java
+++ b/services/java/com/android/server/content/SyncQueue.java
@@ -14,14 +14,15 @@
  * limitations under the License.
  */
 
-package android.content;
+package com.android.server.content;
 
 import android.accounts.Account;
 import android.content.pm.PackageManager;
 import android.content.pm.RegisteredServicesCache;
+import android.content.SyncAdapterType;
+import android.content.SyncAdaptersCache;
 import android.content.pm.RegisteredServicesCache.ServiceInfo;
 import android.os.SystemClock;
-import android.os.UserHandle;
 import android.text.format.DateUtils;
 import android.util.Log;
 import android.util.Pair;
diff --git a/core/java/android/content/SyncStorageEngine.java b/services/java/com/android/server/content/SyncStorageEngine.java
similarity index 98%
rename from core/java/android/content/SyncStorageEngine.java
rename to services/java/com/android/server/content/SyncStorageEngine.java
index 8d9b8e0..5b8d26f 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/services/java/com/android/server/content/SyncStorageEngine.java
@@ -14,18 +14,16 @@
  * limitations under the License.
  */
 
-package android.content;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastXmlSerializer;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
+package com.android.server.content;
 
 import android.accounts.Account;
 import android.accounts.AccountAndUser;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ISyncStatusObserver;
+import android.content.PeriodicSync;
+import android.content.SyncInfo;
+import android.content.SyncStatusInfo;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteException;
@@ -39,9 +37,17 @@
 import android.os.RemoteException;
 import android.util.AtomicFile;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 import android.util.Xml;
-import android.util.Pair;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -50,9 +56,9 @@
 import java.util.Calendar;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Random;
 import java.util.TimeZone;
-import java.util.List;
 
 /**
  * Singleton that tracks the sync data and overall sync
@@ -107,9 +113,6 @@
 
     public static final long NOT_IN_BACKOFF_MODE = -1;
 
-    public static final Intent SYNC_CONNECTION_SETTING_CHANGED_INTENT =
-            new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
-
     // TODO: i18n -- grab these out of resources.
     /** String names for the sync source types. */
     public static final String[] SOURCES = { "SERVER",
@@ -710,7 +713,7 @@
                     for (int i = 0, N = authority.periodicSyncs.size(); i < N; i++) {
                         Pair<Bundle, Long> syncInfo = authority.periodicSyncs.get(i);
                         final Bundle existingExtras = syncInfo.first;
-                        if (equals(existingExtras, extras)) {
+                        if (PeriodicSync.syncExtrasEquals(existingExtras, extras)) {
                             if (syncInfo.second == period) {
                                 return;
                             }
@@ -734,7 +737,7 @@
                     int i = 0;
                     while (iterator.hasNext()) {
                         Pair<Bundle, Long> syncInfo = iterator.next();
-                        if (equals(syncInfo.first, extras)) {
+                        if (PeriodicSync.syncExtrasEquals(syncInfo.first, extras)) {
                             iterator.remove();
                             changed = true;
                             // if we removed an entry from the periodicSyncs array also
@@ -800,7 +803,7 @@
                     new Bundle());
         }
         reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
-        mContext.sendBroadcast(SYNC_CONNECTION_SETTING_CHANGED_INTENT);
+        mContext.sendBroadcast(ContentResolver.ACTION_SYNC_CONN_STATUS_CHANGED);
     }
 
     public boolean getMasterSyncAutomatically(int userId) {
@@ -1095,24 +1098,6 @@
         return id;
     }
 
-    public static boolean equals(Bundle b1, Bundle b2) {
-        if (b1.size() != b2.size()) {
-            return false;
-        }
-        if (b1.isEmpty()) {
-            return true;
-        }
-        for (String key : b1.keySet()) {
-            if (!b2.containsKey(key)) {
-                return false;
-            }
-            if (!b1.get(key).equals(b2.get(key))) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     public void stopSyncEvent(long historyId, long elapsedTime, String resultMessage,
             long downstreamActivity, long upstreamActivity) {
         synchronized (mAuthorities) {
diff --git a/services/java/com/android/server/dreams/DreamManagerService.java b/services/java/com/android/server/dreams/DreamManagerService.java
index 7e4a554..dd0b5b3 100644
--- a/services/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/java/com/android/server/dreams/DreamManagerService.java
@@ -25,6 +25,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -38,6 +39,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
 
 import libcore.util.Objects;
 
@@ -279,7 +282,37 @@
         String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),
                 Settings.Secure.SCREENSAVER_COMPONENTS,
                 userId);
-        return names == null ? null : componentsFromString(names);
+        ComponentName[] components = componentsFromString(names);
+
+        // first, ensure components point to valid services
+        List<ComponentName> validComponents = new ArrayList<ComponentName>();
+        if (components != null) {
+            for (ComponentName component : components) {
+                if (serviceExists(component)) {
+                    validComponents.add(component);
+                } else {
+                    Slog.w(TAG, "Dream " + component + " does not exist");
+                }
+            }
+        }
+
+        // fallback to the default dream component if necessary
+        if (validComponents.isEmpty()) {
+            ComponentName defaultDream = getDefaultDreamComponent();
+            if (defaultDream != null) {
+                Slog.w(TAG, "Falling back to default dream " + defaultDream);
+                validComponents.add(defaultDream);
+            }
+        }
+        return validComponents.toArray(new ComponentName[validComponents.size()]);
+    }
+
+    private boolean serviceExists(ComponentName name) {
+        try {
+            return name != null && mContext.getPackageManager().getServiceInfo(name, 0) != null;
+        } catch (NameNotFoundException e) {
+            return false;
+        }
     }
 
     private void startDreamLocked(final ComponentName name,
diff --git a/core/java/android/os/SchedulingPolicyService.java b/services/java/com/android/server/os/SchedulingPolicyService.java
similarity index 96%
rename from core/java/android/os/SchedulingPolicyService.java
rename to services/java/com/android/server/os/SchedulingPolicyService.java
index a3fede6..c0123bf 100644
--- a/core/java/android/os/SchedulingPolicyService.java
+++ b/services/java/com/android/server/os/SchedulingPolicyService.java
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-package android.os;
+package com.android.server.os;
 
-import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
+import android.os.ISchedulingPolicyService;
 import android.os.Process;
-import android.util.Log;
 
 /**
  * The implementation of the scheduling policy service interface.
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index fd649a1..2238f17 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -6353,6 +6353,18 @@
                                 pkgLite = mContainerService.getMinimalPackageInfo(packageFilePath,
                                         flags, lowThreshold);
                             }
+                            /*
+                             * The cache free must have deleted the file we
+                             * downloaded to install.
+                             *
+                             * TODO: fix the "freeCache" call to not delete
+                             *       the file we care about.
+                             */
+                            if (pkgLite.recommendedInstallLocation
+                                    == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
+                                pkgLite.recommendedInstallLocation
+                                    = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
+                            }
                         }
                     }
                 } finally {
diff --git a/services/java/com/android/server/power/Notifier.java b/services/java/com/android/server/power/Notifier.java
index 5e05693..d99d523 100644
--- a/services/java/com/android/server/power/Notifier.java
+++ b/services/java/com/android/server/power/Notifier.java
@@ -23,6 +23,10 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.media.AudioManager;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
 import android.os.BatteryStats;
 import android.os.Handler;
 import android.os.Looper;
@@ -32,6 +36,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.provider.Settings;
 import android.util.EventLog;
 import android.util.Slog;
 import android.view.WindowManagerPolicy;
@@ -64,6 +69,7 @@
 
     private static final int MSG_USER_ACTIVITY = 1;
     private static final int MSG_BROADCAST = 2;
+    private static final int MSG_WIRELESS_CHARGING_STARTED = 3;
 
     private final Object mLock = new Object();
 
@@ -312,6 +318,20 @@
         }
     }
 
+    /**
+     * Called when wireless charging has started so as to provide user feedback.
+     */
+    public void onWirelessChargingStarted() {
+        if (DEBUG) {
+            Slog.d(TAG, "onWirelessChargingStarted");
+        }
+
+        mSuspendBlocker.acquire();
+        Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED);
+        msg.setAsynchronous(true);
+        mHandler.sendMessage(msg);
+    }
+
     private void updatePendingBroadcastLocked() {
         if (!mBroadcastInProgress
                 && mActualPowerState != POWER_STATE_UNKNOWN
@@ -473,6 +493,23 @@
         }
     };
 
+    private void playWirelessChargingStartedSound() {
+        final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
+                Settings.Global.WIRELESS_CHARGING_STARTED_SOUND);
+        if (soundPath != null) {
+            final Uri soundUri = Uri.parse("file://" + soundPath);
+            if (soundUri != null) {
+                final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
+                if (sfx != null) {
+                    sfx.setStreamType(AudioManager.STREAM_SYSTEM);
+                    sfx.play();
+                }
+            }
+        }
+
+        mSuspendBlocker.release();
+    }
+
     private final class NotifierHandler extends Handler {
         public NotifierHandler(Looper looper) {
             super(looper, null, true /*async*/);
@@ -488,6 +525,10 @@
                 case MSG_BROADCAST:
                     sendNextBroadcast();
                     break;
+
+                case MSG_WIRELESS_CHARGING_STARTED:
+                    playWirelessChargingStartedSound();
+                    break;
             }
         }
     }
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 7f83c17..5a5d910 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -1150,6 +1150,16 @@
                 }
                 userActivityNoUpdateLocked(
                         now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
+
+                // Tell the notifier whether wireless charging has started so that
+                // it can provide feedback to the user.  Refer to
+                // shouldWakeUpWhenPluggedOrUnpluggedLocked for justification of the
+                // heuristics used here.
+                if (!wasPowered && mIsPowered
+                        && mPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS
+                        && mBatteryLevel < WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT) {
+                    mNotifier.onWirelessChargingStarted();
+                }
             }
         }
     }
diff --git a/core/java/android/server/search/SearchManagerService.java b/services/java/com/android/server/search/SearchManagerService.java
similarity index 99%
rename from core/java/android/server/search/SearchManagerService.java
rename to services/java/com/android/server/search/SearchManagerService.java
index 46f2723..132ae79 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/services/java/com/android/server/search/SearchManagerService.java
@@ -14,10 +14,7 @@
  * limitations under the License.
  */
 
-package android.server.search;
-
-import com.android.internal.content.PackageMonitor;
-import com.android.internal.util.IndentingPrintWriter;
+package com.android.server.search;
 
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -45,6 +42,9 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.IndentingPrintWriter;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.List;
diff --git a/core/java/android/server/search/Searchables.java b/services/java/com/android/server/search/Searchables.java
similarity index 99%
rename from core/java/android/server/search/Searchables.java
rename to services/java/com/android/server/search/Searchables.java
index a0095d6..0ffbb7d 100644
--- a/core/java/android/server/search/Searchables.java
+++ b/services/java/com/android/server/search/Searchables.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.server.search;
+package com.android.server.search;
 
 import android.app.AppGlobals;
 import android.app.SearchManager;
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java
index 49f8c0e..34513a1 100644
--- a/services/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/java/com/android/server/wm/AppWindowAnimator.java
@@ -129,7 +129,7 @@
             if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
                 mService.setInputMethodAnimLayerAdjustment(adj);
             }
-            if (w == mAnimator.mWallpaperTarget && mAnimator.mLowerWallpaperTarget == null) {
+            if (w == mService.mWallpaperTarget && mService.mLowerWallpaperTarget == null) {
                 mService.setWallpaperAnimLayerAdjustmentLocked(adj);
             }
         }
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 3ec6d26..275c9bf 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -30,7 +30,6 @@
 import android.view.WindowManager;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
 
 /**
  * Version of WindowToken that is specifically for a particular application (or
@@ -42,7 +41,7 @@
 
     // All of the windows and child windows that are included in this
     // application token.  Note this list is NOT sorted!
-    final ArrayList<WindowState> allAppWindows = new ArrayList<WindowState>();
+    final WindowList allAppWindows = new WindowList();
     final AppWindowAnimator mAppAnimator;
 
     final WindowAnimator mAnimator;
diff --git a/services/java/com/android/server/wm/DisplayMagnificationMediator.java b/services/java/com/android/server/wm/DisplayMagnificationMediator.java
index 8621c5c..0e3a6e1 100644
--- a/services/java/com/android/server/wm/DisplayMagnificationMediator.java
+++ b/services/java/com/android/server/wm/DisplayMagnificationMediator.java
@@ -183,8 +183,6 @@
             displayState.mMagnificationSpec.initialize(spec.scale, spec.offsetX,
                     spec.offsetY);
             spec.recycle();
-        }
-        synchronized (mWindowManagerService.mLayoutToAnim) {
             mWindowManagerService.scheduleAnimationLocked();
         }
     }
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 73293b0..f041d9f 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -9,8 +9,7 @@
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_MAY_CHANGE;
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_FORCE_HIDING_CHANGED;
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE;
-
-import static com.android.server.wm.WindowManagerService.H.UPDATE_ANIM_PARAMETERS;
+import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_ACTION_PENDING;
 
 import android.content.Context;
 import android.os.Debug;
@@ -25,9 +24,8 @@
 import android.view.WindowManagerPolicy;
 import android.view.animation.Animation;
 
-import com.android.server.wm.WindowManagerService.AppWindowAnimParams;
+import com.android.server.wm.WindowManagerService.DisplayContentsIterator;
 import com.android.server.wm.WindowManagerService.LayoutFields;
-import com.android.server.wm.WindowManagerService.LayoutToAnimatorParams;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -49,9 +47,6 @@
 
     int mAdjResult;
 
-    // Layout changes for individual Displays. Indexed by displayId.
-    SparseIntArray mPendingLayoutChanges = new SparseIntArray();
-
     /** Time of current animation step. Reset on each iteration */
     long mCurrentTime;
 
@@ -73,28 +68,6 @@
     SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators =
             new SparseArray<WindowAnimator.DisplayContentsAnimator>();
 
-    static final int WALLPAPER_ACTION_PENDING = 1;
-    int mPendingActions;
-
-    WindowState mWallpaperTarget = null;
-    AppWindowAnimator mWpAppAnimator = null;
-    WindowState mLowerWallpaperTarget = null;
-    WindowState mUpperWallpaperTarget = null;
-
-    ArrayList<AppWindowAnimator> mAppAnimators = new ArrayList<AppWindowAnimator>();
-
-    ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
-
-    /** Parameters being passed from this into mService. */
-    static class AnimatorToLayoutParams {
-        boolean mUpdateQueued;
-        int mBulkUpdateParams;
-        SparseIntArray mPendingLayoutChanges;
-        WindowState mWindowDetachedWallpaper;
-    }
-    /** Do not modify unless holding mService.mWindowMap or this and mAnimToLayout in that order */
-    final AnimatorToLayoutParams mAnimToLayout = new AnimatorToLayoutParams();
-
     boolean mInitialized = false;
 
     // forceHiding states.
@@ -122,13 +95,9 @@
         mAnimationRunnable = new Runnable() {
             @Override
             public void run() {
-                // TODO(cmautner): When full isolation is achieved for animation, the first lock
-                // goes away and only the WindowAnimator.this remains.
-                synchronized(mService.mWindowMap) {
-                    synchronized(WindowAnimator.this) {
-                        copyLayoutToAnimParamsLocked();
-                        animateLocked();
-                    }
+                synchronized (mService.mWindowMap) {
+                    mService.mAnimationScheduled = false;
+                    animateLocked();
                 }
             }
         };
@@ -162,117 +131,17 @@
         mDisplayContentsAnimators.delete(displayId);
     }
 
-    /** Locked on mAnimToLayout */
-    void updateAnimToLayoutLocked() {
-        final AnimatorToLayoutParams animToLayout = mAnimToLayout;
-        synchronized (animToLayout) {
-            animToLayout.mBulkUpdateParams = mBulkUpdateParams;
-            animToLayout.mPendingLayoutChanges = mPendingLayoutChanges.clone();
-            animToLayout.mWindowDetachedWallpaper = mWindowDetachedWallpaper;
-
-            if (!animToLayout.mUpdateQueued) {
-                animToLayout.mUpdateQueued = true;
-                mService.mH.sendMessage(mService.mH.obtainMessage(UPDATE_ANIM_PARAMETERS));
-            }
-        }
+    AppWindowAnimator getWallpaperAppAnimator() {
+        return mService.mWallpaperTarget == null
+                ? null : mService.mWallpaperTarget.mAppToken == null
+                        ? null : mService.mWallpaperTarget.mAppToken.mAppAnimator;
     }
 
-    /** Copy all WindowManagerService params into local params here. Locked on 'this'. */
-    private void copyLayoutToAnimParamsLocked() {
-        final LayoutToAnimatorParams layoutToAnim = mService.mLayoutToAnim;
-        synchronized(layoutToAnim) {
-            layoutToAnim.mAnimationScheduled = false;
+    void hideWallpapersLocked(final WindowState w) {
+        final WindowState wallpaperTarget = mService.mWallpaperTarget;
+        final WindowState lowerWallpaperTarget = mService.mLowerWallpaperTarget;
+        final ArrayList<WindowToken> wallpaperTokens = mService.mWallpaperTokens;
 
-            if (!layoutToAnim.mParamsModified) {
-                return;
-            }
-            layoutToAnim.mParamsModified = false;
-
-            if ((layoutToAnim.mChanges & LayoutToAnimatorParams.WALLPAPER_TOKENS_CHANGED) != 0) {
-                layoutToAnim.mChanges &= ~LayoutToAnimatorParams.WALLPAPER_TOKENS_CHANGED;
-                mWallpaperTokens = new ArrayList<WindowToken>(layoutToAnim.mWallpaperTokens);
-            }
-
-            if (WindowManagerService.DEBUG_WALLPAPER_LIGHT) {
-                if (mWallpaperTarget != layoutToAnim.mWallpaperTarget
-                        || mLowerWallpaperTarget != layoutToAnim.mLowerWallpaperTarget
-                        || mUpperWallpaperTarget != layoutToAnim.mUpperWallpaperTarget) {
-                    Slog.d(TAG, "Pulling anim wallpaper: target=" + layoutToAnim.mWallpaperTarget
-                            + " lower=" + layoutToAnim.mLowerWallpaperTarget + " upper="
-                            + layoutToAnim.mUpperWallpaperTarget);
-                }
-            }
-            mWallpaperTarget = layoutToAnim.mWallpaperTarget;
-            mWpAppAnimator = mWallpaperTarget == null
-                    ? null : mWallpaperTarget.mAppToken == null
-                            ? null : mWallpaperTarget.mAppToken.mAppAnimator;
-            mLowerWallpaperTarget = layoutToAnim.mLowerWallpaperTarget;
-            mUpperWallpaperTarget = layoutToAnim.mUpperWallpaperTarget;
-
-            // Set the new DimAnimator params.
-            final int numDisplays = mDisplayContentsAnimators.size();
-            for (int i = 0; i < numDisplays; i++) {
-                final int displayId = mDisplayContentsAnimators.keyAt(i);
-                DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
-
-                displayAnimator.mWinAnimators.clear();
-                final WinAnimatorList winAnimators = layoutToAnim.mWinAnimatorLists.get(displayId);
-                if (winAnimators != null) {
-                    displayAnimator.mWinAnimators.addAll(winAnimators);
-                }
-
-                DimAnimator.Parameters dimParams = layoutToAnim.mDimParams.get(displayId);
-                if (dimParams == null) {
-                    displayAnimator.mDimParams = null;
-                } else {
-                    final WindowStateAnimator newWinAnimator = dimParams.mDimWinAnimator;
-
-                    // Only set dim params on the highest dimmed layer.
-                    final WindowStateAnimator existingDimWinAnimator =
-                            displayAnimator.mDimParams == null ?
-                                    null : displayAnimator.mDimParams.mDimWinAnimator;
-                    // Don't turn on for an unshown surface, or for any layer but the highest
-                    // dimmed layer.
-                    if (newWinAnimator.mSurfaceShown && (existingDimWinAnimator == null
-                            || !existingDimWinAnimator.mSurfaceShown
-                            || existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
-                        displayAnimator.mDimParams = new DimAnimator.Parameters(dimParams);
-                    }
-                }
-            }
-
-            mAppAnimators.clear();
-            final int N = layoutToAnim.mAppWindowAnimParams.size();
-            for (int i = 0; i < N; i++) {
-                final AppWindowAnimParams params = layoutToAnim.mAppWindowAnimParams.get(i);
-                AppWindowAnimator appAnimator = params.mAppAnimator;
-                appAnimator.mAllAppWinAnimators.clear();
-                appAnimator.mAllAppWinAnimators.addAll(params.mWinAnimators);
-                mAppAnimators.add(appAnimator);
-            }
-        }
-    }
-
-    void hideWallpapersLocked(final WindowState w, boolean fromAnimator) {
-        // There is an issue where this function can be called either from
-        // the animation or the layout side of the window manager.  The problem
-        // is that if it is called from the layout side, we may not yet have
-        // propagated the current layout wallpaper state over into the animation
-        // state.  If that is the case, we can do bad things like hide the
-        // wallpaper when we had just made it shown because the animation side
-        // doesn't yet see that there is now a wallpaper target.  As a temporary
-        // work-around, we tell the function here which side of the window manager
-        // is calling so it can use the right state.
-        if (fromAnimator) {
-            hideWallpapersLocked(w, mWallpaperTarget, mLowerWallpaperTarget, mWallpaperTokens);
-        } else {
-            hideWallpapersLocked(w, mService.mWallpaperTarget,
-                    mService.mLowerWallpaperTarget, mService.mWallpaperTokens);
-        }
-    }
-
-    void hideWallpapersLocked(final WindowState w, final WindowState wallpaperTarget,
-            final WindowState lowerWallpaperTarget, final ArrayList<WindowToken> wallpaperTokens) {
         if ((wallpaperTarget == w && lowerWallpaperTarget == null) || wallpaperTarget == null) {
             final int numTokens = wallpaperTokens.size();
             for (int i = numTokens - 1; i >= 0; i--) {
@@ -299,9 +168,10 @@
 
     private void updateAppWindowsLocked() {
         int i;
-        final int NAT = mAppAnimators.size();
+        final ArrayList<AppWindowToken> appTokens = mService.mAnimatingAppTokens;
+        final int NAT = appTokens.size();
         for (i=0; i<NAT; i++) {
-            final AppWindowAnimator appAnimator = mAppAnimators.get(i);
+            final AppWindowAnimator appAnimator = appTokens.get(i).mAppAnimator;
             final boolean wasAnimating = appAnimator.animation != null
                     && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
             if (appAnimator.stepAnimationLocked(mCurrentTime)) {
@@ -335,15 +205,14 @@
     private void updateWindowsLocked(final int displayId) {
         ++mAnimTransactionSequence;
 
-        final WinAnimatorList winAnimatorList =
-                getDisplayContentsAnimatorLocked(displayId).mWinAnimators;
+        final WindowList windows = mService.getWindowListLocked(displayId);
         ArrayList<WindowStateAnimator> unForceHiding = null;
         boolean wallpaperInUnForceHiding = false;
         mForceHiding = KEYGUARD_NOT_SHOWN;
 
-        for (int i = winAnimatorList.size() - 1; i >= 0; i--) {
-            WindowStateAnimator winAnimator = winAnimatorList.get(i);
-            WindowState win = winAnimator.mWin;
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            WindowState win = windows.get(i);
+            WindowStateAnimator winAnimator = win.mWinAnimator;
             final int flags = winAnimator.mAttrFlags;
 
             if (winAnimator.mSurface != null) {
@@ -355,13 +224,13 @@
                             ", nowAnimating=" + nowAnimating);
                 }
 
-                if (wasAnimating && !winAnimator.mAnimating && mWallpaperTarget == win) {
+                if (wasAnimating && !winAnimator.mAnimating && mService.mWallpaperTarget == win) {
                     mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
                     setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
                             WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                     if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
                         mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 2",
-                            mPendingLayoutChanges.get(Display.DEFAULT_DISPLAY));
+                                getPendingLayoutChanges(Display.DEFAULT_DISPLAY));
                     }
                 }
 
@@ -375,7 +244,7 @@
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
                             mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 3",
-                                mPendingLayoutChanges.get(displayId));
+                                    getPendingLayoutChanges(displayId));
                         }
                         mService.mFocusMayChange = true;
                     }
@@ -438,7 +307,7 @@
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
                             mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 4",
-                                mPendingLayoutChanges.get(Display.DEFAULT_DISPLAY));
+                                    getPendingLayoutChanges(Display.DEFAULT_DISPLAY));
                         }
                     }
                 }
@@ -448,11 +317,11 @@
             if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) {
                 if (atoken == null || atoken.allDrawn) {
                     if (winAnimator.performShowLocked()) {
-                        mPendingLayoutChanges.put(displayId,
+                        setPendingLayoutChanges(displayId,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
                             mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 5",
-                                mPendingLayoutChanges.get(displayId));
+                                    getPendingLayoutChanges(displayId));
                         }
                     }
                 }
@@ -486,21 +355,21 @@
     private void updateWallpaperLocked(int displayId) {
         final DisplayContentsAnimator displayAnimator =
                 getDisplayContentsAnimatorLocked(displayId);
-        final WinAnimatorList winAnimatorList = displayAnimator.mWinAnimators;
+        final WindowList windows = mService.getWindowListLocked(displayId);
         WindowStateAnimator windowAnimationBackground = null;
         int windowAnimationBackgroundColor = 0;
         WindowState detachedWallpaper = null;
         final DimSurface windowAnimationBackgroundSurface =
                 displayAnimator.mWindowAnimationBackgroundSurface;
 
-        for (int i = winAnimatorList.size() - 1; i >= 0; i--) {
-            WindowStateAnimator winAnimator = winAnimatorList.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState win = windows.get(i);
+            WindowStateAnimator winAnimator = win.mWinAnimator;
             if (winAnimator.mSurface == null) {
                 continue;
             }
 
             final int flags = winAnimator.mAttrFlags;
-            final WindowState win = winAnimator.mWin;
 
             // If this window is animating, make a note that we have
             // an animating window and take care of a request to run
@@ -559,11 +428,11 @@
             // don't cause the wallpaper to suddenly disappear.
             int animLayer = windowAnimationBackground.mAnimLayer;
             WindowState win = windowAnimationBackground.mWin;
-            if (mWallpaperTarget == win
-                    || mLowerWallpaperTarget == win || mUpperWallpaperTarget == win) {
-                final int N = winAnimatorList.size();
+            if (mService.mWallpaperTarget == win || mService.mLowerWallpaperTarget == win
+                    || mService.mUpperWallpaperTarget == win) {
+                final int N = windows.size();
                 for (int i = 0; i < N; i++) {
-                    WindowStateAnimator winAnimator = winAnimatorList.get(i);
+                    WindowStateAnimator winAnimator = windows.get(i).mWinAnimator;
                     if (winAnimator.mIsWallpaper) {
                         animLayer = winAnimator.mAnimLayer;
                         break;
@@ -586,10 +455,13 @@
     /** See if any windows have been drawn, so they (and others associated with them) can now be
      *  shown. */
     private void testTokenMayBeDrawnLocked() {
-        final int NT = mAppAnimators.size();
+        // See if any windows have been drawn, so they (and others
+        // associated with them) can now be shown.
+        final ArrayList<AppWindowToken> appTokens = mService.mAnimatingAppTokens;
+        final int NT = appTokens.size();
         for (int i=0; i<NT; i++) {
-            AppWindowAnimator appAnimator = mAppAnimators.get(i);
-            AppWindowToken wtoken = appAnimator.mAppToken;
+            AppWindowToken wtoken = appTokens.get(i);
+            AppWindowAnimator appAnimator = wtoken.mAppAnimator;
             final boolean allDrawn = wtoken.allDrawn;
             if (allDrawn != appAnimator.allDrawn) {
                 appAnimator.allDrawn = allDrawn;
@@ -611,7 +483,7 @@
                         setAppLayoutChanges(appAnimator,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
                                 "testTokenMayBeDrawnLocked");
- 
+
                         // We can now show all of the drawn windows!
                         if (!mService.mOpeningApps.contains(wtoken)) {
                             mAnimating |= appAnimator.showAllWindowsLocked();
@@ -634,7 +506,6 @@
             return;
         }
 
-        mPendingLayoutChanges.clear();
         mCurrentTime = SystemClock.uptimeMillis();
         mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
         boolean wasAnimating = mAnimating;
@@ -671,10 +542,10 @@
                 // associated with exiting/removed apps
                 performAnimationsLocked(displayId);
 
-                final WinAnimatorList winAnimatorList = displayAnimator.mWinAnimators;
-                final int N = winAnimatorList.size();
+                final WindowList windows = mService.getWindowListLocked(displayId);
+                final int N = windows.size();
                 for (int j = 0; j < N; j++) {
-                    winAnimatorList.get(j).prepareSurfaceLocked(true);
+                    windows.get(j).mWinAnimator.prepareSurfaceLocked(true);
                 }
             }
 
@@ -712,21 +583,30 @@
                     TAG, "<<< CLOSE TRANSACTION animateLocked");
         }
 
-        for (int i = mPendingLayoutChanges.size() - 1; i >= 0; i--) {
-            if ((mPendingLayoutChanges.valueAt(i)
-                    & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
-                mPendingActions |= WALLPAPER_ACTION_PENDING;
+        boolean hasPendingLayoutChanges = false;
+        DisplayContentsIterator iterator = mService.new DisplayContentsIterator();
+        while (iterator.hasNext()) {
+            final DisplayContent displayContent = iterator.next();
+            final int pendingChanges = getPendingLayoutChanges(displayContent.getDisplayId());
+            if ((pendingChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+                mBulkUpdateParams |= SET_WALLPAPER_ACTION_PENDING;
+            }
+            if (pendingChanges != 0) {
+                hasPendingLayoutChanges = true;
             }
         }
 
-        if (mBulkUpdateParams != 0 || mPendingLayoutChanges.size() > 0) {
-            updateAnimToLayoutLocked();
+        boolean doRequest = false;
+        if (mBulkUpdateParams != 0) {
+            doRequest = mService.copyAnimToLayoutParamsLocked();
+        }
+
+        if (hasPendingLayoutChanges || doRequest) {
+            mService.requestTraversalLocked();
         }
 
         if (mAnimating) {
-            synchronized (mService.mLayoutToAnim) {
-                mService.scheduleAnimationLocked();
-            }
+            mService.scheduleAnimationLocked();
         } else if (wasAnimating) {
             mService.requestTraversalLocked();
         }
@@ -734,7 +614,7 @@
             Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
                 + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
                 + " mPendingLayoutChanges(DEFAULT_DISPLAY)="
-                + Integer.toHexString(mPendingLayoutChanges.get(Display.DEFAULT_DISPLAY)));
+                + Integer.toHexString(getPendingLayoutChanges(Display.DEFAULT_DISPLAY)));
         }
     }
 
@@ -777,51 +657,16 @@
         final String subPrefix = "  " + prefix;
         final String subSubPrefix = "  " + subPrefix;
 
-        boolean needSep = false;
-        if (mAppAnimators.size() > 0) {
-            needSep = true;
-            pw.println("  App Animators:");
-            for (int i=mAppAnimators.size()-1; i>=0; i--) {
-                AppWindowAnimator anim = mAppAnimators.get(i);
-                pw.print(prefix); pw.print("App Animator #"); pw.print(i);
-                        pw.print(' '); pw.print(anim);
-                if (dumpAll) {
-                    pw.println(':');
-                    anim.dump(pw, subPrefix, dumpAll);
-                } else {
-                    pw.println();
-                }
-            }
-        }
-        if (mWallpaperTokens.size() > 0) {
-            if (needSep) {
-                pw.println();
-            }
-            needSep = true;
-            pw.print(prefix); pw.println("Wallpaper tokens:");
-            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
-                WindowToken token = mWallpaperTokens.get(i);
-                pw.print(prefix); pw.print("Wallpaper #"); pw.print(i);
-                        pw.print(' '); pw.print(token);
-                if (dumpAll) {
-                    pw.println(':');
-                    token.dump(pw, subPrefix);
-                } else {
-                    pw.println();
-                }
-            }
-        }
-
-        if (needSep) {
-            pw.println();
-        }
         for (int i = 0; i < mDisplayContentsAnimators.size(); i++) {
             pw.print(prefix); pw.print("DisplayContentsAnimator #");
                     pw.print(mDisplayContentsAnimators.keyAt(i));
                     pw.println(":");
             DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
-            for (int j=0; j<displayAnimator.mWinAnimators.size(); j++) {
-                WindowStateAnimator wanim = displayAnimator.mWinAnimators.get(j);
+            final WindowList windows =
+                    mService.getWindowListLocked(mDisplayContentsAnimators.keyAt(i));
+            final int N = windows.size();
+            for (int j = 0; j < N; j++) {
+                WindowStateAnimator wanim = windows.get(j).mWinAnimator;
                 pw.print(subPrefix); pw.print("Window #"); pw.print(j);
                         pw.print(": "); pw.println(wanim);
             }
@@ -867,48 +712,34 @@
                     pw.print(Integer.toHexString(mBulkUpdateParams));
                     pw.println(bulkUpdateParamsToString(mBulkUpdateParams));
         }
-        if (mPendingActions != 0) {
-            pw.print(prefix); pw.print("mPendingActions=0x");
-                    pw.println(Integer.toHexString(mPendingActions));
-        }
         if (mWindowDetachedWallpaper != null) {
             pw.print(prefix); pw.print("mWindowDetachedWallpaper=");
                 pw.println(mWindowDetachedWallpaper);
         }
-        pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget);
-        pw.print(prefix); pw.print("mWpAppAnimator="); pw.println(mWpAppAnimator);
-        if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) {
-            pw.print(prefix); pw.print("mLowerWallpaperTarget=");
-                    pw.println(mLowerWallpaperTarget);
-            pw.print(prefix); pw.print("mUpperWallpaperTarget=");
-                    pw.println(mUpperWallpaperTarget);
-        }
         if (mUniverseBackground != null) {
             pw.print(prefix); pw.print("mUniverseBackground="); pw.print(mUniverseBackground);
                     pw.print(" mAboveUniverseLayer="); pw.println(mAboveUniverseLayer);
         }
     }
 
-    void clearPendingActions() {
-        synchronized (this) {
-            mPendingActions = 0;
-        }
+    int getPendingLayoutChanges(final int displayId) {
+        return mService.getDisplayContentLocked(displayId).pendingLayoutChanges;
     }
 
     void setPendingLayoutChanges(final int displayId, final int changes) {
-        mPendingLayoutChanges.put(displayId, mPendingLayoutChanges.get(displayId) | changes);
+        mService.getDisplayContentLocked(displayId).pendingLayoutChanges |= changes;
     }
 
     void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String s) {
         // Used to track which displays layout changes have been done.
         SparseIntArray displays = new SparseIntArray();
-        for (int i = appAnimator.mAllAppWinAnimators.size() - 1; i >= 0; i--) {
-            WindowStateAnimator winAnimator = appAnimator.mAllAppWinAnimators.get(i);
-            final int displayId = winAnimator.mWin.mDisplayContent.getDisplayId();
+        WindowList windows = appAnimator.mAppToken.allAppWindows;
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final int displayId = windows.get(i).getDisplayId();
             if (displays.indexOfKey(displayId) < 0) {
                 setPendingLayoutChanges(displayId, changes);
                 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                    mService.debugLayoutRepeats(s, mPendingLayoutChanges.get(displayId));
+                    mService.debugLayoutRepeats(s, getPendingLayoutChanges(displayId));
                 }
                 // Keep from processing this display again.
                 displays.put(displayId, changes);
@@ -916,6 +747,27 @@
         }
     }
 
+    void setDimParamsLocked(int displayId, DimAnimator.Parameters dimParams) {
+        DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
+        if (dimParams == null) {
+            displayAnimator.mDimParams = null;
+        } else {
+            final WindowStateAnimator newWinAnimator = dimParams.mDimWinAnimator;
+
+            // Only set dim params on the highest dimmed layer.
+            final WindowStateAnimator existingDimWinAnimator =
+                    displayAnimator.mDimParams == null ?
+                            null : displayAnimator.mDimParams.mDimWinAnimator;
+            // Don't turn on for an unshown surface, or for any layer but the highest
+            // dimmed layer.
+            if (newWinAnimator.mSurfaceShown && (existingDimWinAnimator == null
+                    || !existingDimWinAnimator.mSurfaceShown
+                    || existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
+                displayAnimator.mDimParams = new DimAnimator.Parameters(dimParams);
+            }
+        }
+    }
+
     private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) {
         DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
         if (displayAnimator == null) {
@@ -934,7 +786,6 @@
     }
 
     private class DisplayContentsAnimator {
-        WinAnimatorList mWinAnimators = new WinAnimatorList();
         DimAnimator mDimAnimator = null;
         DimAnimator.Parameters mDimParams = null;
         DimSurface mWindowAnimationBackgroundSurface = null;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 9041a9b..d078273 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -125,7 +125,6 @@
 import android.view.InputEvent;
 import android.view.InputEventReceiver;
 import android.view.KeyEvent;
-import android.view.MagnificationSpec;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.SurfaceSession;
@@ -522,7 +521,7 @@
     WindowState mLowerWallpaperTarget = null;
     // If non-null, we are in the middle of animating from one wallpaper target
     // to another, and this is the higher one in Z-order.
-    private WindowState mUpperWallpaperTarget = null;
+    WindowState mUpperWallpaperTarget = null;
     int mWallpaperAnimLayerAdjustment;
     float mLastWallpaperX = -1;
     float mLastWallpaperY = -1;
@@ -566,6 +565,7 @@
         static final int SET_FORCE_HIDING_CHANGED           = 1 << 2;
         static final int SET_ORIENTATION_CHANGE_COMPLETE    = 1 << 3;
         static final int SET_TURN_ON_SCREEN                 = 1 << 4;
+        static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 5;
 
         boolean mWallpaperForceHidingChanged = false;
         boolean mWallpaperMayChange = false;
@@ -579,6 +579,7 @@
         private float mButtonBrightness = -1;
         private long mUserActivityTimeout = -1;
         private boolean mUpdateRotation = false;
+        boolean mWallpaperActionPending = false;
 
         private static final int DISPLAY_CONTENT_UNKNOWN = 0;
         private static final int DISPLAY_CONTENT_MIRROR = 1;
@@ -603,27 +604,7 @@
         }
     }
 
-    static class LayoutToAnimatorParams {
-        boolean mParamsModified;
-
-        static final long WALLPAPER_TOKENS_CHANGED = 1 << 0;
-        long mChanges;
-
-        boolean mAnimationScheduled;
-        SparseArray<WinAnimatorList> mWinAnimatorLists = new SparseArray<WinAnimatorList>();
-        WindowState mWallpaperTarget;
-        WindowState mLowerWallpaperTarget;
-        WindowState mUpperWallpaperTarget;
-        SparseArray<DimAnimator.Parameters> mDimParams = new SparseArray<DimAnimator.Parameters>();
-        ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
-        ArrayList<AppWindowAnimParams> mAppWindowAnimParams = new ArrayList<AppWindowAnimParams>();
-    }
-    /** Params from WindowManagerService to WindowAnimator. Do not modify or read without first
-     * locking on either mWindowMap or mAnimator and then on mLayoutToAnim */
-    final LayoutToAnimatorParams mLayoutToAnim = new LayoutToAnimatorParams();
-
-    /** The lowest wallpaper target with a detached wallpaper animation on it. */
-    WindowState mWindowDetachedWallpaper = null;
+    boolean mAnimationScheduled;
 
     /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
      * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
@@ -703,9 +684,6 @@
      */
     boolean mInTouchMode = true;
 
-    // Temp regions for intermediary calculations.
-    private final Region mTempRegion = new Region();
-
     private ViewServer mViewServer;
     private ArrayList<WindowChangeListener> mWindowChangeListeners =
         new ArrayList<WindowChangeListener>();
@@ -1592,7 +1570,7 @@
                 continue;
             }
             topCurW = null;
-            if (w != mWindowDetachedWallpaper && w.mAppToken != null) {
+            if (w != mAnimator.mWindowDetachedWallpaper && w.mAppToken != null) {
                 // If this window's app token is hidden and not animating,
                 // it is of no interest to us.
                 if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) {
@@ -1618,7 +1596,7 @@
                     continue;
                 }
                 break;
-            } else if (w == mWindowDetachedWallpaper) {
+            } else if (w == mAnimator.mWindowDetachedWallpaper) {
                 windowDetachedI = i;
             }
         }
@@ -2817,7 +2795,7 @@
                 }
                 if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
                     // To change the format, we need to re-build the surface.
-                    winAnimator.destroySurfaceLocked(false);
+                    winAnimator.destroySurfaceLocked();
                     toBeDisplayed = true;
                     surfaceChanged = true;
                 }
@@ -2898,7 +2876,7 @@
                             if (mInputMethodWindow == win) {
                                 mInputMethodWindow = null;
                             }
-                            winAnimator.destroySurfaceLocked(false);
+                            winAnimator.destroySurfaceLocked();
                         }
                         if (mMagnificationMediator != null) {
                             mMagnificationMediator.onWindowTransitionLw(win, transit);
@@ -3002,7 +2980,7 @@
                 if (win == null) {
                     return;
                 }
-                win.mWinAnimator.destroyDeferredSurfaceLocked(false);
+                win.mWinAnimator.destroyDeferredSurfaceLocked();
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -3179,7 +3157,6 @@
             mTokenMap.put(token, wtoken);
             if (type == TYPE_WALLPAPER) {
                 mWallpaperTokens.add(wtoken);
-                updateLayoutToAnimWallpaperTokens();
             }
         }
     }
@@ -3231,7 +3208,6 @@
                         mExitingTokens.add(wtoken);
                     } else if (wtoken.windowType == TYPE_WALLPAPER) {
                         mWallpaperTokens.remove(wtoken);
-                        updateLayoutToAnimWallpaperTokens();
                     }
                 }
 
@@ -5593,7 +5569,7 @@
                         rotation, mFxSession,
                         MAX_ANIMATION_DURATION, mTransitionAnimationScale,
                         displayInfo.logicalWidth, displayInfo.logicalHeight)) {
-                    updateLayoutToAnimationLocked();
+                    scheduleAnimationLocked();
                 }
             }
 
@@ -6641,19 +6617,17 @@
         public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
         public static final int BOOT_TIMEOUT = 23;
         public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
-        public static final int UPDATE_ANIM_PARAMETERS = 25;
-        public static final int SHOW_STRICT_MODE_VIOLATION = 26;
-        public static final int DO_ANIMATION_CALLBACK = 27;
+        public static final int SHOW_STRICT_MODE_VIOLATION = 25;
+        public static final int DO_ANIMATION_CALLBACK = 26;
 
-        public static final int DO_DISPLAY_ADDED = 28;
-        public static final int DO_DISPLAY_REMOVED = 29;
-        public static final int DO_DISPLAY_CHANGED = 30;
+        public static final int DO_DISPLAY_ADDED = 27;
+        public static final int DO_DISPLAY_REMOVED = 28;
+        public static final int DO_DISPLAY_CHANGED = 29;
 
-        public static final int CLIENT_FREEZE_TIMEOUT = 31;
+        public static final int CLIENT_FREEZE_TIMEOUT = 30;
 
         public static final int ANIMATOR_WHAT_OFFSET = 100000;
         public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
-        public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 2;
 
         public H() {
         }
@@ -6933,20 +6907,18 @@
 
                 case FORCE_GC: {
                     synchronized (mWindowMap) {
-                        synchronized (mAnimator) {
-                            // Since we're holding both mWindowMap and mAnimator we don't need to
-                            // hold mAnimator.mLayoutToAnim.
-                            if (mAnimator.mAnimating || mLayoutToAnim.mAnimationScheduled) {
-                                // If we are animating, don't do the gc now but
-                                // delay a bit so we don't interrupt the animation.
-                                sendEmptyMessageDelayed(H.FORCE_GC, 2000);
-                                return;
-                            }
-                            // If we are currently rotating the display, it will
-                            // schedule a new message when done.
-                            if (mDisplayFrozen) {
-                                return;
-                            }
+                        // Since we're holding both mWindowMap and mAnimator we don't need to
+                        // hold mAnimator.mLayoutToAnim.
+                        if (mAnimator.mAnimating || mAnimationScheduled) {
+                            // If we are animating, don't do the gc now but
+                            // delay a bit so we don't interrupt the animation.
+                            sendEmptyMessageDelayed(H.FORCE_GC, 2000);
+                            return;
+                        }
+                        // If we are currently rotating the display, it will
+                        // schedule a new message when done.
+                        if (mDisplayFrozen) {
+                            return;
                         }
                     }
                     Runtime.getRuntime().gc();
@@ -6960,16 +6932,14 @@
 
                 case APP_FREEZE_TIMEOUT: {
                     synchronized (mWindowMap) {
-                        synchronized (mAnimator) {
-                            Slog.w(TAG, "App freeze timeout expired.");
-                            int i = mAppTokens.size();
-                            while (i > 0) {
-                                i--;
-                                AppWindowToken tok = mAppTokens.get(i);
-                                if (tok.mAppAnimator.freezingScreen) {
-                                    Slog.w(TAG, "Force clearing freeze: " + tok);
-                                    unsetAppFreezingScreenLocked(tok, true, true);
-                                }
+                        Slog.w(TAG, "App freeze timeout expired.");
+                        int i = mAppTokens.size();
+                        while (i > 0) {
+                            i--;
+                            AppWindowToken tok = mAppTokens.get(i);
+                            if (tok.mAppAnimator.freezingScreen) {
+                                Slog.w(TAG, "Force clearing freeze: " + tok);
+                                unsetAppFreezingScreenLocked(tok, true, true);
                             }
                         }
                     }
@@ -7060,17 +7030,6 @@
                     break;
                 }
 
-                case UPDATE_ANIM_PARAMETERS: {
-                    // Used to send multiple changes from the animation side to the layout side.
-                    synchronized (mWindowMap) {
-                        if (copyAnimToLayoutParamsLocked()) {
-                            sendEmptyMessage(CLEAR_PENDING_ACTIONS);
-                            performLayoutAndPlaceSurfacesLocked();
-                        }
-                    }
-                    break;
-                }
-
                 case SHOW_STRICT_MODE_VIOLATION: {
                     showStrictModeViolation(msg.arg1, msg.arg2);
                     break;
@@ -7085,11 +7044,6 @@
                     break;
                 }
 
-                case CLEAR_PENDING_ACTIONS: {
-                    mAnimator.clearPendingActions();
-                    break;
-                }
-
                 case DO_ANIMATION_CALLBACK: {
                     try {
                         ((IRemoteCallback)msg.obj).sendResult(null);
@@ -7468,7 +7422,7 @@
                     pw.flush();
                     Slog.w(TAG, "This window was lost: " + ws);
                     Slog.w(TAG, sw.toString());
-                    ws.mWinAnimator.destroySurfaceLocked(false);
+                    ws.mWinAnimator.destroySurfaceLocked();
                 }
             }
             Slog.w(TAG, "Current app token list:");
@@ -7530,7 +7484,7 @@
             }
             if (layerChanged && mAnimator.isDimmingLocked(winAnimator)) {
                 // Force an animation pass just to update the mDimAnimator layer.
-                updateLayoutToAnimationLocked();
+                scheduleAnimationLocked();
             }
             if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
                     + "mBase=" + w.mBaseLayer
@@ -7556,6 +7510,7 @@
             mH.removeMessages(H.DO_TRAVERSAL);
             loopCount--;
         } while (mTraversalScheduled && loopCount > 0);
+        mInnerFields.mWallpaperActionPending = false;
     }
 
     private boolean mInLayout = false;
@@ -7688,7 +7643,7 @@
             // soon won't be visible, to avoid wasting time and funky
             // changes while a window is animating away.
             final boolean gone = (behindDream && mPolicy.canBeForceHidden(win, win.mAttrs))
-                    || (win.isGoneForLayoutLw() && !win.isOnScreen());
+                    || (win.isGoneForLayoutLw() && !(win.isOnScreen() && win.isDrawFinishedLw()));
 
             if (DEBUG_LAYOUT && !win.mLayoutAttached) {
                 Slog.v(TAG, "1ST PASS " + win
@@ -8780,7 +8735,7 @@
                 if (win == mWallpaperTarget) {
                     wallpaperDestroyed = true;
                 }
-                win.mWinAnimator.destroySurfaceLocked(false);
+                win.mWinAnimator.destroySurfaceLocked();
             } while (i > 0);
             mDestroySurface.clear();
         }
@@ -8792,7 +8747,6 @@
                 mExitingTokens.remove(i);
                 if (token.windowType == TYPE_WALLPAPER) {
                     mWallpaperTokens.remove(token);
-                    updateLayoutToAnimWallpaperTokens();
                 }
             }
         }
@@ -8903,7 +8857,7 @@
         // be enabled, because the window obscured flags have changed.
         enableScreenIfNeededLocked();
 
-        updateLayoutToAnimationLocked();
+        scheduleAnimationLocked();
 
         if (DEBUG_WINDOW_TRACE) {
             Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: animating="
@@ -9000,82 +8954,21 @@
 
     /** Note that Locked in this case is on mLayoutToAnim */
     void scheduleAnimationLocked() {
-        final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
-        if (!layoutToAnim.mAnimationScheduled) {
-            layoutToAnim.mAnimationScheduled = true;
+        if (!mAnimationScheduled) {
+            mAnimationScheduled = true;
             mChoreographer.postCallback(
                     Choreographer.CALLBACK_ANIMATION, mAnimator.mAnimationRunnable, null);
         }
     }
 
-    void updateLayoutToAnimationLocked() {
-        final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
-        synchronized (layoutToAnim) {
-            // Copy local params to transfer params.
-            SparseArray<WinAnimatorList> allWinAnimatorLists = layoutToAnim.mWinAnimatorLists;
-            allWinAnimatorLists.clear();
-            DisplayContentsIterator iterator = new DisplayContentsIterator();
-            while (iterator.hasNext()) {
-                final DisplayContent displayContent = iterator.next();
-                WinAnimatorList winAnimatorList = new WinAnimatorList();
-                final WindowList windows = displayContent.getWindowList();
-                int N = windows.size();
-                for (int i = 0; i < N; i++) {
-                    final WindowStateAnimator winAnimator = windows.get(i).mWinAnimator;
-                    if (winAnimator.mSurface != null) {
-                        winAnimatorList.add(winAnimator);
-                    }
-                }
-                allWinAnimatorLists.put(displayContent.getDisplayId(), winAnimatorList);
-            }
-
-            if (WindowManagerService.DEBUG_WALLPAPER_LIGHT) {
-                if (mWallpaperTarget != layoutToAnim.mWallpaperTarget
-                        || mLowerWallpaperTarget != layoutToAnim.mLowerWallpaperTarget
-                        || mUpperWallpaperTarget != layoutToAnim.mUpperWallpaperTarget) {
-                    Slog.d(TAG, "Pushing anim wallpaper: target=" + mWallpaperTarget
-                            + " lower=" + mLowerWallpaperTarget + " upper="
-                            + mUpperWallpaperTarget + "\n" + Debug.getCallers(5, "  "));
-                }
-            }
-            layoutToAnim.mWallpaperTarget = mWallpaperTarget;
-            layoutToAnim.mLowerWallpaperTarget = mLowerWallpaperTarget;
-            layoutToAnim.mUpperWallpaperTarget = mUpperWallpaperTarget;
-
-            final ArrayList<AppWindowAnimParams> paramList = layoutToAnim.mAppWindowAnimParams;
-            paramList.clear();
-            int N = mAnimatingAppTokens.size();
-            for (int i = 0; i < N; i++) {
-                paramList.add(new AppWindowAnimParams(mAnimatingAppTokens.get(i).mAppAnimator));
-            }
-
-            layoutToAnim.mParamsModified = true;
-            scheduleAnimationLocked();
-        }
-    }
-
-    void updateLayoutToAnimWallpaperTokens() {
-        synchronized(mLayoutToAnim) {
-            mLayoutToAnim.mWallpaperTokens = new ArrayList<WindowToken>(mWallpaperTokens);
-            mLayoutToAnim.mChanges |= LayoutToAnimatorParams.WALLPAPER_TOKENS_CHANGED;
-        }
-    }
-
-    void setAnimDimParams(int displayId, DimAnimator.Parameters params) {
-        synchronized (mLayoutToAnim) {
-            mLayoutToAnim.mDimParams.put(displayId, params);
-            scheduleAnimationLocked();
-        }
-    }
-
     void startDimmingLocked(final WindowStateAnimator winAnimator, final float target,
                       final int width, final int height) {
-        setAnimDimParams(winAnimator.mWin.getDisplayId(),
+        mAnimator.setDimParamsLocked(winAnimator.mWin.getDisplayId(),
                 new DimAnimator.Parameters(winAnimator, width, height, target));
     }
 
     void stopDimmingLocked(int displayId) {
-        setAnimDimParams(displayId, null);
+        mAnimator.setDimParamsLocked(displayId, null);
     }
 
     private boolean needsLayout() {
@@ -9088,53 +8981,39 @@
         return false;
     }
 
-    private boolean copyAnimToLayoutParamsLocked() {
+    boolean copyAnimToLayoutParamsLocked() {
         boolean doRequest = false;
-        final WindowAnimator.AnimatorToLayoutParams animToLayout = mAnimator.mAnimToLayout;
-        synchronized (animToLayout) {
-            animToLayout.mUpdateQueued = false;
-            final int bulkUpdateParams = animToLayout.mBulkUpdateParams;
-            // TODO(cmautner): As the number of bits grows, use masks of bit groups to
-            //  eliminate unnecessary tests.
-            if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
-                mInnerFields.mUpdateRotation = true;
-                doRequest = true;
-            }
-            if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
-                mInnerFields.mWallpaperMayChange = true;
-                doRequest = true;
-            }
-            if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
-                mInnerFields.mWallpaperForceHidingChanged = true;
-                doRequest = true;
-            }
-            if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
-                mInnerFields.mOrientationChangeComplete = false;
-            } else {
-                mInnerFields.mOrientationChangeComplete = true;
-                if (mWindowsFreezingScreen) {
-                    doRequest = true;
-                }
-            }
-            if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
-                mTurnOnScreen = true;
-            }
 
-            SparseIntArray pendingLayouts = animToLayout.mPendingLayoutChanges;
-            final int count = pendingLayouts.size();
-            if (count > 0) {
-                doRequest = true;
-            }
-            for (int i = 0; i < count; ++i) {
-                final DisplayContent displayContent =
-                        getDisplayContentLocked(pendingLayouts.keyAt(i));
-                if (displayContent != null) {
-                    displayContent.pendingLayoutChanges |= pendingLayouts.valueAt(i);
-                }
-            }
-
-            mWindowDetachedWallpaper = animToLayout.mWindowDetachedWallpaper;
+        final int bulkUpdateParams = mAnimator.mBulkUpdateParams;
+        // TODO(cmautner): As the number of bits grows, use masks of bit groups to
+        //  eliminate unnecessary tests.
+        if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
+            mInnerFields.mUpdateRotation = true;
+            doRequest = true;
         }
+        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
+            mInnerFields.mWallpaperMayChange = true;
+            doRequest = true;
+        }
+        if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
+            mInnerFields.mWallpaperForceHidingChanged = true;
+            doRequest = true;
+        }
+        if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
+            mInnerFields.mOrientationChangeComplete = false;
+        } else {
+            mInnerFields.mOrientationChangeComplete = true;
+            if (mWindowsFreezingScreen) {
+                doRequest = true;
+            }
+        }
+        if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
+            mTurnOnScreen = true;
+        }
+        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_ACTION_PENDING) != 0) {
+            mInnerFields.mWallpaperActionPending = true;
+        }
+
         return doRequest;
     }
 
@@ -9298,7 +9177,7 @@
         }
         return false;
     }
-    
+
     private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
         mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
     }
@@ -9450,7 +9329,7 @@
                 + ", mClientFreezingScreen=" + mClientFreezingScreen);
             return;
         }
-        
+
         mDisplayFrozen = false;
         mH.removeMessages(H.APP_FREEZE_TIMEOUT);
         mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
@@ -9472,7 +9351,7 @@
             if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
                     mTransitionAnimationScale, displayInfo.logicalWidth,
                         displayInfo.logicalHeight)) {
-                updateLayoutToAnimationLocked();
+                scheduleAnimationLocked();
             } else {
                 screenRotationAnimation.kill();
                 screenRotationAnimation = null;
@@ -9668,14 +9547,17 @@
         return mPolicy.hasNavigationBar();
     }
 
+    @Override
     public void lockNow(Bundle options) {
         mPolicy.lockNow(options);
     }
     
+    @Override
     public boolean isSafeModeEnabled() {
         return mSafeMode;
     }
 
+    @Override
     public void showAssistant() {
         // TODO: What permission?
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
@@ -10015,31 +9897,6 @@
             pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
                     pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
             pw.println("  mLayoutToAnim:");
-            pw.print("    mParamsModified="); pw.print(mLayoutToAnim.mParamsModified);
-                    pw.print(" mAnimationScheduled="); pw.print(mLayoutToAnim.mAnimationScheduled);
-                    pw.print(" mChanges=0x");
-                    pw.println(Long.toHexString(mLayoutToAnim.mChanges));
-            pw.print("    mWallpaperTarget="); pw.println(mLayoutToAnim.mWallpaperTarget);
-            if (mLayoutToAnim.mLowerWallpaperTarget != null
-                    || mLayoutToAnim.mUpperWallpaperTarget != null) {
-                pw.print("    mLowerWallpaperTarget=");
-                        pw.println(mLayoutToAnim.mLowerWallpaperTarget);
-                pw.print("    mUpperWallpaperTarget=");
-                        pw.println(mLayoutToAnim.mUpperWallpaperTarget);
-            }
-            for (int i=0; i<mLayoutToAnim.mWinAnimatorLists.size(); i++) {
-                pw.print("    Win Animator List #");
-                        pw.print(mLayoutToAnim.mWinAnimatorLists.keyAt(i)); pw.println(":");
-                WinAnimatorList wanim = mLayoutToAnim.mWinAnimatorLists.valueAt(i);
-                for (int wi=0; wi<wanim.size(); wi++) {
-                    pw.print("      "); pw.println(wanim.get(wi));
-                }
-            }
-            for (int i=0; i<mLayoutToAnim.mWallpaperTokens.size(); i++) {
-                pw.print("    Wallpaper Token #"); pw.print(i); pw.print(": ");
-                        pw.println(mLayoutToAnim.mWallpaperTokens.get(i));
-            }
-            // XXX also need to print mDimParams and mAppWindowAnimParams.  I am lazy.
             mAppTransition.dump(pw);
         }
     }
@@ -10250,6 +10107,7 @@
     }
 
     // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
+    @Override
     public void monitor() {
         synchronized (mWindowMap) { }
     }
@@ -10391,7 +10249,16 @@
      * @return The list of WindowStates on the screen, or null if the there is no screen.
      */
     public WindowList getWindowListLocked(final Display display) {
-        final DisplayContent displayContent = getDisplayContentLocked(display.getDisplayId());
+        return getWindowListLocked(display.getDisplayId());
+    }
+
+    /**
+     * Return the list of WindowStates associated on the passed display.
+     * @param displayId The screen to return windows from.
+     * @return The list of WindowStates on the screen, or null if the there is no screen.
+     */
+    public WindowList getWindowListLocked(final int displayId) {
+        final DisplayContent displayContent = getDisplayContentLocked(displayId);
         return displayContent != null ? displayContent.getWindowList() : null;
     }
 
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 541e859..cc658c2 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -730,7 +730,7 @@
         final AppWindowToken atoken = mAppToken;
         if (atoken != null) {
             return ((!mAttachedHidden && !atoken.hiddenRequested)
-                            || mWinAnimator.mAnimation != null || atoken.mAppAnimator.animation != null);
+                    || mWinAnimator.mAnimation != null || atoken.mAppAnimator.animation != null);
         }
         return !mAttachedHidden || mWinAnimator.mAnimation != null;
     }
@@ -811,6 +811,17 @@
      * Returns true if the window has a surface that it has drawn a
      * complete UI in to.
      */
+    public boolean isDrawFinishedLw() {
+        return mHasSurface && !mDestroying &&
+                (mWinAnimator.mDrawState == WindowStateAnimator.COMMIT_DRAW_PENDING
+                || mWinAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW
+                || mWinAnimator.mDrawState == WindowStateAnimator.HAS_DRAWN);
+    }
+
+    /**
+     * Returns true if the window has a surface that it has drawn a
+     * complete UI in to.
+     */
     public boolean isDrawnLw() {
         return mHasSurface && !mDestroying &&
                 (mWinAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW
@@ -872,8 +883,8 @@
             if (WindowManagerService.DEBUG_ADD_REMOVE) Slog.v(TAG, "Removing " + this + " from " + mAttachedWindow);
             mAttachedWindow.mChildWindows.remove(this);
         }
-        mWinAnimator.destroyDeferredSurfaceLocked(false);
-        mWinAnimator.destroySurfaceLocked(false);
+        mWinAnimator.destroyDeferredSurfaceLocked();
+        mWinAnimator.destroySurfaceLocked();
         mSession.windowRemovedLocked();
         try {
             mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
@@ -974,7 +985,7 @@
             mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_ENTER, true);
         }
         if (requestAnim) {
-            mService.updateLayoutToAnimationLocked();
+            mService.scheduleAnimationLocked();
         }
         return true;
     }
@@ -1017,7 +1028,7 @@
             }
         }
         if (requestAnim) {
-            mService.updateLayoutToAnimationLocked();
+            mService.scheduleAnimationLocked();
         }
         return true;
     }
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 3c9424a..e03e40d 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -226,7 +226,7 @@
             mAnimation.cancel();
             mAnimation = null;
             mLocalAnimating = false;
-            destroySurfaceLocked(true);
+            destroySurfaceLocked();
         }
     }
 
@@ -369,7 +369,7 @@
         final int displayId = mWin.mDisplayContent.getDisplayId();
         mAnimator.setPendingLayoutChanges(displayId, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats(
-                "WindowStateAnimator", mAnimator.mPendingLayoutChanges.get(displayId));
+                "WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId));
 
         if (mWin.mAppToken != null) {
             mWin.mAppToken.updateReportedVisibilityLocked();
@@ -413,7 +413,7 @@
             mService.mPendingRemove.add(mWin);
             mWin.mRemoveOnExit = false;
         }
-        mAnimator.hideWallpapersLocked(mWin, true);
+        mAnimator.hideWallpapersLocked(mWin);
     }
 
     void hide() {
@@ -752,7 +752,7 @@
         return mSurface;
     }
 
-    void destroySurfaceLocked(boolean fromAnimator) {
+    void destroySurfaceLocked() {
         if (mWin.mAppToken != null && mWin == mWin.mAppToken.startingWindow) {
             mWin.mAppToken.startingDisplayed = false;
         }
@@ -802,7 +802,7 @@
                     }
                     mSurface.destroy();
                 }
-                mAnimator.hideWallpapersLocked(mWin, fromAnimator);
+                mAnimator.hideWallpapersLocked(mWin);
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Exception thrown when destroying Window " + this
                     + " surface " + mSurface + " session " + mSession
@@ -816,7 +816,7 @@
         }
     }
 
-    void destroyDeferredSurfaceLocked(boolean fromAnimator) {
+    void destroyDeferredSurfaceLocked() {
         try {
             if (mPendingDestroySurface != null) {
                 if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
@@ -828,7 +828,7 @@
                     WindowManagerService.logSurface(mWin, "DESTROY PENDING", e);
                 }
                 mPendingDestroySurface.destroy();
-                mAnimator.hideWallpapersLocked(mWin, fromAnimator);
+                mAnimator.hideWallpapersLocked(mWin);
             }
         } catch (RuntimeException e) {
             Slog.w(TAG, "Exception thrown when destroying Window "
@@ -849,9 +849,9 @@
 
         // Wallpapers are animated based on the "real" window they
         // are currently targeting.
-        if (mIsWallpaper && mAnimator.mLowerWallpaperTarget == null
-                && mAnimator.mWallpaperTarget != null) {
-            final WindowStateAnimator wallpaperAnimator = mAnimator.mWallpaperTarget.mWinAnimator;
+        if (mIsWallpaper && mService.mLowerWallpaperTarget == null
+                && mService.mWallpaperTarget != null) {
+            final WindowStateAnimator wallpaperAnimator = mService.mWallpaperTarget.mWinAnimator;
             if (wallpaperAnimator.mHasLocalTransformation &&
                     wallpaperAnimator.mAnimation != null &&
                     !wallpaperAnimator.mAnimation.getDetachWallpaper()) {
@@ -860,7 +860,7 @@
                     Slog.v(TAG, "WP target attached xform: " + attachedTransformation);
                 }
             }
-            final AppWindowAnimator wpAppAnimator = mAnimator.mWpAppAnimator;
+            final AppWindowAnimator wpAppAnimator = mAnimator.getWallpaperAppAnimator();
             if (wpAppAnimator != null && wpAppAnimator.hasTransformation
                     && wpAppAnimator.animation != null
                     && !wpAppAnimator.animation.getDetachWallpaper()) {
@@ -986,8 +986,7 @@
                     + " screen=" + (screenAnimation ?
                             screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
             return;
-        } else if (mIsWallpaper &&
-                    (mAnimator.mPendingActions & WindowAnimator.WALLPAPER_ACTION_PENDING) != 0) {
+        } else if (mIsWallpaper && mService.mInnerFields.mWallpaperActionPending) {
             return;
         }
 
@@ -1220,7 +1219,7 @@
             hide();
         } else if (w.mAttachedHidden || !w.isReadyForDisplay()) {
             hide();
-            mAnimator.hideWallpapersLocked(w, true);
+            mAnimator.hideWallpapersLocked(w);
 
             // If we are waiting for this window to handle an
             // orientation change, well, it is hidden, so
@@ -1414,7 +1413,7 @@
             if (DEBUG_SURFACE_TRACE || DEBUG_ANIM)
                 Slog.v(TAG, "performShowLocked: mDrawState=HAS_DRAWN in " + this);
             mDrawState = HAS_DRAWN;
-            mService.updateLayoutToAnimationLocked();
+            mService.scheduleAnimationLocked();
 
             int i = mWin.mChildWindows.size();
             while (i > 0) {
diff --git a/core/tests/coretests/src/android/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
similarity index 98%
rename from core/tests/coretests/src/android/accounts/AccountManagerServiceTest.java
rename to services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 84c9957..00c3a67 100644
--- a/core/tests/coretests/src/android/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-package android.accounts;
+package com.android.server.accounts;
 
+import android.accounts.Account;
+import android.accounts.AuthenticatorDescription;
 import android.app.Notification;
 import android.content.Context;
 import android.content.pm.PackageManager;
diff --git a/core/tests/coretests/src/android/content/ObserverNodeTest.java b/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
similarity index 94%
rename from core/tests/coretests/src/android/content/ObserverNodeTest.java
rename to services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
index 1acff9c..5b70c17 100644
--- a/core/tests/coretests/src/android/content/ObserverNodeTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
@@ -14,18 +14,19 @@
  * limitations under the License.
  */
 
-package android.content;
+package com.android.server.content;
 
 import java.util.ArrayList;
 
-import android.content.ContentService.ObserverCall;
-import android.content.ContentService.ObserverNode;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.UserHandle;
 import android.test.AndroidTestCase;
 
+import com.android.server.content.ContentService.ObserverCall;
+import com.android.server.content.ContentService.ObserverNode;
+
 public class ObserverNodeTest extends AndroidTestCase {
     static class TestObserver  extends ContentObserver {
         public TestObserver() {
diff --git a/core/tests/coretests/src/android/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
similarity index 97%
rename from core/tests/coretests/src/android/content/SyncOperationTest.java
rename to services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
index 1fd25d2..f2772c8 100644
--- a/core/tests/coretests/src/android/content/SyncOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-package android.content;
+package com.android.server;
 
 import android.accounts.Account;
 import android.os.Bundle;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.server.content.SyncOperation;
+
 /**
  * You can run those tests with:
  *
diff --git a/core/tests/coretests/src/android/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
similarity index 98%
rename from core/tests/coretests/src/android/content/SyncStorageEngineTest.java
rename to services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
index 58d2327..8b00f2c 100644
--- a/core/tests/coretests/src/android/content/SyncStorageEngineTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
@@ -14,9 +14,14 @@
  * limitations under the License.
  */
 
-package android.content;
+package com.android.server.content;
 
 import android.accounts.Account;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.PeriodicSync;
 import android.os.Bundle;
 import android.test.AndroidTestCase;
 import android.test.RenamingDelegatingContext;
diff --git a/core/tests/coretests/src/android/app/SearchablesTest.java b/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
similarity index 99%
rename from core/tests/coretests/src/android/app/SearchablesTest.java
rename to services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
index 4d3b144..79b9135 100644
--- a/core/tests/coretests/src/android/app/SearchablesTest.java
+++ b/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.app;
+package com.android.server.search;
 
 import android.app.SearchManager;
 import android.app.SearchableInfo;
@@ -30,7 +30,7 @@
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.os.RemoteException;
-import android.server.search.Searchables;
+import com.android.server.search.Searchables;
 import android.test.AndroidTestCase;
 import android.test.MoreAsserts;
 import android.test.mock.MockContext;
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index 19047c8..4cba70d 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -803,6 +803,10 @@
      */
     public static TextEncodingDetails
     countGsmSeptets(CharSequence s, boolean use7bitOnly) {
+        // Load enabled language tables from config.xml, including any MCC overlays
+        if (!sDisableCountryEncodingCheck) {
+            enableCountrySpecificEncodings();
+        }
         // fast path for common case where no national language shift tables are enabled
         if (sEnabledSingleShiftTables.length + sEnabledLockingShiftTables.length == 0) {
             TextEncodingDetails ted = new TextEncodingDetails();
@@ -989,6 +993,7 @@
      */
     static synchronized void setEnabledSingleShiftTables(int[] tables) {
         sEnabledSingleShiftTables = tables;
+        sDisableCountryEncodingCheck = true;
 
         if (tables.length > 0) {
             sHighestEnabledSingleShiftCode = tables[tables.length - 1];
@@ -1006,6 +1011,7 @@
      */
     static synchronized void setEnabledLockingShiftTables(int[] tables) {
         sEnabledLockingShiftTables = tables;
+        sDisableCountryEncodingCheck = true;
     }
 
     /**
@@ -1030,6 +1036,24 @@
         return sEnabledLockingShiftTables;
     }
 
+    /**
+     * Enable country-specific language tables from MCC-specific overlays.
+     * @context the context to use to get the TelephonyManager
+     */
+    private static void enableCountrySpecificEncodings() {
+        Resources r = Resources.getSystem();
+        // See comments in frameworks/base/core/res/res/values/config.xml for allowed values
+        sEnabledSingleShiftTables = r.getIntArray(R.array.config_sms_enabled_single_shift_tables);
+        sEnabledLockingShiftTables = r.getIntArray(R.array.config_sms_enabled_locking_shift_tables);
+
+        if (sEnabledSingleShiftTables.length > 0) {
+            sHighestEnabledSingleShiftCode =
+                    sEnabledSingleShiftTables[sEnabledSingleShiftTables.length-1];
+        } else {
+            sHighestEnabledSingleShiftCode = 0;
+        }
+    }
+
     /** Reverse mapping from Unicode characters to indexes into language tables. */
     private static final SparseIntArray[] sCharsToGsmTables;
 
@@ -1045,6 +1069,9 @@
     /** Highest language code to include in array of single shift counters. */
     private static int sHighestEnabledSingleShiftCode;
 
+    /** Flag to bypass check for country-specific overlays (for test cases only). */
+    private static boolean sDisableCountryEncodingCheck = false;
+
     /**
      * Septet counter for a specific locking shift table and all of
      * the single shift tables that it can be paired with.
@@ -1408,10 +1435,7 @@
     };
 
     static {
-        Resources r = Resources.getSystem();
-        // See comments in frameworks/base/core/res/res/values/config.xml for allowed values
-        sEnabledSingleShiftTables = r.getIntArray(R.array.config_sms_enabled_single_shift_tables);
-        sEnabledLockingShiftTables = r.getIntArray(R.array.config_sms_enabled_locking_shift_tables);
+        enableCountrySpecificEncodings();
         int numTables = sLanguageTables.length;
         int numShiftTables = sLanguageShiftTables.length;
         if (numTables != numShiftTables) {
@@ -1419,13 +1443,6 @@
                     " != shift tables array length " + numShiftTables);
         }
 
-        if (sEnabledSingleShiftTables.length > 0) {
-            sHighestEnabledSingleShiftCode =
-                    sEnabledSingleShiftTables[sEnabledSingleShiftTables.length-1];
-        } else {
-            sHighestEnabledSingleShiftCode = 0;
-        }
-
         sCharsToGsmTables = new SparseIntArray[numTables];
         for (int i = 0; i < numTables; i++) {
             String table = sLanguageTables[i];
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/BWFilter.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/BWFilter.java
new file mode 100644
index 0000000..4fd63bf
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/BWFilter.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 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.rs.image;
+
+import java.lang.Math;
+
+import android.renderscript.Allocation;
+
+public class BWFilter extends TestBase {
+    private ScriptC_bwfilter mScript;
+
+    public void createTest(android.content.res.Resources res) {
+        mScript = new ScriptC_bwfilter(mRS);
+    }
+
+    public void runTest() {
+        mScript.invoke_prepareBwFilter(50, 50, 50);
+        mScript.forEach_bwFilterKernel(mInPixelsAllocation, mOutPixelsAllocation);
+    }
+
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Contrast.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Contrast.java
new file mode 100644
index 0000000..f3cf1b7
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Contrast.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 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.rs.image;
+
+import java.lang.Math;
+
+import android.renderscript.Allocation;
+
+public class Contrast extends TestBase {
+    private ScriptC_contrast mScript;
+
+    public void createTest(android.content.res.Resources res) {
+        mScript = new ScriptC_contrast(mRS);
+    }
+
+    public void runTest() {
+        mScript.invoke_setBright(50.f);
+        mScript.forEach_contrast(mInPixelsAllocation, mOutPixelsAllocation);
+    }
+
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Exposure.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Exposure.java
new file mode 100644
index 0000000..bec53ab
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Exposure.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 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.rs.image;
+
+import java.lang.Math;
+
+import android.renderscript.Allocation;
+
+public class Exposure extends TestBase {
+    private ScriptC_exposure mScript;
+
+    public void createTest(android.content.res.Resources res) {
+        mScript = new ScriptC_exposure(mRS);
+    }
+
+    public void runTest() {
+        mScript.invoke_setBright(50.f);
+        mScript.forEach_exposure(mInPixelsAllocation, mOutPixelsAllocation);
+    }
+
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 90fa74f..ac72688 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -273,9 +273,27 @@
         case 29:
             mTest = new Blur25G();
             break;
+        case 30:
+            mTest = new Vibrance();
+            break;
+        case 31:
+            mTest = new BWFilter();
+            break;
+        case 32:
+            mTest = new Shadows();
+            break;
+        case 33:
+            mTest = new Contrast();
+            break;
+        case 34:
+            mTest = new Exposure();
+            break;
+        case 35:
+            mTest = new WhiteBalance();
+            break;
         }
 
-        mTest.createBaseTest(this, mBitmapIn, mBitmapIn2);
+        mTest.createBaseTest(this, mBitmapIn, mBitmapIn2, mBitmapOut);
         setupBars();
 
         mTest.runTest();
@@ -284,7 +302,7 @@
     }
 
     void setupTests() {
-        mTestNames = new String[30];
+        mTestNames = new String[36];
         mTestNames[0] = "Levels Vec3 Relaxed";
         mTestNames[1] = "Levels Vec4 Relaxed";
         mTestNames[2] = "Levels Vec3 Full";
@@ -315,6 +333,12 @@
         mTestNames[27] = "Mandelbrot";
         mTestNames[28] = "Intrinsics Blend";
         mTestNames[29] = "Intrinsics Blur 25 uchar";
+        mTestNames[30] = "Vibrance";
+        mTestNames[31] = "BW Filter";
+        mTestNames[32] = "Shadows";
+        mTestNames[33] = "Contrast";
+        mTestNames[34] = "Exposure";
+        mTestNames[35] = "White Balance";
 
         mTestSpinner.setAdapter(new ArrayAdapter<String>(
             this, R.layout.spinner_layout, mTestNames));
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Shadows.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Shadows.java
new file mode 100644
index 0000000..98ab15f
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Shadows.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 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.rs.image;
+
+import java.lang.Math;
+
+import android.renderscript.Allocation;
+
+public class Shadows extends TestBase {
+    private ScriptC_shadows mScript;
+
+    public void createTest(android.content.res.Resources res) {
+        mScript = new ScriptC_shadows(mRS);
+    }
+
+    public void runTest() {
+        mScript.invoke_prepareShadows(50.f);
+        mScript.forEach_shadowsKernel(mInPixelsAllocation, mOutPixelsAllocation);
+    }
+
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
index d4c4898..abe2e83 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
@@ -106,7 +106,7 @@
         return false;
     }
 
-    public final void createBaseTest(ImageProcessingActivity ipact, Bitmap b, Bitmap b2) {
+    public final void createBaseTest(ImageProcessingActivity ipact, Bitmap b, Bitmap b2, Bitmap outb) {
         act = ipact;
         mRS = RenderScript.create(act);
         mRS.setMessageHandler(new MessageProcessor(act));
@@ -117,7 +117,7 @@
         mInPixelsAllocation2 = Allocation.createFromBitmap(mRS, b2,
                                                           Allocation.MipmapControl.MIPMAP_NONE,
                                                           Allocation.USAGE_SCRIPT);
-        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, b,
+        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, outb,
                                                            Allocation.MipmapControl.MIPMAP_NONE,
                                                            Allocation.USAGE_SCRIPT);
         createTest(act.getResources());
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Vibrance.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Vibrance.java
new file mode 100644
index 0000000..0bc1ff7
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Vibrance.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 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.rs.image;
+
+import java.lang.Math;
+
+import android.renderscript.Allocation;
+
+public class Vibrance extends TestBase {
+    private ScriptC_vibrance mScript;
+
+    public void createTest(android.content.res.Resources res) {
+        mScript = new ScriptC_vibrance(mRS);
+    }
+
+    public void runTest() {
+        mScript.set_vibrance(50.f);
+        mScript.invoke_prepareVibrance();
+        mScript.forEach_vibranceKernel(mInPixelsAllocation, mOutPixelsAllocation);
+    }
+
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/WhiteBalance.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/WhiteBalance.java
new file mode 100644
index 0000000..a836067
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/WhiteBalance.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 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.rs.image;
+
+import java.lang.Math;
+
+import android.renderscript.Allocation;
+
+public class WhiteBalance extends TestBase {
+    private ScriptC_wbalance mScript;
+
+    public void createTest(android.content.res.Resources res) {
+        mScript = new ScriptC_wbalance(mRS);
+    }
+
+    public void runTest() {
+        mScript.set_histogramSource(mInPixelsAllocation);
+        mScript.set_histogramWidth(mInPixelsAllocation.getType().getX());
+        mScript.set_histogramHeight(mInPixelsAllocation.getType().getY());
+        mScript.invoke_prepareWhiteBalance();
+        mScript.forEach_whiteBalanceKernel(mInPixelsAllocation, mOutPixelsAllocation);
+    }
+
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/bwfilter.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/bwfilter.rs
new file mode 100644
index 0000000..2818bf5
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/bwfilter.rs
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+#pragma rs_fp_relaxed
+
+static float sr = 0.f;
+static float sg = 0.f;
+static float sb = 0.f;
+
+void prepareBwFilter(uint32_t rw, uint32_t gw, uint32_t bw) {
+
+    sr = rw;
+    sg = gw;
+    sb = bw;
+
+    float imageMin = min(sg,sb);
+    imageMin = fmin(sr,imageMin);
+    float imageMax = max(sg,sb);
+    imageMax = fmax(sr,imageMax);
+    float avg = (imageMin + imageMax)/2;
+    sb /= avg;
+    sg /= avg;
+    sr /= avg;
+
+}
+
+void bwFilterKernel(const uchar4 *in, uchar4 *out) {
+    float r = in->r * sr;
+    float g = in->g * sg;
+    float b = in->b * sb;
+    float localMin, localMax, avg;
+    localMin = fmin(g,b);
+    localMin = fmin(r,localMin);
+    localMax = fmax(g,b);
+    localMax = fmax(r,localMax);
+    avg = (localMin+localMax) * 0.5f;
+    out->r = out->g = out->b = rsClamp(avg, 0, 255);
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/contrast.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/contrast.rs
new file mode 100644
index 0000000..5fd7be1
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/contrast.rs
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+#pragma rs_fp_full
+
+static float brightM = 0.f;
+static float brightC = 0.f;
+
+void setBright(float v) {
+    brightM = pow(2.f, v / 100.f);
+    brightC = 127.f - brightM * 127.f;
+}
+
+void contrast(const uchar4 *in, uchar4 *out)
+{
+#if 0
+    out->r = rsClamp((int)(brightM * in->r + brightC), 0, 255);
+    out->g = rsClamp((int)(brightM * in->g + brightC), 0, 255);
+    out->b = rsClamp((int)(brightM * in->b + brightC), 0, 255);
+#else
+    float3 v = convert_float3(in->rgb) * brightM + brightC;
+    out->rgb = convert_uchar3(clamp(v, 0.f, 255.f));
+#endif
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/exposure.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/exposure.rs
new file mode 100644
index 0000000..adfae4a
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/exposure.rs
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+#pragma rs_fp_full
+
+static float bright = 0.f;
+
+void setBright(float v) {
+    bright = 255.f / (255.f - v);
+}
+
+void exposure(const uchar4 *in, uchar4 *out)
+{
+    out->r = rsClamp((int)(bright * in->r), 0, 255);
+    out->g = rsClamp((int)(bright * in->g), 0, 255);
+    out->b = rsClamp((int)(bright * in->b), 0, 255);
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/shadows.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/shadows.rs
new file mode 100644
index 0000000..81cb9d0
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/shadows.rs
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+#pragma rs_fp_relaxed
+
+static double shadowFilterMap[] = {
+    -0.00591,  0.0001,
+     1.16488,  0.01668,
+    -0.18027, -0.06791,
+    -0.12625,  0.09001,
+     0.15065, -0.03897
+};
+
+static double poly[] = {
+    0., 0.,
+    0., 0.,
+    0.
+};
+
+static const int ABITS = 4;
+static const int HSCALE = 256;
+static const int k1=255 << ABITS;
+static const int k2=HSCALE << ABITS;
+
+static double fastevalPoly(double *poly,int n, double x){
+
+    double f =x;
+    double sum = poly[0]+poly[1]*f;
+    int i;
+    for (i = 2; i < n; i++) {
+        f*=x;
+        sum += poly[i]*f;
+    }
+    return sum;
+}
+
+static ushort3 rgb2hsv( uchar4 rgb)
+{
+    int iMin,iMax,chroma;
+
+    int ri = rgb.r;
+    int gi = rgb.g;
+    int bi = rgb.b;
+    short rv,rs,rh;
+
+    if (ri > gi) {
+        iMax = max (ri, bi);
+        iMin = min (gi, bi);
+    } else {
+        iMax = max (gi, bi);
+        iMin = min (ri, bi);
+    }
+
+    chroma = iMax - iMin;
+    // set value
+    rv = (short)( iMax << ABITS);
+
+    // set saturation
+    if (rv == 0)
+        rs = 0;
+    else
+        rs = (short)((k1*chroma)/iMax);
+
+    // set hue
+    if (rs == 0)
+        rh = 0;
+    else {
+        if ( ri == iMax ) {
+            rh  = (short)( (k2*(6*chroma+gi - bi))/(6*chroma));
+            if (rh >= k2) rh -= k2;
+        } else if (gi  == iMax)
+            rh  = (short)( (k2*(2*chroma+bi - ri ))/(6*chroma));
+        else // (bi == iMax )
+                    rh  = (short)( (k2*(4*chroma+ri - gi ))/(6*chroma));
+    }
+
+    ushort3 out;
+    out.x = rv;
+    out.y = rs;
+    out.z = rh;
+    return out;
+}
+
+static uchar4 hsv2rgb(ushort3 hsv)
+{
+    int ABITS = 4;
+    int HSCALE = 256;
+    int m;
+    int H,X,ih,is,iv;
+    int k1=255<<ABITS;
+    int k2=HSCALE<<ABITS;
+    int k3=1<<(ABITS-1);
+    int rr=0;
+    int rg=0;
+    int rb=0;
+    short cv = hsv.x;
+    short cs = hsv.y;
+    short ch = hsv.z;
+
+    // set chroma and min component value m
+    //chroma = ( cv * cs )/k1;
+    //m = cv - chroma;
+    m = ((int)cv*(k1 - (int)cs ))/k1;
+
+    // chroma  == 0 <-> cs == 0 --> m=cv
+    if (cs == 0) {
+        rb = ( rg = ( rr =( cv >> ABITS) ));
+    } else {
+        ih=(int)ch;
+        is=(int)cs;
+        iv=(int)cv;
+
+        H = (6*ih)/k2;
+        X = ((iv*is)/k2)*(k2- abs(6*ih- 2*(H>>1)*k2 - k2)) ;
+
+        // removing additional bits --> unit8
+        X=( (X+iv*(k1 - is ))/k1 + k3 ) >> ABITS;
+        m=m >> ABITS;
+
+        // ( chroma + m ) --> cv ;
+        cv=(short) (cv >> ABITS);
+        switch (H) {
+        case 0:
+            rr = cv;
+            rg = X;
+            rb = m;
+            break;
+        case 1:
+            rr = X;
+            rg = cv;
+            rb = m;
+            break;
+        case 2:
+            rr = m;
+            rg = cv;
+            rb = X;
+            break;
+        case 3:
+            rr = m;
+            rg = X;
+            rb = cv;
+            break;
+        case 4:
+            rr = X;
+            rg = m;
+            rb = cv;
+            break;
+        case 5:
+            rr = cv;
+            rg = m ;
+            rb = X;
+            break;
+        }
+    }
+
+    uchar4 rgb;
+
+    rgb.r =  rr;
+    rgb.g =  rg;
+    rgb.b =  rb;
+
+    return rgb;
+}
+
+void prepareShadows(float scale) {
+    double s = (scale>=0)?scale:scale/5;
+    for (int i = 0; i < 5; i++) {
+        poly[i] = fastevalPoly(shadowFilterMap+i*2,2 , s);
+    }
+}
+
+void shadowsKernel(const uchar4 *in, uchar4 *out) {
+    ushort3 hsv = rgb2hsv(*in);
+    double v = (fastevalPoly(poly,5,hsv.x/4080.)*4080);
+    if (v>4080) v = 4080;
+    hsv.x = (unsigned short) ((v>0)?v:0);
+    *out = hsv2rgb(hsv);
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vibrance.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vibrance.rs
new file mode 100644
index 0000000..677e857
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vibrance.rs
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+#pragma rs_fp_relaxed
+
+float vibrance = 0.f;
+
+static const float Rf = 0.2999f;
+static const float Gf = 0.587f;
+static const float Bf = 0.114f;
+
+static float S  = 0.f;
+static float MS = 0.f;
+static float Rt = 0.f;
+static float Gt = 0.f;
+static float Bt = 0.f;
+static float Vib = 0.f;
+
+void vibranceKernel(const uchar4 *in, uchar4 *out) {
+
+    float R, G, B;
+
+    int r = in->r;
+    int g = in->g;
+    int b = in->b;
+    float red = (r-max(g, b))/256.f;
+    float sx = (float)(Vib/(1+exp(-red*3)));
+    S = sx+1;
+    MS = 1.0f - S;
+    Rt = Rf * MS;
+    Gt = Gf * MS;
+    Bt = Bf * MS;
+    int t = (r + g) / 2;
+    R = r;
+    G = g;
+    B = b;
+
+    float Rc = R * (Rt + S) + G * Gt + B * Bt;
+    float Gc = R * Rt + G * (Gt + S) + B * Bt;
+    float Bc = R * Rt + G * Gt + B * (Bt + S);
+
+    out->r = rsClamp(Rc, 0, 255);
+    out->g = rsClamp(Gc, 0, 255);
+    out->b = rsClamp(Bc, 0, 255);
+
+}
+
+void prepareVibrance() {
+
+    Vib = vibrance/100.f;
+    S  = Vib + 1;
+    MS = 1.0f - S;
+    Rt = Rf * MS;
+    Gt = Gf * MS;
+    Bt = Bf * MS;
+
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/wbalance.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/wbalance.rs
new file mode 100644
index 0000000..b9c28fc
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/wbalance.rs
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+#pragma rs_fp_relaxed
+
+static int histR[256] = {0}, histG[256] = {0}, histB[256] = {0};
+
+rs_allocation histogramSource;
+uint32_t histogramHeight;
+uint32_t histogramWidth;
+
+static float scaleR;
+static float scaleG;
+static float scaleB;
+
+static uchar4 estimateWhite() {
+
+    for (int i = 0; i < 256; i++) {
+        histR[i] = 0; histG[i] = 0; histB[i] = 0;
+    }
+
+    for (uint32_t i = 0; i < histogramHeight; i++) {
+        for (uint32_t j = 0; j < histogramWidth; j++) {
+            uchar4 in = rsGetElementAt_uchar4(histogramSource, j, i);
+            histR[in.r]++;
+            histG[in.g]++;
+            histB[in.b]++;
+        }
+    }
+
+    int min_r = -1, min_g = -1, min_b = -1;
+    int max_r =  0, max_g =  0, max_b =  0;
+    int sum_r =  0, sum_g =  0, sum_b =  0;
+
+    for (int i = 1; i < 255; i++) {
+        int r = histR[i];
+        int g = histG[i];
+        int b = histB[i];
+        sum_r += r;
+        sum_g += g;
+        sum_b += b;
+
+        if (r>0){
+            if (min_r < 0) min_r = i;
+            max_r = i;
+        }
+        if (g>0){
+            if (min_g < 0) min_g = i;
+            max_g = i;
+        }
+        if (b>0){
+            if (min_b < 0) min_b = i;
+            max_b = i;
+        }
+    }
+
+    int sum15r = 0, sum15g = 0, sum15b = 0;
+    int count15r = 0, count15g = 0, count15b = 0;
+    int tmp_r = 0, tmp_g = 0, tmp_b = 0;
+
+    for (int i = 254; i >0; i--) {
+        int r = histR[i];
+        int g = histG[i];
+        int b = histB[i];
+        tmp_r += r;
+        tmp_g += g;
+        tmp_b += b;
+
+        if ((tmp_r > sum_r/20) && (tmp_r < sum_r/5)) {
+            sum15r += r*i;
+            count15r += r;
+        }
+        if ((tmp_g > sum_g/20) && (tmp_g < sum_g/5)) {
+            sum15g += g*i;
+            count15g += g;
+        }
+        if ((tmp_b > sum_b/20) && (tmp_b < sum_b/5)) {
+            sum15b += b*i;
+            count15b += b;
+        }
+
+    }
+
+    uchar4 out;
+
+    if ((count15r>0) && (count15g>0) && (count15b>0) ){
+        out.r = sum15r/count15r;
+        out.g = sum15g/count15g;
+        out.b = sum15b/count15b;
+    }else {
+        out.r = out.g = out.b = 255;
+    }
+
+    return out;
+
+}
+
+void prepareWhiteBalance() {
+    uchar4 estimation = estimateWhite();
+    int minimum = min(estimation.r, min(estimation.g, estimation.b));
+    int maximum = max(estimation.r, max(estimation.g, estimation.b));
+    float avg = (minimum + maximum) / 2.f;
+
+    scaleR =  avg/estimation.r;
+    scaleG =  avg/estimation.g;
+    scaleB =  avg/estimation.b;
+
+}
+
+static unsigned char contrastClamp(int c)
+{
+    int N = 255;
+    c &= ~(c >> 31);
+    c -= N;
+    c &= (c >> 31);
+    c += N;
+    return  (unsigned char) c;
+}
+
+void whiteBalanceKernel(const uchar4 *in, uchar4 *out) {
+    float Rc =  in->r*scaleR;
+    float Gc =  in->g*scaleG;
+    float Bc =  in->b*scaleB;
+
+    out->r = contrastClamp(Rc);
+    out->g = contrastClamp(Gc);
+    out->b = contrastClamp(Bc);
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
index 7662007..8645ae5 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
@@ -84,6 +84,7 @@
         unitTests.add(new UT_alloc(this, mRes, mCtx));
         unitTests.add(new UT_refcount(this, mRes, mCtx));
         unitTests.add(new UT_foreach(this, mRes, mCtx));
+        unitTests.add(new UT_foreach_bounds(this, mRes, mCtx));
         unitTests.add(new UT_noroot(this, mRes, mCtx));
         unitTests.add(new UT_atomic(this, mRes, mCtx));
         unitTests.add(new UT_struct(this, mRes, mCtx));
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java
new file mode 100644
index 0000000..bda055b
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 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.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_foreach_bounds extends UnitTest {
+    private Resources mRes;
+    private Allocation A;
+
+    protected UT_foreach_bounds(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "ForEach (bounds)", ctx);
+        mRes = res;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_foreach_bounds s) {
+        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
+        int X = 5;
+        int Y = 7;
+        s.set_dimX(X);
+        s.set_dimY(Y);
+        typeBuilder.setX(X).setY(Y);
+        A = Allocation.createTyped(RS, typeBuilder.create());
+        s.bind_a(A);
+        s.set_s(s);
+        s.set_ain(A);
+        s.set_aout(A);
+        s.set_xStart(2);
+        s.set_xEnd(5);
+        s.set_yStart(3);
+        s.set_yEnd(6);
+        s.forEach_zero(A);
+
+        return;
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_foreach_bounds s = new ScriptC_foreach_bounds(pRS);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_foreach_bounds_test();
+        pRS.finish();
+        waitForMessage();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs
new file mode 100644
index 0000000..ddf17f8
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs
@@ -0,0 +1,71 @@
+#include "shared.rsh"
+
+int *a;
+int dimX;
+int dimY;
+int xStart = 0;
+int xEnd = 0;
+int yStart = 0;
+int yEnd = 0;
+
+rs_script s;
+rs_allocation ain;
+rs_allocation aout;
+
+void root(int *out, uint32_t x, uint32_t y) {
+    *out = x + y * dimX;
+}
+
+int __attribute__((kernel)) zero() {
+    return 0;
+}
+
+static bool test_root_output() {
+    bool failed = false;
+    int i, j;
+
+    for (j = 0; j < dimY; j++) {
+        for (i = 0; i < dimX; i++) {
+            rsDebug("i: ", i);
+            rsDebug("j: ", j);
+            rsDebug("a[j][i]: ", a[i + j * dimX]);
+            if (i < xStart || i >= xEnd || j < yStart || j >= yEnd) {
+                _RS_ASSERT(a[i + j * dimX] == 0);
+            } else {
+                _RS_ASSERT(a[i + j * dimX] == (i + j * dimX));
+            }
+        }
+    }
+
+    if (failed) {
+        rsDebug("test_root_output FAILED", 0);
+    }
+    else {
+        rsDebug("test_root_output PASSED", 0);
+    }
+
+    return failed;
+}
+
+void foreach_bounds_test() {
+    static bool failed = false;
+
+    rs_script_call_t rssc = {0};
+    rssc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
+    rssc.xStart = xStart;
+    rssc.xEnd = xEnd;
+    rssc.yStart = yStart;
+    rssc.yEnd = yEnd;
+
+    rsForEach(s, ain, aout, NULL, 0, &rssc);
+
+    failed |= test_root_output();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index 7d71539..ad52585 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -26,6 +26,7 @@
 /**
  * A class representing a Wi-Fi p2p device
  *
+ * Note that the operations are not thread safe
  * {@see WifiP2pManager}
  */
 public class WifiP2pDevice implements Parcelable {
@@ -260,9 +261,29 @@
         return (groupCapability & GROUP_CAPAB_GROUP_LIMIT) != 0;
     }
 
-    /** @hide */
+    /**
+     * Update device details. This will be throw an exception if the device address
+     * does not match.
+     * @param device to be updated
+     * @throws IllegalArgumentException if the device is null or device address does not match
+     * @hide
+     */
     public void update(WifiP2pDevice device) {
-        if (device == null || device.deviceAddress == null) return;
+        updateSupplicantDetails(device);
+        status = device.status;
+    }
+
+    /** Updates details obtained from supplicant @hide */
+    void updateSupplicantDetails(WifiP2pDevice device) {
+        if (device == null) {
+            throw new IllegalArgumentException("device is null");
+        }
+        if (device.deviceAddress == null) {
+            throw new IllegalArgumentException("deviceAddress is null");
+        }
+        if (!deviceAddress.equals(device.deviceAddress)) {
+            throw new IllegalArgumentException("deviceAddress does not match");
+        }
         deviceName = device.deviceName;
         primaryDeviceType = device.primaryDeviceType;
         secondaryDeviceType = device.secondaryDeviceType;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
index f14c305..f7bceac 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
@@ -58,16 +58,28 @@
         }
     }
 
-    /** @hide */
+    /** Clear the list @hide */
     public boolean clear() {
         if (mDevices.isEmpty()) return false;
         mDevices.clear();
         return true;
     }
 
-    /** @hide */
+    /**
+     * Add/update a device to the list. If the device is not found, a new device entry
+     * is created. If the device is already found, the device details are updated
+     * @param device to be updated
+     * @hide
+     */
     public void update(WifiP2pDevice device) {
         if (device == null || device.deviceAddress == null) return;
+        updateSupplicantDetails(device);
+        mDevices.get(device.deviceAddress).status = device.status;
+    }
+
+    /** Only updates details fetched from the supplicant @hide */
+    void updateSupplicantDetails(WifiP2pDevice device) {
+        if (device == null || device.deviceAddress == null) return;
         WifiP2pDevice d = mDevices.get(device.deviceAddress);
         if (d != null) {
             d.deviceName = device.deviceName;
@@ -84,7 +96,7 @@
     }
 
     /** @hide */
-    public void updateGroupCapability(String deviceAddress, int groupCapab) {
+    void updateGroupCapability(String deviceAddress, int groupCapab) {
         if (TextUtils.isEmpty(deviceAddress)) return;
         WifiP2pDevice d = mDevices.get(deviceAddress);
         if (d != null) {
@@ -93,7 +105,7 @@
     }
 
     /** @hide */
-    public void updateStatus(String deviceAddress, int status) {
+    void updateStatus(String deviceAddress, int status) {
         if (TextUtils.isEmpty(deviceAddress)) return;
         WifiP2pDevice d = mDevices.get(deviceAddress);
         if (d != null) {
@@ -101,7 +113,11 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Fetch a device from the list
+     * @param deviceAddress is the address of the device
+     * @return WifiP2pDevice device found, or null if none found
+     */
     public WifiP2pDevice get(String deviceAddress) {
         if (deviceAddress == null) return null;
 
@@ -114,6 +130,17 @@
         return mDevices.remove(device.deviceAddress) != null;
     }
 
+    /**
+     * Remove a device from the list
+     * @param deviceAddress is the address of the device
+     * @return WifiP2pDevice device removed, or null if none removed
+     * @hide
+     */
+    public WifiP2pDevice remove(String deviceAddress) {
+        if (deviceAddress == null) return null;
+        return mDevices.remove(deviceAddress);
+    }
+
     /** Returns true if any device the list was removed @hide */
     public boolean remove(WifiP2pDeviceList list) {
         boolean ret = false;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index cf7604d..ca737f9 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -27,7 +27,9 @@
 import java.util.regex.Matcher;
 
 /**
- * A class representing a Wi-Fi P2p group
+ * A class representing a Wi-Fi P2p group. A p2p group consists of a single group
+ * owner and one or more clients. In the case of a group with only two devices, one
+ * will be the group owner and the other will be a group client.
  *
  * {@see WifiP2pManager}
  */
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 6edc232..5bd0349 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -29,7 +29,6 @@
 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceResponse;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Handler;
 import android.os.Looper;
@@ -172,10 +171,12 @@
      * Broadcast intent action indicating that the state of Wi-Fi p2p connectivity
      * has changed. One extra {@link #EXTRA_WIFI_P2P_INFO} provides the p2p connection info in
      * the form of a {@link WifiP2pInfo} object. Another extra {@link #EXTRA_NETWORK_INFO} provides
-     * the network info in the form of a {@link android.net.NetworkInfo}.
+     * the network info in the form of a {@link android.net.NetworkInfo}. A third extra provides
+     * the details of the group.
      *
      * @see #EXTRA_WIFI_P2P_INFO
      * @see #EXTRA_NETWORK_INFO
+     * @see #EXTRA_WIFI_P2P_GROUP
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String WIFI_P2P_CONNECTION_CHANGED_ACTION =
@@ -189,41 +190,46 @@
 
     /**
      * The lookup key for a {@link android.net.NetworkInfo} object associated with the
-     * Wi-Fi network. Retrieve with
+     * p2p network. Retrieve with
      * {@link android.content.Intent#getParcelableExtra(String)}.
      */
     public static final String EXTRA_NETWORK_INFO = "networkInfo";
 
     /**
-     * The lookup key for a {@link android.net.LinkProperties} object associated with the
-     * network. Retrieve with
+     * The lookup key for a {@link android.net.wifi.p2p.WifiP2pGroup} object
+     * associated with the p2p network. Retrieve with
      * {@link android.content.Intent#getParcelableExtra(String)}.
-     * @hide
      */
-    public static final String EXTRA_LINK_PROPERTIES = "linkProperties";
+    public static final String EXTRA_WIFI_P2P_GROUP = "p2pGroupInfo";
 
     /**
-     * The lookup key for a {@link android.net.LinkCapabilities} object associated with the
-     * network. Retrieve with
-     * {@link android.content.Intent#getParcelableExtra(String)}.
-     * @hide
-     */
-    public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities";
-
-    /**
-     * Broadcast intent action indicating that the available peer list has changed. Fetch
-     * the changed list of peers with {@link #requestPeers}
+     * Broadcast intent action indicating that the available peer list has changed. This
+     * can be sent as a result of peers being found, lost or updated.
+     *
+     * <p> An extra {@link #EXTRA_P2P_DEVICE_LIST} provides the full list of
+     * current peers. The full list of peers can also be obtained any time with
+     * {@link #requestPeers}.
+     *
+     * @see #EXTRA_P2P_DEVICE_LIST
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String WIFI_P2P_PEERS_CHANGED_ACTION =
         "android.net.wifi.p2p.PEERS_CHANGED";
 
+     /**
+      * The lookup key for a {@link android.net.wifi.p2p.WifiP2pDeviceList} object representing
+      * the new peer list when {@link #WIFI_P2P_PEERS_CHANGED_ACTION} broadcast is sent.
+      *
+      * <p>Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
+      */
+     public static final String EXTRA_P2P_DEVICE_LIST = "wifiP2pDeviceList";
+
     /**
      * Broadcast intent action indicating that peer discovery has either started or stopped.
      * One extra {@link #EXTRA_DISCOVERY_STATE} indicates whether discovery has started
      * or stopped.
      *
-     * Note that discovery will be stopped during a connection setup. If the application tries
+     * <p>Note that discovery will be stopped during a connection setup. If the application tries
      * to re-initiate discovery during this time, it can fail.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -273,41 +279,6 @@
     public static final String WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION =
         "android.net.wifi.p2p.PERSISTENT_GROUPS_CHANGED";
 
-    /**
-     * The lookup key for a {@link #String} object.
-     * Retrieve with {@link android.os.Bundle#getString(String)}.
-     * @hide
-     */
-    public static final String APP_PKG_BUNDLE_KEY = "appPkgName";
-
-    /**
-     * The lookup key for a {@link #Boolean} object.
-     * Retrieve with {@link android.os.Bundle#getBoolean(String)}.
-     * @hide
-     */
-    public static final String RESET_DIALOG_LISTENER_BUNDLE_KEY = "dialogResetFlag";
-
-    /**
-     * The lookup key for a {@link #String} object.
-     * Retrieve with {@link android.os.Bundle#getString(String)}.
-     * @hide
-     */
-    public static final String WPS_PIN_BUNDLE_KEY = "wpsPin";
-
-    /**
-     * The lookup key for a {@link android.net.wifi.p2p.WifiP2pDevice} object
-     * Retrieve with {@link android.os.Bundle#getParcelable(String)}.
-     * @hide
-     */
-    public static final String P2P_DEV_BUNDLE_KEY = "wifiP2pDevice";
-
-    /**
-     * The lookup key for a {@link android.net.wifi.p2p.WifiP2pConfig} object
-     * Retrieve with {@link android.os.Bundle#getParcelable(String)}.
-     * @hide
-     */
-    public static final String P2P_CONFIG_BUNDLE_KEY = "wifiP2pConfig";
-
     IWifiP2pManager mService;
 
     private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER;
@@ -432,35 +403,23 @@
     public static final int SET_DEVICE_NAME_SUCCEEDED               = BASE + 53;
 
     /** @hide */
-    public static final int SET_DIALOG_LISTENER                     = BASE + 54;
+    public static final int DELETE_PERSISTENT_GROUP                 = BASE + 54;
     /** @hide */
-    public static final int DIALOG_LISTENER_DETACHED                = BASE + 55;
+    public static final int DELETE_PERSISTENT_GROUP_FAILED          = BASE + 55;
     /** @hide */
-    public static final int DIALOG_LISTENER_ATTACHED                = BASE + 56;
+    public static final int DELETE_PERSISTENT_GROUP_SUCCEEDED       = BASE + 56;
 
     /** @hide */
-    public static final int CONNECTION_REQUESTED                    = BASE + 57;
+    public static final int REQUEST_PERSISTENT_GROUP_INFO           = BASE + 57;
     /** @hide */
-    public static final int SHOW_PIN_REQUESTED                      = BASE + 58;
+    public static final int RESPONSE_PERSISTENT_GROUP_INFO          = BASE + 58;
 
     /** @hide */
-    public static final int DELETE_PERSISTENT_GROUP                 = BASE + 59;
+    public static final int SET_WFD_INFO                            = BASE + 59;
     /** @hide */
-    public static final int DELETE_PERSISTENT_GROUP_FAILED          = BASE + 60;
+    public static final int SET_WFD_INFO_FAILED                     = BASE + 60;
     /** @hide */
-    public static final int DELETE_PERSISTENT_GROUP_SUCCEEDED       = BASE + 61;
-
-    /** @hide */
-    public static final int REQUEST_PERSISTENT_GROUP_INFO           = BASE + 62;
-    /** @hide */
-    public static final int RESPONSE_PERSISTENT_GROUP_INFO          = BASE + 63;
-
-    /** @hide */
-    public static final int SET_WFD_INFO                            = BASE + 64;
-    /** @hide */
-    public static final int SET_WFD_INFO_FAILED                     = BASE + 65;
-    /** @hide */
-    public static final int SET_WFD_INFO_SUCCEEDED                  = BASE + 66;
+    public static final int SET_WFD_INFO_SUCCEEDED                  = BASE + 61;
 
     /**
      * Create a new WifiP2pManager instance. Applications use
@@ -501,14 +460,6 @@
      */
     public static final int NO_SERVICE_REQUESTS = 3;
 
-    /**
-     * Passed with {@link DialogListener#onDetached}.
-     * Indicates that the registered listener was detached from the system because
-     * the application went into background.
-     * @hide
-     */
-    public static final int NOT_IN_FOREGROUND   = 4;
-
     /** Interface for callback invocation when framework channel is lost */
     public interface ChannelListener {
         /**
@@ -640,49 +591,6 @@
     }
 
 
-    /**
-     * Interface for callback invocation when dialog events are received.
-     * see {@link #setDialogListener}.
-     * @hide
-     */
-    public interface DialogListener {
-
-        /**
-         * Called by the system when a request to show WPS pin is received.
-         *
-         * @param pin WPS pin.
-         */
-        public void onShowPinRequested(String pin);
-
-        /**
-         * Called by the system when a request to establish the connection is received.
-         *
-         * Application can then call {@link #connect} with the given config if the request
-         * is acceptable.
-         *
-         * @param device the source device.
-         * @param config p2p configuration.
-         */
-        public void onConnectionRequested(WifiP2pDevice device, WifiP2pConfig config);
-
-        /**
-         * Called by the system when this listener was attached to the system.
-         */
-        public void onAttached();
-
-        /**
-         * Called by the system when this listener was detached from the system or
-         * failed to attach.
-         *
-         * Application can request again using {@link #setDialogListener} when it is
-         * in the foreground.
-         *
-         * @param reason The reason for failure could be one of {@link #ERROR},
-         * {@link #BUSY}, {@link #P2P_UNSUPPORTED} or {@link #NOT_IN_FOREGROUND}
-         */
-        public void onDetached(int reason);
-    }
-
     /** Interface for callback invocation when stored group info list is available {@hide}*/
     public interface PersistentGroupInfoListener {
         /**
@@ -713,7 +621,6 @@
         private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
         private Object mListenerMapLock = new Object();
         private int mListenerKey = 0;
-        private DialogListener mDialogListener;
 
         private AsyncChannel mAsyncChannel;
         private P2pHandler mHandler;
@@ -797,34 +704,6 @@
                         WifiP2pServiceResponse resp = (WifiP2pServiceResponse) message.obj;
                         handleServiceResponse(resp);
                         break;
-                    case WifiP2pManager.CONNECTION_REQUESTED:
-                        if (mDialogListener != null) {
-                            Bundle bundle = message.getData();
-                            mDialogListener.onConnectionRequested(
-                                    (WifiP2pDevice)bundle.getParcelable(
-                                            P2P_DEV_BUNDLE_KEY),
-                                    (WifiP2pConfig)bundle.getParcelable(
-                                            P2P_CONFIG_BUNDLE_KEY));
-                        }
-                        break;
-                    case WifiP2pManager.SHOW_PIN_REQUESTED:
-                        if (mDialogListener != null) {
-                            Bundle bundle = message.getData();
-                            mDialogListener.onShowPinRequested(
-                                    bundle.getString(WPS_PIN_BUNDLE_KEY));
-                        }
-                        break;
-                    case WifiP2pManager.DIALOG_LISTENER_ATTACHED:
-                        if (mDialogListener != null) {
-                            mDialogListener.onAttached();
-                        }
-                        break;
-                    case WifiP2pManager.DIALOG_LISTENER_DETACHED:
-                        if (mDialogListener != null) {
-                            mDialogListener.onDetached(message.arg1);
-                            mDialogListener = null;
-                        }
-                        break;
                     case WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO:
                         WifiP2pGroupList groups = (WifiP2pGroupList) message.obj;
                         if (listener != null) {
@@ -897,10 +776,6 @@
                 return mListenerMap.remove(key);
             }
         }
-
-        private void setDialogListener(DialogListener listener) {
-            mDialogListener = listener;
-        }
     }
 
     private static void checkChannel(Channel c) {
@@ -1314,41 +1189,6 @@
         c.mAsyncChannel.sendMessage(SET_WFD_INFO, 0, c.putListener(listener), wfdInfo);
     }
 
-    /**
-     * Set dialog listener to over-ride system dialogs on p2p events. This function
-     * allows an application to receive notifications on connection requests from
-     * peers so that it can customize the user experience for connection with
-     * peers.
-     *
-     * <p> The function call immediately returns after sending a request
-     * to the framework. The application is notified of a success or failure to attach
-     * to the system through listener callbacks {@link DialogListener#onAttached} or
-     * {@link DialogListener#onDetached}.
-     *
-     * <p> Note that only foreground application will be successful in overriding the
-     * system dialogs.
-     * @hide
-     *
-     * @param c is the channel created at {@link #initialize}
-     * @param listener for callback on a dialog event.
-     */
-    public void setDialogListener(Channel c, DialogListener listener) {
-        checkChannel(c);
-        c.setDialogListener(listener);
-
-        /**
-         * mAsyncChannel should always stay private and inaccessible from the app
-         * to prevent an app from sending a message with a fake app name to gain
-         * control over the dialogs
-         */
-        Message msg = Message.obtain();
-        Bundle bundle = new Bundle();
-        bundle.putString(APP_PKG_BUNDLE_KEY, c.mContext.getPackageName());
-        bundle.putBoolean(RESET_DIALOG_LISTENER_BUNDLE_KEY, listener == null);
-        msg.what = SET_DIALOG_LISTENER;
-        msg.setData(bundle);
-        c.mAsyncChannel.sendMessage(msg);
-    }
 
     /**
      * Delete a stored persistent group from the system settings.
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 30764fb..c1d177d 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -16,13 +16,10 @@
 
 package android.net.wifi.p2p;
 
-import android.app.Activity;
-import android.app.ActivityManager;
 import android.app.AlertDialog;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.app.ActivityManager.RunningTaskInfo;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -51,20 +48,16 @@
 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
 import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
 import android.os.Messenger;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.os.Parcelable.Creator;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -114,8 +107,6 @@
     INetworkManagementService mNwService;
     private DhcpStateMachine mDhcpStateMachine;
 
-    private ActivityManager mActivityMgr;
-
     private P2pStateMachine mP2pStateMachine;
     private AsyncChannel mReplyChannel = new AsyncChannel();
     private AsyncChannel mWifiChannel;
@@ -211,13 +202,6 @@
     /* clients(application) information list. */
     private HashMap<Messenger, ClientInfo> mClientInfoList = new HashMap<Messenger, ClientInfo>();
 
-    /* The foreground application's messenger.
-     * The connection request is notified only to foreground application  */
-    private Messenger mForegroundAppMessenger;
-
-    /* the package name of foreground application. */
-    private String mForegroundAppPkgName;
-
     /* Is chosen as a unique range to avoid conflict with
        the range defined in Tethering.java */
     private static final String[] DHCP_RANGE = {"192.168.49.2", "192.168.49.254"};
@@ -306,8 +290,6 @@
 
         //STOPSHIP: get this from native side
         mInterface = "p2p0";
-        mActivityMgr = (ActivityManager)context.getSystemService(Activity.ACTIVITY_SERVICE);
-
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, "");
 
         mP2pSupported = mContext.getPackageManager().hasSystemFeature(
@@ -421,9 +403,6 @@
         // Saved WifiP2pGroup from invitation request
         private WifiP2pGroup mSavedP2pGroup;
 
-        // Saved WifiP2pDevice from provisioning request
-        private WifiP2pDevice mSavedProvDiscDevice;
-
         P2pStateMachine(String name, boolean p2pSupported) {
             super(name);
 
@@ -562,18 +541,6 @@
                     replyToMessage(message, WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO,
                             new WifiP2pGroupList(mGroups, null));
                     break;
-                case WifiP2pManager.SET_DIALOG_LISTENER:
-                    String appPkgName = (String)message.getData().getString(
-                            WifiP2pManager.APP_PKG_BUNDLE_KEY);
-                    boolean isReset = message.getData().getBoolean(
-                            WifiP2pManager.RESET_DIALOG_LISTENER_BUNDLE_KEY);
-                    if (setDialogListenerApp(message.replyTo, appPkgName, isReset)) {
-                        replyToMessage(message, WifiP2pManager.DIALOG_LISTENER_ATTACHED);
-                    } else {
-                        replyToMessage(message, WifiP2pManager.DIALOG_LISTENER_DETACHED,
-                                WifiP2pManager.NOT_IN_FOREGROUND);
-                    }
-                    break;
                     // Ignore
                 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
                 case WifiMonitor.SCAN_RESULTS_EVENT:
@@ -666,10 +633,6 @@
                     replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED,
                             WifiP2pManager.P2P_UNSUPPORTED);
                     break;
-                case WifiP2pManager.SET_DIALOG_LISTENER:
-                    replyToMessage(message, WifiP2pManager.DIALOG_LISTENER_DETACHED,
-                            WifiP2pManager.P2P_UNSUPPORTED);
-                    break;
                 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
                     replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED,
                             WifiP2pManager.P2P_UNSUPPORTED);
@@ -828,7 +791,9 @@
                     //Nothing to do
                     break;
                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
-                    if (mPeers.clear()) sendP2pPeersChangedBroadcast();
+                    if (mPeers.clear()) {
+                        sendPeersChangedBroadcast();
+                    }
                     if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast();
 
                     mWifiNative.closeSupplicantConnection();
@@ -896,12 +861,16 @@
                 case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
                     if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
-                    mPeers.update(device);
-                    sendP2pPeersChangedBroadcast();
+                    mPeers.updateSupplicantDetails(device);
+                    sendPeersChangedBroadcast();
                     break;
                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
                     device = (WifiP2pDevice) message.obj;
-                    if (mPeers.remove(device)) sendP2pPeersChangedBroadcast();
+                    // Gets current details for the one removed
+                    device = mPeers.remove(device.deviceAddress);
+                    if (device != null) {
+                        sendPeersChangedBroadcast();
+                    }
                     break;
                case WifiP2pManager.ADD_LOCAL_SERVICE:
                     if (DBG) logd(getName() + " add service");
@@ -997,7 +966,7 @@
                         break;
                     }
                     mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
-                    sendP2pPeersChangedBroadcast();
+                    sendPeersChangedBroadcast();
                     replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
                     if (connectRet == NEEDS_PROVISION_REQ) {
                         if (DBG) logd("Sending prov disc");
@@ -1022,10 +991,7 @@
                     mSavedPeerConfig = (WifiP2pConfig) message.obj;
                     mAutonomousGroup = false;
                     mJoinExistingGroup = false;
-                    if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress),
-                            mSavedPeerConfig)) {
-                        transitionTo(mUserAuthorizingInvitationState);
-                    }
+                    transitionTo(mUserAuthorizingInvitationState);
                     break;
                 case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT:
                     WifiP2pGroup group = (WifiP2pGroup) message.obj;
@@ -1053,11 +1019,7 @@
 
                     mAutonomousGroup = false;
                     mJoinExistingGroup = true;
-                    //TODO In the p2p client case, we should set source address correctly.
-                    if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress),
-                            mSavedPeerConfig)) {
-                        transitionTo(mUserAuthorizingInvitationState);
-                    }
+                    transitionTo(mUserAuthorizingInvitationState);
                     break;
                 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
@@ -1150,7 +1112,7 @@
                     }
                     // Do nothing
                     if (DBG) logd("Add device to lost list " + device);
-                    mPeersLostDuringConnection.update(device);
+                    mPeersLostDuringConnection.updateSupplicantDetails(device);
                     break;
                 case WifiP2pManager.DISCOVER_PEERS:
                     /* Discovery will break negotiation */
@@ -1194,7 +1156,7 @@
                         break;
                     }
                     mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
-                    sendP2pPeersChangedBroadcast();
+                    sendPeersChangedBroadcast();
                     transitionTo(mGroupNegotiationState);
                     break;
                 case PEER_CONNECTION_USER_REJECT:
@@ -1251,10 +1213,7 @@
                             transitionTo(mGroupNegotiationState);
                         } else {
                             mJoinExistingGroup = false;
-                            if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress),
-                                    mSavedPeerConfig)) {
-                                transitionTo(mUserAuthorizingInvitationState);
-                            }
+                            transitionTo(mUserAuthorizingInvitationState);
                         }
                     }
                     break;
@@ -1267,9 +1226,7 @@
                         if (DBG) logd("Found a match " + mSavedPeerConfig);
                         mSavedPeerConfig.wps.pin = provDisc.pin;
                         p2pConnectWithPinDisplay(mSavedPeerConfig);
-                        if (!sendShowPinReqToFrontApp(provDisc.pin)) {
-                            notifyInvitationSent(provDisc.pin, device.deviceAddress);
-                        }
+                        notifyInvitationSent(provDisc.pin, device.deviceAddress);
                         transitionTo(mGroupNegotiationState);
                     }
                     break;
@@ -1331,9 +1288,9 @@
                         mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
                         WifiP2pDevice groupOwner = mGroup.getOwner();
                         /* update group owner details with the ones found at discovery */
-                        groupOwner.update(mPeers.get(groupOwner.deviceAddress));
+                        groupOwner.updateSupplicantDetails(mPeers.get(groupOwner.deviceAddress));
                         mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
-                        sendP2pPeersChangedBroadcast();
+                        sendPeersChangedBroadcast();
                     }
                     mSavedPeerConfig = null;
                     transitionTo(mGroupCreatedState);
@@ -1519,10 +1476,6 @@
                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
                     String deviceAddress = device.deviceAddress;
                     if (deviceAddress != null) {
-                        if (mSavedProvDiscDevice != null &&
-                                deviceAddress.equals(mSavedProvDiscDevice.deviceAddress)) {
-                            mSavedProvDiscDevice = null;
-                        }
                         if (mPeers.get(deviceAddress) != null) {
                             mGroup.addClient(mPeers.get(deviceAddress));
                         } else {
@@ -1530,7 +1483,7 @@
                         }
                         mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED);
                         if (DBG) logd(getName() + " ap sta connected");
-                        sendP2pPeersChangedBroadcast();
+                        sendPeersChangedBroadcast();
                     } else {
                         loge("Connect on null device address, ignore");
                     }
@@ -1558,7 +1511,7 @@
                                 if (DBG) logd("client " + c.deviceAddress);
                             }
                         }
-                        sendP2pPeersChangedBroadcast();
+                        sendPeersChangedBroadcast();
                         if (DBG) logd(getName() + " ap sta disconnected");
                     } else {
                         loge("Disconnect on unknown device: " + device);
@@ -1611,7 +1564,7 @@
                     //Device loss for a connected device indicates it is not in discovery any more
                     if (mGroup.contains(device)) {
                         if (DBG) logd("Add device to lost list " + device);
-                        mPeersLostDuringConnection.update(device);
+                        mPeersLostDuringConnection.updateSupplicantDetails(device);
                         return HANDLED;
                     }
                     // Do the regular device lost handling
@@ -1622,41 +1575,33 @@
                     break;
                 case WifiP2pManager.CONNECT:
                     WifiP2pConfig config = (WifiP2pConfig) message.obj;
-                    if (config.deviceAddress == null ||
-                            (mSavedProvDiscDevice != null &&
-                                    mSavedProvDiscDevice.deviceAddress.equals(
-                                            config.deviceAddress))) {
-                        if (config.wps.setup == WpsInfo.PBC) {
-                            mWifiNative.startWpsPbc(mGroup.getInterface(), null);
-                        } else {
-                            if (config.wps.pin == null) {
-                                String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface());
-                                try {
-                                    Integer.parseInt(pin);
-                                    if (!sendShowPinReqToFrontApp(pin)) {
-                                        notifyInvitationSent(pin,
-                                                config.deviceAddress != null ?
-                                                        config.deviceAddress : "any");
-                                    }
-                                } catch (NumberFormatException ignore) {
-                                    // do nothing if pin is invalid
-                                }
-                            } else {
-                                mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
-                                        config.wps.pin);
-                            }
-                        }
-                        if (config.deviceAddress != null) {
-                            mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
-                            sendP2pPeersChangedBroadcast();
-                        }
+                    // This allows any client to join the GO during the
+                    // WPS window
+                    if (config.deviceAddress == null) {
+                         if (config.wps.setup == WpsInfo.PBC) {
+                             mWifiNative.startWpsPbc(mGroup.getInterface(), null);
+                         } else {
+                             if (config.wps.pin == null) {
+                                 String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface());
+                                 try {
+                                     Integer.parseInt(pin);
+                                     notifyInvitationSent(pin, config.deviceAddress != null ?
+                                             config.deviceAddress : "any");
+                                 } catch (NumberFormatException ignore) {
+                                     // do nothing if pin is invalid
+                                 }
+                             } else {
+                                 mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
+                                         config.wps.pin);
+                             }
+                         }
                         replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
                     } else {
                         logd("Inviting device : " + config.deviceAddress);
                         mSavedPeerConfig = config;
                         if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) {
                             mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
-                            sendP2pPeersChangedBroadcast();
+                            sendPeersChangedBroadcast();
                             replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
                         } else {
                             replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
@@ -1692,7 +1637,6 @@
                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
                     WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj;
-                    mSavedProvDiscDevice = provDisc.device;
                     mSavedPeerConfig = new WifiP2pConfig();
                     mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress;
                     if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) {
@@ -1703,9 +1647,7 @@
                     } else {
                         mSavedPeerConfig.wps.setup = WpsInfo.PBC;
                     }
-                    if (!sendConnectNoticeToApp(mSavedProvDiscDevice, mSavedPeerConfig)) {
-                        transitionTo(mUserAuthorizingJoinState);
-                    }
+                    transitionTo(mUserAuthorizingJoinState);
                     break;
                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
                     Slog.e(TAG, "Duplicate group creation event notice, ignore");
@@ -1717,7 +1659,6 @@
         }
 
         public void exit() {
-            mSavedProvDiscDevice = null;
             updateThisDevice(WifiP2pDevice.AVAILABLE);
             resetWifiP2pInfo();
             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
@@ -1799,7 +1740,6 @@
         pw.println("mGroup " + mGroup);
         pw.println("mSavedPeerConfig " + mSavedPeerConfig);
         pw.println("mSavedP2pGroup " + mSavedP2pGroup);
-        pw.println("mSavedProvDiscDevice " + mSavedProvDiscDevice);
         pw.println();
     }
 
@@ -1837,8 +1777,9 @@
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
-    private void sendP2pPeersChangedBroadcast() {
+    private void sendPeersChangedBroadcast() {
         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
+        intent.putExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST, mPeers);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
     }
@@ -1850,6 +1791,7 @@
                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
         intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, new WifiP2pInfo(mWifiP2pInfo));
         intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
+        intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, new WifiP2pGroup(mGroup));
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
         mWifiChannel.sendMessage(WifiP2pService.P2P_CONNECTION_CHANGED,
                 new NetworkInfo(mNetworkInfo));
@@ -2285,9 +2227,7 @@
         String pin = mWifiNative.p2pConnect(config, dev.isGroupOwner());
         try {
             Integer.parseInt(pin);
-            if (!sendShowPinReqToFrontApp(pin)) {
-                notifyInvitationSent(pin, config.deviceAddress);
-            }
+            notifyInvitationSent(pin, config.deviceAddress);
         } catch (NumberFormatException ignore) {
             // do nothing if p2pConnect did not return a pin
         }
@@ -2379,26 +2319,24 @@
         resetWifiP2pInfo();
         mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.FAILED, null, null);
         sendP2pConnectionChangedBroadcast();
+
+        // Remove only the peer we failed to connect to so that other devices discovered
+        // that have not timed out still remain in list for connection
+        boolean peersChanged = mPeers.remove(mPeersLostDuringConnection);
+        if (mSavedPeerConfig != null && mPeers.remove(mSavedPeerConfig.deviceAddress) != null) {
+            peersChanged = true;
+        }
+        if (peersChanged) {
+            sendPeersChangedBroadcast();
+        }
+
         mSavedPeerConfig = null;
-        /* After cancelling group formation, new connections on existing peers can fail
-         * at supplicant. Flush and restart discovery */
-        mWifiNative.p2pFlush();
-        if (mPeers.remove(mPeersLostDuringConnection)) sendP2pPeersChangedBroadcast();
         mPeersLostDuringConnection.clear();
         mServiceDiscReqId = null;
         sendMessage(WifiP2pManager.DISCOVER_PEERS);
     }
 
     private void handleGroupRemoved() {
-        Collection <WifiP2pDevice> devices = mGroup.getClientList();
-        boolean changed = false;
-        for (WifiP2pDevice d : mPeers.getDeviceList()) {
-            if (devices.contains(d) || mGroup.getOwner().equals(d)) {
-                d.status = WifiP2pDevice.AVAILABLE;
-                changed = true;
-            }
-        }
-
         if (mGroup.isGroupOwner()) {
             stopDhcpServer(mGroup.getInterface());
         } else {
@@ -2419,12 +2357,21 @@
         // that reuse the main p2p interface for a created group.
         mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0);
 
+        boolean peersChanged = false;
+        // Remove only peers part of the group, so that other devices discovered
+        // that have not timed out still remain in list for connection
+        for (WifiP2pDevice d : mGroup.getClientList()) {
+            if (mPeers.remove(d)) peersChanged = true;
+        }
+        if (mPeers.remove(mGroup.getOwner())) peersChanged = true;
+        if (mPeers.remove(mPeersLostDuringConnection)) peersChanged = true;
+        if (peersChanged) {
+            sendPeersChangedBroadcast();
+        }
+
         mGroup = null;
-        mWifiNative.p2pFlush();
-        if (mPeers.remove(mPeersLostDuringConnection)) sendP2pPeersChangedBroadcast();
         mPeersLostDuringConnection.clear();
         mServiceDiscReqId = null;
-        if (changed) sendP2pPeersChangedBroadcast();
 
         if (mTempoarilyDisconnectedWifi) {
             mWifiChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_REQUEST, 0);
@@ -2720,139 +2667,6 @@
         return clientInfo;
     }
 
-    /**
-     * Send detached message to dialog listener in the foreground application.
-     * @param reason
-     */
-    private void sendDetachedMsg(int reason) {
-        if (mForegroundAppMessenger == null) return;
-
-        Message msg = Message.obtain();
-        msg.what = WifiP2pManager.DIALOG_LISTENER_DETACHED;
-        msg.arg1 = reason;
-        try {
-            mForegroundAppMessenger.send(msg);
-        } catch (RemoteException e) {
-        }
-        mForegroundAppMessenger = null;
-        mForegroundAppPkgName = null;
-    }
-
-    /**
-     * Send a request to show wps pin to dialog listener in the foreground application.
-     * @param pin WPS pin
-     * @return
-     */
-    private boolean sendShowPinReqToFrontApp(String pin) {
-        if (!isForegroundApp(mForegroundAppPkgName)) {
-            sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND);
-            return false;
-        }
-        Message msg = Message.obtain();
-        msg.what = WifiP2pManager.SHOW_PIN_REQUESTED;
-        Bundle bundle = new Bundle();
-        bundle.putString(WifiP2pManager.WPS_PIN_BUNDLE_KEY, pin);
-        msg.setData(bundle);
-        return sendDialogMsgToFrontApp(msg);
-    }
-
-    /**
-     * Send a request to establish the connection to dialog listener in the foreground
-     * application.
-     * @param dev source device
-     * @param config
-     * @return
-     */
-    private boolean sendConnectNoticeToApp(WifiP2pDevice dev, WifiP2pConfig config) {
-        if (dev == null) {
-            dev = new WifiP2pDevice(config.deviceAddress);
-        }
-
-        if (!isForegroundApp(mForegroundAppPkgName)) {
-            if (DBG) logd("application is NOT foreground");
-            sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND);
-            return false;
-        }
-
-        Message msg = Message.obtain();
-        msg.what = WifiP2pManager.CONNECTION_REQUESTED;
-        Bundle bundle = new Bundle();
-        bundle.putParcelable(WifiP2pManager.P2P_DEV_BUNDLE_KEY, dev);
-        bundle.putParcelable(WifiP2pManager.P2P_CONFIG_BUNDLE_KEY, config);
-        msg.setData(bundle);
-        return sendDialogMsgToFrontApp(msg);
-    }
-
-    /**
-     * Send dialog event message to front application's dialog listener.
-     * @param msg
-     * @return true if success.
-     */
-    private boolean sendDialogMsgToFrontApp(Message msg) {
-        try {
-            mForegroundAppMessenger.send(msg);
-        } catch (RemoteException e) {
-            mForegroundAppMessenger = null;
-            mForegroundAppPkgName = null;
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Set dialog listener application.
-     * @param m
-     * @param appPkgName if null, reset the listener.
-     * @param isReset if true, try to reset.
-     * @return
-     */
-    private boolean setDialogListenerApp(Messenger m,
-            String appPkgName, boolean isReset) {
-
-        if (mForegroundAppPkgName != null && !mForegroundAppPkgName.equals(appPkgName)) {
-            if (isForegroundApp(mForegroundAppPkgName)) {
-                // The current dialog listener is foreground app's.
-                if (DBG) logd("application is NOT foreground");
-                return false;
-            }
-            // detach an old listener.
-            sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND);
-        }
-
-        if (isReset) {
-            if (DBG) logd("reset dialog listener");
-            mForegroundAppMessenger = null;
-            mForegroundAppPkgName = null;
-            return true;
-        }
-
-        if (!isForegroundApp(appPkgName)) {
-            return false;
-        }
-
-        mForegroundAppMessenger = m;
-        mForegroundAppPkgName = appPkgName;
-        if (DBG) logd("set dialog listener. app=" + appPkgName);
-        return true;
-    }
-
-    /**
-     * Return true if the specified package name is foreground app's.
-     *
-     * @param pkgName application package name.
-     * @return
-     */
-    private boolean isForegroundApp(String pkgName) {
-        if (pkgName == null) return false;
-
-        List<RunningTaskInfo> tasks = mActivityMgr.getRunningTasks(1);
-        if (tasks.size() == 0) {
-            return false;
-        }
-
-        return pkgName.equals(tasks.get(0).baseActivity.getPackageName());
-    }
-
     }
 
     /**