Merge "Give IMEs the entire screen to use for measuring purposes." into klp-dev
diff --git a/api/current.txt b/api/current.txt
index 40c7bf5..abb330e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7497,11 +7497,13 @@
 
   public class AssetFileDescriptor implements java.io.Closeable android.os.Parcelable {
     ctor public AssetFileDescriptor(android.os.ParcelFileDescriptor, long, long);
+    ctor public AssetFileDescriptor(android.os.ParcelFileDescriptor, long, long, android.os.Bundle);
     method public void close() throws java.io.IOException;
     method public java.io.FileInputStream createInputStream() throws java.io.IOException;
     method public java.io.FileOutputStream createOutputStream() throws java.io.IOException;
     method public int describeContents();
     method public long getDeclaredLength();
+    method public android.os.Bundle getExtras();
     method public java.io.FileDescriptor getFileDescriptor();
     method public long getLength();
     method public android.os.ParcelFileDescriptor getParcelFileDescriptor();
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index c39415f..eb1f265 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -72,6 +73,7 @@
      * an intent; instead, use {@link #getCropAndSetWallpaperIntent}.
      * <p>Input:  {@link Intent#getData} is the URI of the image to crop and set as wallpaper.
      * <p>Output: RESULT_OK if user decided to crop/set the wallpaper, RESULT_CANCEL otherwise
+     * Activities that support this intent should specify a MIME filter of "image/*"
      */
     public static final String ACTION_CROP_AND_SET_WALLPAPER =
             "android.service.wallpaper.CROP_AND_SET_WALLPAPER";
@@ -657,8 +659,19 @@
      * that supports cropping wallpapers, it will be preferred as the default.
      * Use this method instead of directly creating a {@link #ACTION_CROP_AND_SET_WALLPAPER}
      * intent.
+     *
+     * @param imageUri The image URI that will be set in the intent. The must be a content
+     *                 URI and its provider must resolve its type to "image/*"
+     *
+     * @throws IllegalArgumentException if the URI is not a content URI or its MIME type is
+     *         not "image/*"
      */
     public Intent getCropAndSetWallpaperIntent(Uri imageUri) {
+        if (!ContentResolver.SCHEME_CONTENT.equals(imageUri.getScheme())) {
+            throw new IllegalArgumentException("Image URI must be of the "
+                    + ContentResolver.SCHEME_CONTENT + " scheme type");
+        }
+
         final PackageManager packageManager = mContext.getPackageManager();
         Intent cropAndSetWallpaperIntent =
                 new Intent(ACTION_CROP_AND_SET_WALLPAPER, imageUri);
@@ -680,7 +693,15 @@
 
         // fallback crop activity
         cropAndSetWallpaperIntent.setPackage("com.android.wallpapercropper");
-        return cropAndSetWallpaperIntent;
+        List<ResolveInfo> cropAppList = packageManager.queryIntentActivities(
+                cropAndSetWallpaperIntent, 0);
+        if (cropAppList.size() > 0) {
+            return cropAndSetWallpaperIntent;
+        }
+        // If the URI is not of the right type, or for some reason the system wallpaper
+        // cropper doesn't exist, return null
+        throw new IllegalArgumentException("Cannot use passed URI to set wallpaper; " +
+            "check that the type returned by ContentProvider matches image/*");
     }
 
     /**
diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java
index e4cc77f..28edde0 100644
--- a/core/java/android/content/res/AssetFileDescriptor.java
+++ b/core/java/android/content/res/AssetFileDescriptor.java
@@ -16,6 +16,7 @@
 
 package android.content.res;
 
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
@@ -42,17 +43,35 @@
     private final ParcelFileDescriptor mFd;
     private final long mStartOffset;
     private final long mLength;
-    
+    private final Bundle mExtras;
+
     /**
      * Create a new AssetFileDescriptor from the given values.
+     *
      * @param fd The underlying file descriptor.
      * @param startOffset The location within the file that the asset starts.
-     * This must be 0 if length is UNKNOWN_LENGTH.
+     *            This must be 0 if length is UNKNOWN_LENGTH.
      * @param length The number of bytes of the asset, or
-     * {@link #UNKNOWN_LENGTH} if it extends to the end of the file.
+     *            {@link #UNKNOWN_LENGTH} if it extends to the end of the file.
      */
     public AssetFileDescriptor(ParcelFileDescriptor fd, long startOffset,
             long length) {
+        this(fd, startOffset, length, null);
+    }
+
+    /**
+     * Create a new AssetFileDescriptor from the given values.
+     *
+     * @param fd The underlying file descriptor.
+     * @param startOffset The location within the file that the asset starts.
+     *            This must be 0 if length is UNKNOWN_LENGTH.
+     * @param length The number of bytes of the asset, or
+     *            {@link #UNKNOWN_LENGTH} if it extends to the end of the file.
+     * @param extras additional details that can be used to interpret the
+     *            underlying file descriptor. May be null.
+     */
+    public AssetFileDescriptor(ParcelFileDescriptor fd, long startOffset,
+            long length, Bundle extras) {
         if (fd == null) {
             throw new IllegalArgumentException("fd must not be null");
         }
@@ -63,8 +82,9 @@
         mFd = fd;
         mStartOffset = startOffset;
         mLength = length;
+        mExtras = extras;
     }
-    
+
     /**
      * The AssetFileDescriptor contains its own ParcelFileDescriptor, which
      * in addition to the normal FileDescriptor object also allows you to close
@@ -88,7 +108,15 @@
     public long getStartOffset() {
         return mStartOffset;
     }
-    
+
+    /**
+     * Returns any additional details that can be used to interpret the
+     * underlying file descriptor. May be null.
+     */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
     /**
      * Returns the total number of bytes of this asset entry's data.  May be
      * {@link #UNKNOWN_LENGTH} if the asset extends to the end of the file.
@@ -307,25 +335,37 @@
             super.write(oneByte);
         }
     }
-    
-    
+
     /* Parcelable interface */
+    @Override
     public int describeContents() {
         return mFd.describeContents();
     }
 
+    @Override
     public void writeToParcel(Parcel out, int flags) {
         mFd.writeToParcel(out, flags);
         out.writeLong(mStartOffset);
         out.writeLong(mLength);
+        if (mExtras != null) {
+            out.writeInt(1);
+            out.writeBundle(mExtras);
+        } else {
+            out.writeInt(0);
+        }
     }
 
     AssetFileDescriptor(Parcel src) {
         mFd = ParcelFileDescriptor.CREATOR.createFromParcel(src);
         mStartOffset = src.readLong();
         mLength = src.readLong();
+        if (src.readInt() != 0) {
+            mExtras = src.readBundle();
+        } else {
+            mExtras = null;
+        }
     }
-    
+
     public static final Parcelable.Creator<AssetFileDescriptor> CREATOR
             = new Parcelable.Creator<AssetFileDescriptor>() {
         public AssetFileDescriptor createFromParcel(Parcel in) {
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index 3cd7863..58d9616 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -33,6 +33,18 @@
 import java.util.HashMap;
 import java.util.List;
 
+/**
+ * This class can be used to query the state of
+ * NFC card emulation services.
+ *
+ * For a general introduction into NFC card emulation,
+ * please read the <a href="{@docRoot}guide/topics/nfc/ce.html">
+ * NFC card emulation developer guide</a>.</p>
+ *
+ * <p class="note">Use of this class requires the
+ * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present
+ * on the device.
+ */
 public final class CardEmulation {
     static final String TAG = "CardEmulation";
 
@@ -50,32 +62,28 @@
             "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
 
     /**
-     * The category extra for {@link #ACTION_CHANGE_DEFAULT}
+     * The category extra for {@link #ACTION_CHANGE_DEFAULT}.
      *
      * @see #ACTION_CHANGE_DEFAULT
      */
     public static final String EXTRA_CATEGORY = "category";
 
     /**
-     * The ComponentName object passed in as a parcelable
-     * extra for {@link #ACTION_CHANGE_DEFAULT}
+     * The service {@link ComponentName} object passed in as an
+     * extra for {@link #ACTION_CHANGE_DEFAULT}.
      *
      * @see #ACTION_CHANGE_DEFAULT
      */
     public static final String EXTRA_SERVICE_COMPONENT = "component";
 
     /**
-     * The payment category can be used to indicate that an AID
-     * represents a payment application.
+     * Category used for NFC payment services.
      */
     public static final String CATEGORY_PAYMENT = "payment";
 
     /**
-     * If an AID group does not contain a category, or the
-     * specified category is not defined by the platform version
-     * that is parsing the AID group, all AIDs in the group will
-     * automatically be categorized under the {@link #CATEGORY_OTHER}
-     * category.
+     * Category that can be used for all other card emulation
+     * services.
      */
     public static final String CATEGORY_OTHER = "other";
 
@@ -83,49 +91,23 @@
      * Return value for {@link #getSelectionModeForCategory(String)}.
      *
      * <p>In this mode, the user has set a default service for this
-     *    AID category. If a remote reader selects any of the AIDs
+     *    category.
+     *
+     * <p>When using ISO-DEP card emulation with {@link HostApduService}
+     *    or {@link OffHostApduService}, if a remote NFC device selects
+     *    any of the Application IDs (AIDs)
      *    that the default service has registered in this category,
      *    that service will automatically be bound to to handle
      *    the transaction.
-     *
-     * <p>There are still cases where a service that is
-     *    not the default for a category can selected:
-     *    <p>
-     *    If a remote reader selects an AID in this category
-     *    that is not handled by the default service, and there is a set
-     *    of other services {S} that do handle this AID, the
-     *    user is asked if he wants to use any of the services in
-     *    {S} instead.
-     *    <p>
-     *    As a special case, if the size of {S} is one, containing a single service X,
-     *    and all AIDs X has registered in this category are not
-     *    registered by any other service, then X will be
-     *    selected automatically without asking the user.
-     *    <p>Example:
-     *    <ul>
-     *    <li>Service A registers AIDs "1", "2" and "3" in the category
-     *    <li>Service B registers AIDs "3" and "4" in the category
-     *    <li>Service C registers AIDs "5" and "6" in the category
-     *    </ul>
-     *    In this case, the following will happen when service A
-     *    is the default:
-     *    <ul>
-     *    <li>Reader selects AID "1", "2" or "3": service A is invoked automatically
-     *    <li>Reader selects AID "4": the user is asked to confirm he
-     *        wants to use service B, because its AIDs overlap with service A.
-     *    <li>Reader selects AID "5" or "6": service C is invoked automatically,
-     *        because all AIDs it has asked for are only registered by C,
-     *        and there is no overlap.
-     *    </ul>
-     *
      */
     public static final int SELECTION_MODE_PREFER_DEFAULT = 0;
 
     /**
      * Return value for {@link #getSelectionModeForCategory(String)}.
      *
-     * <p>In this mode, whenever an AID of this category is selected,
-     *    the user is asked which service he wants to use to handle
+     * <p>In this mode, when using ISO-DEP card emulation with {@link HostApduService}
+     *    or {@link OffHostApduService}, whenever an Application ID (AID) of this category
+     *    is selected, the user is asked which service he wants to use to handle
      *    the transaction, even if there is only one matching service.
      */
     public static final int SELECTION_MODE_ALWAYS_ASK = 1;
@@ -133,13 +115,16 @@
     /**
      * Return value for {@link #getSelectionModeForCategory(String)}.
      *
-     * <p>In this mode, the user will only be asked to select a service
-     *    if the selected AID has been registered by multiple applications.
+     * <p>In this mode, when using ISO-DEP card emulation with {@link HostApduService}
+     *    or {@link OffHostApduService}, the user will only be asked to select a service
+     *    if the Application ID (AID) selected by the reader has been registered by multiple
+     *    services. If there is only one service that has registered for the AID,
+     *    that service will be invoked directly.
      */
     public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2;
 
     static boolean sIsInitialized = false;
-    static HashMap<Context, CardEmulation> sCardEmus = new HashMap();
+    static HashMap<Context, CardEmulation> sCardEmus = new HashMap<Context, CardEmulation>();
     static INfcCardEmulation sService;
 
     final Context mContext;
@@ -149,6 +134,12 @@
         sService = service;
     }
 
+    /**
+     * Helper to get an instance of this class.
+     *
+     * @param adapter A reference to an NfcAdapter object.
+     * @return
+     */
     public static synchronized CardEmulation getInstance(NfcAdapter adapter) {
         if (adapter == null) throw new NullPointerException("NfcAdapter is null");
         Context context = adapter.getContext();
@@ -188,12 +179,19 @@
      * the default service to handle a card emulation category.
      *
      * <p>Note that if {@link #getSelectionModeForCategory(String)}
-     * returns {@link #SELECTION_MODE_ALWAYS_ASK}, this method will always
-     * return false.
+     * returns {@link #SELECTION_MODE_ALWAYS_ASK} or {@link #SELECTION_MODE_ASK_IF_CONFLICT},
+     * this method will always return false. That is because in these
+     * selection modes a default can't be set at the category level. For categories where
+     * the selection mode is {@link #SELECTION_MODE_ALWAYS_ASK} or
+     * {@link #SELECTION_MODE_ASK_IF_CONFLICT}, use
+     * {@link #isDefaultServiceForAid(ComponentName, String)} to determine whether a service
+     * is the default for a specific AID.
      *
      * @param service The ComponentName of the service
      * @param category The category
      * @return whether service is currently the default service for the category.
+     *
+     * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
      */
     public boolean isDefaultServiceForCategory(ComponentName service, String category) {
         try {
@@ -222,7 +220,9 @@
      *
      * @param service The ComponentName of the service
      * @param aid The ISO7816-4 Application ID
-     * @return
+     * @return whether the service is the default handler for the specified AID
+     *
+     * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
      */
     public boolean isDefaultServiceForAid(ComponentName service, String aid) {
         try {
@@ -244,16 +244,16 @@
     }
 
     /**
-     * Returns the application selection mode for the passed in category.
+     * Returns the service selection mode for the passed in category.
      * Valid return values are:
      * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default
-     *    application for this category, which will be preferred.
+     *    service for this category, which will be preferred.
      * <p>{@link #SELECTION_MODE_ALWAYS_ASK} the user has requested to be asked
-     *    every time what app he would like to use in this category.
+     *    every time what service he would like to use in this category.
      * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked
      *    to pick a service if there is a conflict.
      * @param category The category, for example {@link #CATEGORY_PAYMENT}
-     * @return
+     * @return the selection mode for the passed in category
      */
     public int getSelectionModeForCategory(String category) {
         if (CATEGORY_PAYMENT.equals(category)) {
@@ -314,6 +314,7 @@
             }
         }
     }
+
     /**
      * @hide
      */
diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/core/java/android/nfc/cardemulation/HostApduService.java
index e2c3ca6..ad34e61 100644
--- a/core/java/android/nfc/cardemulation/HostApduService.java
+++ b/core/java/android/nfc/cardemulation/HostApduService.java
@@ -4,6 +4,7 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Service;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -13,30 +14,136 @@
 import android.util.Log;
 
 /**
- * <p>A convenience class that can be extended to implement
- * a service that processes ISO7816-4 commands on top of
- * the ISO14443-4 / IsoDep protocol (T=CL).
+ * <p>HostApduService is a convenience {@link Service} class that can be
+ * extended to emulate an NFC card inside an Android
+ * service component.
  *
- * <p>To tell the platform which ISO7816 application ID (AIDs)
- * are implemented by this service, a {@link #SERVICE_META_DATA}
+ * <div class="special reference">
+ * <h3>Developer Guide</h3>
+ * For a general introduction into the topic of card emulation,
+ * please read the <a href="{@docRoot}guide/topics/nfc/ce.html">
+ * NFC card emulation developer guide.</a></p>
+ * </div>
+ *
+ * <h3>NFC Protocols</h3>
+ * <p>Cards emulated by this class are based on the NFC-Forum ISO-DEP
+ * protocol (based on ISO/IEC 14443-4) and support processing
+ * command Application Protocol Data Units (APDUs) as
+ * defined in the ISO/IEC 7816-4 specification.
+ *
+ * <h3>Service selection</h3>
+ * <p>When a remote NFC device wants to talk to your
+ * service, it sends a so-called
+ * "SELECT AID" APDU as defined in the ISO/IEC 7816-4 specification.
+ * The AID is an application identifier defined in ISO/IEC 7816-4.
+ *
+ * <p>The registration procedure for AIDs is defined in the
+ * ISO/IEC 7816-5 specification. If you don't want to register an
+ * AID, you are free to use AIDs in the proprietary range:
+ * bits 8-5 of the first byte must each be set to '1'. For example,
+ * "0xF00102030405" is a proprietary AID. If you do use proprietary
+ * AIDs, it is recommended to choose an AID of at least 6 bytes,
+ * to reduce the risk of collisions with other applications that
+ * might be using proprietary AIDs as well.
+ *
+ * <h3>AID groups</h3>
+ * <p>In some cases, a service may need to register multiple AIDs
+ * to implement a certain application, and it needs to be sure
+ * that it is the default handler for all of these AIDs (as opposed
+ * to some AIDs in the group going to another service).
+ *
+ * <p>An AID group is a list of AIDs that should be considered as
+ * belonging together by the OS. For all AIDs in an AID group, the
+ * OS will guarantee one of the following:
+ * <ul>
+ * <li>All AIDs in the group are routed to this service
+ * <li>No AIDs in the group are routed to this service
+ * </ul>
+ * In other words, there is no in-between state, where some AIDs
+ * in the group can be routed to this service, and some to another.
+ * <h3>AID groups and categories</h3>
+ * <p>Each AID group can be associated with a category. This allows
+ * the Android OS to classify services, and it allows the user to
+ * set defaults at the category level instead of the AID level.
+ *
+ * <p>You can use
+ * {@link CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String)}
+ * to determine if your service is the default handler for a category.
+ *
+ * <p>In this version of the platform, the only known categories
+ * are {@link CardEmulation#CATEGORY_PAYMENT} and {@link CardEmulation#CATEGORY_OTHER}.
+ * AID groups without a category, or with a category that is not recognized
+ * by the current platform version, will automatically be
+ * grouped into the {@link CardEmulation#CATEGORY_OTHER} category.
+ * <h3>Service AID registration</h3>
+ * <p>To tell the platform which AIDs groups
+ * are requested by this service, a {@link #SERVICE_META_DATA}
  * entry must be included in the declaration of the service. An
- * example of such a service declaration is shown below:
- * <pre> &lt;service android:name=".MyHostApduService"&gt;
+ * example of a HostApduService manifest declaration is shown below:
+ * <pre> &lt;service android:name=".MyHostApduService" android:exported="true" android:permission="android.permission.BIND_NFC_SERVICE"&gt;
  *     &lt;intent-filter&gt;
- *         &lt;action android:name="android.nfc.HostApduService"/&gt;
+ *         &lt;action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/&gt;
  *     &lt;/intent-filter&gt;
- *     &lt;meta-data android:name="android.nfc.HostApduService" android:resource="@xml/apduservice.xml"/&gt;
+ *     &lt;meta-data android:name="android.nfc.cardemulation.host_apdu_ervice" android:resource="@xml/apduservice"/&gt;
  * &lt;/service&gt;</pre>
- * <p>For more details refer to {@link #SERVICE_META_DATA},
- * <code>&lt;{@link android.R.styleable#HostApduService host-apdu-service}&gt;</code>,
- * <code>&lt;{@link android.R.styleable#AidGroup aid-group}&gt;</code> and
- * <code>&lt;{@link android.R.styleable#AidFilter aid-filter}&gt;</code>.
- * <p class="note">The Android platform currently only supports a single
- * logical channel.
+ *
+ * This meta-data tag points to an apduservice.xml file.
+ * An example of this file with a single AID group declaration is shown below:
+ * <pre>
+ * &lt;host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
+ *           android:description="@string/servicedesc" android:requireDeviceUnlock="false"&gt;
+ *       &lt;aid-group android:description="@string/aiddescription" android:category="other">
+ *           &lt;aid-filter android:name="F0010203040506"/&gt;
+ *           &lt;aid-filter android:name="F0394148148100"/&gt;
+ *       &lt;/aid-group&gt;
+ * &lt;/host-apdu-service&gt;
+ * </pre>
+ *
+ * <p>The {@link android.R.styleable#HostApduService &lt;host-apdu-service&gt;} is required
+ * to contain a
+ * {@link android.R.styleable#HostApduService_description &lt;android:description&gt;}
+ * attribute that contains a user-friendly description of the service that may be shown in UI.
+ * The
+ * {@link android.R.styleable#HostApduService_requireDeviceUnlock &lt;requireDeviceUnlock&gt;}
+ * attribute can be used to specify that the device must be unlocked before this service
+ * can be invoked to handle APDUs.
+ * <p>The {@link android.R.styleable#HostApduService &lt;host-apdu-service&gt;} must
+ * contain one or more {@link android.R.styleable#AidGroup &lt;aid-group&gt;} tags.
+ * Each {@link android.R.styleable#AidGroup &lt;aid-group&gt;} must contain one or
+ * more {@link android.R.styleable#AidFilter &lt;aid-filter&gt;} tags, each of which
+ * contains a single AID. The AID must be specified in hexadecimal format, and contain
+ * an even number of characters.
+ * <h3>AID conflict resolution</h3>
+ * Multiple HostApduServices may be installed on a single device, and the same AID
+ * can be registered by more than one service. The Android platform resolves AID
+ * conflicts depending on which category an AID belongs to. Each category may
+ * have a different conflict resolution policy. For example, for some categories
+ * the user may be able to select a default service in the Android settings UI.
+ * For other categories, to policy may be to always ask the user which service
+ * is to be invoked in case of conflict.
+ *
+ * To query the conflict resolution policy for a certain category, see
+ * {@link CardEmulation#getSelectionModeForCategory(String)}.
+ *
+ * <h3>Data exchange</h3>
+ * <p>Once the platform has resolved a "SELECT AID" command APDU to a specific
+ * service component, the "SELECT AID" command APDU and all subsequent
+ * command APDUs will be sent to that service through
+ * {@link #processCommandApdu(byte[], Bundle)}, until either:
+ * <ul>
+ * <li>The NFC link is broken</li>
+ * <li>A "SELECT AID" APDU is received which resolves to another service</li>
+ * </ul>
+ * These two scenarios are indicated by a call to {@link #onDeactivated(int)}.
+ *
+ * <p class="note">Use of this class requires the
+ * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present
+ * on the device.
+ *
  */
 public abstract class HostApduService extends Service {
     /**
-     * The {@link Intent} that must be declared as handled by the service.
+     * The {@link Intent} action that must be declared as handled by the service.
      */
     @SdkConstant(SdkConstantType.SERVICE_ACTION)
     public static final String SERVICE_INTERFACE =
@@ -260,7 +367,7 @@
      * If you cannot return a response APDU immediately, return null
      * and use the {@link #sendResponseApdu(byte[])} method later.
      *
-     * @param commandApdu The APDU that received from the remote device
+     * @param commandApdu The APDU that was received from the remote device
      * @param extras A bundle containing extra data. May be null.
      * @return a byte-array containing the response APDU, or null if no
      *         response APDU can be sent at this point.
diff --git a/core/java/android/nfc/cardemulation/OffHostApduService.java b/core/java/android/nfc/cardemulation/OffHostApduService.java
index 15f63f9..0d01762 100644
--- a/core/java/android/nfc/cardemulation/OffHostApduService.java
+++ b/core/java/android/nfc/cardemulation/OffHostApduService.java
@@ -4,41 +4,126 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Service;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.IBinder;
 
 /**
- * <p>A convenience class that can be extended to implement
- * a service that registers ISO7814-4 AIDs that reside off-host,
- * for example on an embedded secure element or UICC.
+ * <p>OffHostApduService is a convenience {@link Service} class that can be
+ * extended to describe one or more NFC applications that are residing
+ * off-host, for example on an embedded secure element or a UICC.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guide</h3>
+ * For a general introduction into the topic of card emulation,
+ * please read the <a href="{@docRoot}guide/topics/nfc/ce.html">
+ * NFC card emulation developer guide.</a></p>
+ * </div>
+ *
+ * <h3>NFC Protocols</h3>
+ * <p>Off-host applications represented by this class are based on the NFC-Forum ISO-DEP
+ * protocol (based on ISO/IEC 14443-4) and support processing
+ * command Application Protocol Data Units (APDUs) as
+ * defined in the ISO/IEC 7816-4 specification.
+ *
+ * <h3>Service selection</h3>
+ * <p>When a remote NFC device wants to talk to your
+ * off-host NFC application, it sends a so-called
+ * "SELECT AID" APDU as defined in the ISO/IEC 7816-4 specification.
+ * The AID is an application identifier defined in ISO/IEC 7816-4.
+ *
+ * <p>The registration procedure for AIDs is defined in the
+ * ISO/IEC 7816-5 specification. If you don't want to register an
+ * AID, you are free to use AIDs in the proprietary range:
+ * bits 8-5 of the first byte must each be set to '1'. For example,
+ * "0xF00102030405" is a proprietary AID. If you do use proprietary
+ * AIDs, it is recommended to choose an AID of at least 6 bytes,
+ * to reduce the risk of collisions with other applications that
+ * might be using proprietary AIDs as well.
+ *
+ * <h3>AID groups</h3>
+ * <p>In some cases, an off-host environment may need to register multiple AIDs
+ * to implement a certain application, and it needs to be sure
+ * that it is the default handler for all of these AIDs (as opposed
+ * to some AIDs in the group going to another service).
+ *
+ * <p>An AID group is a list of AIDs that should be considered as
+ * belonging together by the OS. For all AIDs in an AID group, the
+ * OS will guarantee one of the following:
+ * <ul>
+ * <li>All AIDs in the group are routed to the off-host execution environment
+ * <li>No AIDs in the group are routed to the off-host execution environment
+ * </ul>
+ * In other words, there is no in-between state, where some AIDs
+ * in the group can be routed to this off-host execution environment,
+ * and some to another or a host-based {@link HostApduService}.
+ * <h3>AID groups and categories</h3>
+ * <p>Each AID group can be associated with a category. This allows
+ * the Android OS to classify services, and it allows the user to
+ * set defaults at the category level instead of the AID level.
+ *
+ * <p>You can use
+ * {@link CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String)}
+ * to determine if your off-host service is the default handler for a category.
+ *
+ * <p>In this version of the platform, the only known categories
+ * are {@link CardEmulation#CATEGORY_PAYMENT} and {@link CardEmulation#CATEGORY_OTHER}.
+ * AID groups without a category, or with a category that is not recognized
+ * by the current platform version, will automatically be
+ * grouped into the {@link CardEmulation#CATEGORY_OTHER} category.
+ *
+ * <h3>Service AID registration</h3>
+ * <p>To tell the platform which AIDs
+ * reside off-host and are managed by this service, a {@link #SERVICE_META_DATA}
+ * entry must be included in the declaration of the service. An
+ * example of a OffHostApduService manifest declaration is shown below:
+ * <pre> &lt;service android:name=".MyOffHostApduService" android:exported="true" android:permission="android.permission.BIND_NFC_SERVICE"&gt;
+ *     &lt;intent-filter&gt;
+ *         &lt;action android:name="android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE"/&gt;
+ *     &lt;/intent-filter&gt;
+ *     &lt;meta-data android:name="android.nfc.cardemulation.off_host_apdu_ervice" android:resource="@xml/apduservice"/&gt;
+ * &lt;/service&gt;</pre>
+ *
+ * This meta-data tag points to an apduservice.xml file.
+ * An example of this file with a single AID group declaration is shown below:
+ * <pre>
+ * &lt;offhost-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
+ *           android:description="@string/servicedesc"&gt;
+ *       &lt;aid-group android:description="@string/subscription" android:category="other">
+ *           &lt;aid-filter android:name="F0010203040506"/&gt;
+ *           &lt;aid-filter android:name="F0394148148100"/&gt;
+ *       &lt;/aid-group&gt;
+ * &lt;/offhost-apdu-service&gt;
+ * </pre>
+ *
+ * <p>The {@link android.R.styleable#OffHostApduService &lt;offhost-apdu-service&gt;} is required
+ * to contain a
+ * {@link android.R.styleable#OffHostApduService_description &lt;android:description&gt;}
+ * attribute that contains a user-friendly description of the service that may be shown in UI.
+ *
+ * <p>The {@link android.R.styleable#OffHostApduService &lt;offhost-apdu-service&gt;} must
+ * contain one or more {@link android.R.styleable#AidGroup &lt;aid-group&gt;} tags.
+ * Each {@link android.R.styleable#AidGroup &lt;aid-group&gt;} must contain one or
+ * more {@link android.R.styleable#AidFilter &lt;aid-filter&gt;} tags, each of which
+ * contains a single AID. The AID must be specified in hexadecimal format, and contain
+ * an even number of characters.
  *
  * <p>This registration will allow the service to be included
- * as an option for handling these AIDs on non-host execution
- * environments. The Operating System will take care of correctly
- * routing the AIDs, based on which service the user has selected
- * to be the handler for an AID.
+ * as an option for being the default handler for categories.
+ * The Android OS will take care of correctly
+ * routing the AIDs to the off-host execution environment,
+ * based on which service the user has selected to be the handler for a certain category.
  *
  * <p>The service may define additional actions outside of the
  * Android namespace that provide further interaction with
  * the off-host execution environment.
  *
- * <p>To tell the platform which ISO7816 application ID (AIDs)
- * are present and handled by the app containing this service,
- * a {@link #SERVICE_META_DATA} entry must be included in the declaration
- * of the service. An example of such a service declaration is shown below:
- * <pre> &lt;service android:name=".MyOffHostApduService"&gt;
- *     &lt;intent-filter&gt;
- *         &lt;action android:name="android.nfc.OffHostApduService"/&gt;
- *     &lt;/intent-filter&gt;
- *     &lt;meta-data android:name="android.nfc.OffHostApduService" android:resource="@xml/apduservice.xml"/&gt;
- * &lt;/service&gt;</pre>
- * <p>For more details refer to {@link #SERVICE_META_DATA},
- * <code>&lt;{@link android.R.styleable#OffHostApduService offhost-apdu-service}&gt;</code>,
- * <code>&lt;{@link android.R.styleable#AidGroup aid-group}&gt;</code> and
- * <code>&lt;{@link android.R.styleable#AidFilter aid-filter}&gt;</code>.
+ * <p class="note">Use of this class requires the
+ * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present
+ * on the device.
  */
 public abstract class OffHostApduService extends Service {
     /**
-     * The {@link Intent} that must be declared as handled by the service.
+     * The {@link Intent} action that must be declared as handled by the service.
      */
     @SdkConstant(SdkConstantType.SERVICE_ACTION)
     public static final String SERVICE_INTERFACE =
diff --git a/core/java/android/nfc/tech/NfcBarcode.java b/core/java/android/nfc/tech/NfcBarcode.java
index 76627de..8901f28 100644
--- a/core/java/android/nfc/tech/NfcBarcode.java
+++ b/core/java/android/nfc/tech/NfcBarcode.java
@@ -102,15 +102,21 @@
      *       </ul>
      *     <p>The following 12 bytes are payload:<ul>
      *       <li> In case of a URL payload, the payload is encoded in US-ASCII,
-     *            following the limitations defined in RF3987,
-     *            {@see http://www.ietf.org/rfc/rfc3987.txt}</li>
-     *       <li> In case of GS1 EPC daya, {@see http://www.gs1.org/gsmp/kc/epcglobal/tds/}
-     *            for more details.</li></ul>
+     *            following the limitations defined in RFC3987.
+     *            {@see <a href="http://www.ietf.org/rfc/rfc3987.txt">RFC 3987</a>}</li>
+     *       <li> In case of GS1 EPC data, see <a href="http://www.gs1.org/gsmp/kc/epcglobal/tds/">
+     *            GS1 Electronic Product Code (EPC) Tag Data Standard (TDS)</a> for more details.
+     *       </li>
+     *     </ul>
      *     <p>The last 2 bytes comprise the CRC.
      *     </ul>
      * <p>Does not cause any RF activity and does not block.
      *
      * @return a byte array containing the barcode
+     * @see <a href="http://www.kovio.com/docs/kovionfcbarcode.pdf">
+     *      Kovio 128-bit NFC barcode datasheet</a>
+     * @see <a href="http://kovio.com/docs/kovio-128-nfc-barcode-data-format.pdf">
+     *      Kovio 128-bit NFC barcode data format</a>
      */
     public byte[] getBarcode() {
         switch (mType) {
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index db5cf1c..b5413db 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -686,7 +686,8 @@
      *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
      */
     public static String getExternalStorageState() {
-        return getStorageState(getExternalStorageDirectory());
+        final File externalDir = sCurrentUser.getExternalDirsForApp()[0];
+        return getStorageState(externalDir);
     }
 
     /**
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index c5e4f21..9d35847 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -28,7 +28,9 @@
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
 import android.graphics.Point;
+import android.media.ExifInterface;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -42,8 +44,10 @@
 import libcore.io.Libcore;
 
 import java.io.BufferedInputStream;
+import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.List;
 
@@ -76,6 +80,15 @@
     /** {@hide} */
     public static final String EXTRA_PACKAGE_NAME = "android.content.extra.PACKAGE_NAME";
 
+    /**
+     * Included in {@link AssetFileDescriptor#getExtras()} when returned
+     * thumbnail should be rotated.
+     *
+     * @see MediaStore.Images.ImageColumns#ORIENTATION
+     * @hide
+     */
+    public static final String EXTRA_ORIENTATION = "android.content.extra.ORIENTATION";
+
     /** {@hide} */
     public static final String ACTION_MANAGE_ROOT = "android.provider.action.MANAGE_ROOT";
     /** {@hide} */
@@ -657,6 +670,7 @@
         openOpts.putParcelable(DocumentsContract.EXTRA_THUMBNAIL_SIZE, size);
 
         AssetFileDescriptor afd = null;
+        Bitmap bitmap = null;
         try {
             afd = client.openTypedAssetFileDescriptor(documentUri, "image/*", openOpts, signal);
 
@@ -688,21 +702,36 @@
 
             opts.inJustDecodeBounds = false;
             opts.inSampleSize = Math.min(widthSample, heightSample);
-            Log.d(TAG, "Decoding with sample size " + opts.inSampleSize);
             if (is != null) {
                 is.reset();
-                return BitmapFactory.decodeStream(is, null, opts);
+                bitmap = BitmapFactory.decodeStream(is, null, opts);
             } else {
                 try {
                     Libcore.os.lseek(fd, offset, SEEK_SET);
                 } catch (ErrnoException e) {
                     e.rethrowAsIOException();
                 }
-                return BitmapFactory.decodeFileDescriptor(fd, null, opts);
+                bitmap = BitmapFactory.decodeFileDescriptor(fd, null, opts);
+            }
+
+            // Transform the bitmap if requested. We use a side-channel to
+            // communicate the orientation, since EXIF thumbnails don't contain
+            // the rotation flags of the original image.
+            final Bundle extras = afd.getExtras();
+            final int orientation = (extras != null) ? extras.getInt(EXTRA_ORIENTATION, 0) : 0;
+            if (orientation != 0) {
+                final int width = bitmap.getWidth();
+                final int height = bitmap.getHeight();
+
+                final Matrix m = new Matrix();
+                m.setRotate(orientation, width / 2, height / 2);
+                bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, m, false);
             }
         } finally {
             IoUtils.closeQuietly(afd);
         }
+
+        return bitmap;
     }
 
     /**
@@ -770,4 +799,44 @@
 
         client.call(METHOD_DELETE_DOCUMENT, null, in);
     }
+
+    /**
+     * Open the given image for thumbnail purposes, using any embedded EXIF
+     * thumbnail if available, and providing orientation hints from the parent
+     * image.
+     *
+     * @hide
+     */
+    public static AssetFileDescriptor openImageThumbnail(File file) throws FileNotFoundException {
+        final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+                file, ParcelFileDescriptor.MODE_READ_ONLY);
+        Bundle extras = null;
+
+        try {
+            final ExifInterface exif = new ExifInterface(file.getAbsolutePath());
+
+            switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1)) {
+                case ExifInterface.ORIENTATION_ROTATE_90:
+                    extras = new Bundle(1);
+                    extras.putInt(EXTRA_ORIENTATION, 90);
+                    break;
+                case ExifInterface.ORIENTATION_ROTATE_180:
+                    extras = new Bundle(1);
+                    extras.putInt(EXTRA_ORIENTATION, 180);
+                    break;
+                case ExifInterface.ORIENTATION_ROTATE_270:
+                    extras = new Bundle(1);
+                    extras.putInt(EXTRA_ORIENTATION, 270);
+                    break;
+            }
+
+            final long[] thumb = exif.getThumbnailRange();
+            if (thumb != null) {
+                return new AssetFileDescriptor(pfd, thumb[0], thumb[1], extras);
+            }
+        } catch (IOException e) {
+        }
+
+        return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH, extras);
+    }
 }
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 8c1cf5f..abd173a 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -253,7 +253,7 @@
      * @param msg The message you would like logged.
      */
     public static int wtf(String tag, String msg) {
-        return wtf(tag, msg, null);
+        return wtf(LOG_ID_MAIN, tag, msg, null, false);
     }
 
     /**
@@ -262,7 +262,7 @@
      * @hide
      */
     public static int wtfStack(String tag, String msg) {
-        return wtfStack(LOG_ID_MAIN, tag, msg);
+        return wtf(LOG_ID_MAIN, tag, msg, null, true);
     }
 
     /**
@@ -272,7 +272,7 @@
      * @param tr An exception to log.
      */
     public static int wtf(String tag, Throwable tr) {
-        return wtf(tag, tr.getMessage(), tr);
+        return wtf(LOG_ID_MAIN, tag, tr.getMessage(), tr, false);
     }
 
     /**
@@ -283,18 +283,13 @@
      * @param tr An exception to log.  May be null.
      */
     public static int wtf(String tag, String msg, Throwable tr) {
-        return wtf(LOG_ID_MAIN, tag, msg, tr);
+        return wtf(LOG_ID_MAIN, tag, msg, tr, false);
     }
 
-    static int wtfStack(int logId, String tag, String msg) {
-        TerribleFailure here = new TerribleFailure("here", null);
-        here.fillInStackTrace();
-        return wtf(logId, tag, msg, here);
-    }
-
-    static int wtf(int logId, String tag, String msg, Throwable tr) {
+    static int wtf(int logId, String tag, String msg, Throwable tr, boolean localStack) {
         TerribleFailure what = new TerribleFailure(msg, tr);
-        int bytes = println_native(logId, ASSERT, tag, msg + '\n' + getStackTraceString(tr));
+        int bytes = println_native(logId, ASSERT, tag, msg + '\n'
+                + getStackTraceString(localStack ? what : tr));
         sWtfHandler.onTerribleFailure(tag, what);
         return bytes;
     }
diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java
index a5c22ff..70795bb 100644
--- a/core/java/android/util/Slog.java
+++ b/core/java/android/util/Slog.java
@@ -79,19 +79,19 @@
     }
 
     public static int wtf(String tag, String msg) {
-        return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null);
+        return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, false);
     }
 
     public static int wtfStack(String tag, String msg) {
-        return Log.wtfStack(Log.LOG_ID_SYSTEM, tag, msg);
+        return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, true);
     }
 
     public static int wtf(String tag, Throwable tr) {
-        return Log.wtf(Log.LOG_ID_SYSTEM, tag, tr.getMessage(), tr);
+        return Log.wtf(Log.LOG_ID_SYSTEM, tag, tr.getMessage(), tr, false);
     }
 
     public static int wtf(String tag, String msg, Throwable tr) {
-        return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, tr);
+        return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, tr, false);
     }
 
     public static int println(int priority, String tag, String msg) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9c388dd..e2d98ed 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -18,6 +18,7 @@
 
 import android.content.ClipData;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -691,9 +692,23 @@
      */
     public static final int NO_ID = -1;
 
+    /**
+     * Signals that compatibility booleans have been initialized according to
+     * target SDK versions.
+     */
+    private static boolean sCompatibilityDone = false;
+
+    /**
+     * Use the old (broken) way of building MeasureSpecs.
+     */
     private static boolean sUseBrokenMakeMeasureSpec = false;
 
     /**
+     * Ignore any optimizations using the measure cache.
+     */
+    private static boolean sIgnoreMeasureCache = false;
+
+    /**
      * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
      * calling setFlags.
      */
@@ -3426,10 +3441,17 @@
         mUserPaddingStart = UNDEFINED_PADDING;
         mUserPaddingEnd = UNDEFINED_PADDING;
 
-        if (!sUseBrokenMakeMeasureSpec && context != null &&
-                context.getApplicationInfo().targetSdkVersion <= JELLY_BEAN_MR1) {
+        if (!sCompatibilityDone && context != null) {
+            final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
+
             // Older apps may need this compatibility hack for measurement.
-            sUseBrokenMakeMeasureSpec = true;
+            sUseBrokenMakeMeasureSpec = targetSdkVersion <= JELLY_BEAN_MR1;
+
+            // Older apps expect onMeasure() to always be called on a layout pass, regardless
+            // of whether a layout was requested on that View.
+            sIgnoreMeasureCache = targetSdkVersion < KITKAT;
+
+            sCompatibilityDone = true;
         }
     }
 
@@ -16431,7 +16453,7 @@
 
             int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :
                     mMeasureCache.indexOfKey(key);
-            if (cacheIndex < 0) {
+            if (cacheIndex < 0 || sIgnoreMeasureCache) {
                 // measure ourselves, this should set the measured dimension flag back
                 onMeasure(widthMeasureSpec, heightMeasureSpec);
                 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 430e43a..222e446 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -2918,29 +2918,38 @@
             }
         }
 
-        public void clearCurrentOwner(Object owner) {
+        public void clearCurrentOwner(Object owner, boolean silently) {
             if (mOwner == owner) {
-                mOwner = null;
                 mProc.decActiveServices(mName);
                 if (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
                         || mExecState != STATE_NOTHING) {
                     long now = SystemClock.uptimeMillis();
                     if (mStartedState != STATE_NOTHING) {
-                        Slog.wtfStack(TAG, "Service owner " + owner + " cleared while started: pkg="
-                                + mPackage + " service=" + mName + " proc=" + mProc);
+                        if (!silently) {
+                            Slog.wtfStack(TAG, "Service owner " + owner
+                                    + " cleared while started: pkg=" + mPackage + " service="
+                                    + mName + " proc=" + mProc);
+                        }
                         setStarted(false, 0, now);
                     }
                     if (mBoundState != STATE_NOTHING) {
-                        Slog.wtfStack(TAG, "Service owner " + owner + " cleared while bound: pkg="
-                                + mPackage + " service=" + mName + " proc=" + mProc);
+                        if (!silently) {
+                            Slog.wtfStack(TAG, "Service owner " + owner
+                                    + " cleared while bound: pkg=" + mPackage + " service="
+                                    + mName + " proc=" + mProc);
+                        }
                         setBound(false, 0, now);
                     }
                     if (mExecState != STATE_NOTHING) {
-                        Slog.wtfStack(TAG, "Service owner " + owner + " cleared while exec: pkg="
-                                + mPackage + " service=" + mName + " proc=" + mProc);
+                        if (!silently) {
+                            Slog.wtfStack(TAG, "Service owner " + owner
+                                    + " cleared while exec: pkg=" + mPackage + " service="
+                                    + mName + " proc=" + mProc);
+                        }
                         setExecuting(false, 0, now);
                     }
                 }
+                mOwner = null;
             }
         }
 
diff --git a/core/res/res/values-mcc208-mnc01/config.xml b/core/res/res/values-mcc208-mnc01/config.xml
deleted file mode 100644
index 3b84ff2..0000000
--- a/core/res/res/values-mcc208-mnc01/config.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, 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">
-    <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
-    <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
-    <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
-    <integer-array translatable="false" name="config_tether_upstream_types">
-        <item>1</item>
-        <item>4</item>
-        <item>7</item>
-        <item>9</item>
-    </integer-array>
-
-    <!-- String containing the apn value for tethering.  May be overriden by secure settings
-         TETHER_DUN_APN.  Value is a comma separated series of strings:
-         "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
-         note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
-    <string translatable="false" name="config_tether_apndata">Orange Internet,orange.fr,,,orange,orange,,,,,208,01,1,DUN</string>
-
-</resources>
diff --git a/core/res/res/values-mcc214-mnc03/config.xml b/core/res/res/values-mcc214-mnc03/config.xml
deleted file mode 100644
index 4a51a2f..0000000
--- a/core/res/res/values-mcc214-mnc03/config.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, 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">
-    <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
-    <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
-    <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
-    <integer-array translatable="false" name="config_tether_upstream_types">
-        <item>1</item>
-        <item>4</item>
-        <item>7</item>
-        <item>9</item>
-    </integer-array>
-
-    <!-- String containing the apn value for tethering.  May be overriden by secure settings
-         TETHER_DUN_APN.  Value is a comma separated series of strings:
-         "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
-         note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
-    <string translatable="false" name="config_tether_apndata">Orange Internet PC,internet,,,orange,orange,,,,,214,03,1,DUN</string>
-
-</resources>
diff --git a/core/res/res/values-mcc214-mnc07/config.xml b/core/res/res/values-mcc214-mnc07/config.xml
deleted file mode 100644
index b49ad74..0000000
--- a/core/res/res/values-mcc214-mnc07/config.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, 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">
-    <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
-    <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
-    <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
-    <integer-array translatable="false" name="config_tether_upstream_types">
-        <item>1</item>
-        <item>4</item>
-        <item>7</item>
-        <item>9</item>
-    </integer-array>
-
-    <!-- String containing the apn value for tethering.  May be overriden by secure settings
-         TETHER_DUN_APN.  Value is a comma separated series of strings:
-         "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
-         note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
-    <string translatable="false" name="config_tether_apndata">Conexión Compartida,movistar.es,,,MOVISTAR,MOVISTAR,,,,,214,07,1,DUN</string>
-
-</resources>
diff --git a/core/res/res/values-mcc222-mnc01/config.xml b/core/res/res/values-mcc222-mnc01/config.xml
deleted file mode 100644
index 6bb1196..0000000
--- a/core/res/res/values-mcc222-mnc01/config.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, 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">
-    <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
-    <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
-    <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
-    <integer-array translatable="false" name="config_tether_upstream_types">
-        <item>1</item>
-        <item>4</item>
-        <item>7</item>
-        <item>9</item>
-    </integer-array>
-
-    <!-- String containing the apn value for tethering.  May be overriden by secure settings
-         TETHER_DUN_APN.  Value is a comma separated series of strings:
-         "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
-         note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
-    <string translatable="false" name="config_tether_apndata">TIM WEB,ibox.tim.it,,,,,,,,,222,01,,DUN</string>
-</resources>
diff --git a/core/res/res/values-mcc234-mnc33/config.xml b/core/res/res/values-mcc234-mnc33/config.xml
index 175f76e..776b570 100644
--- a/core/res/res/values-mcc234-mnc33/config.xml
+++ b/core/res/res/values-mcc234-mnc33/config.xml
@@ -20,22 +20,6 @@
 <!-- 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">
-    <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
-    <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
-    <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
-    <integer-array translatable="false" name="config_tether_upstream_types">
-        <item>1</item>
-        <item>4</item>
-        <item>7</item>
-        <item>9</item>
-    </integer-array>
-
-    <!-- String containing the apn value for tethering.  May be overriden by secure settings
-         TETHER_DUN_APN.  Value is a comma separated series of strings:
-         "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
-         note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
-    <string translatable="false" name="config_tether_apndata">Consumer Broadband,consumerbroadband,,,,,,,,,234,33,,DUN</string>
-
     <!-- Don't use roaming icon for considered operators -->
     <string-array translatable="false" name="config_operatorConsideredNonRoaming">
         <item>23430</item>
diff --git a/core/res/res/values-mcc454-mnc03/config.xml b/core/res/res/values-mcc268-mnc03/config.xml
similarity index 91%
copy from core/res/res/values-mcc454-mnc03/config.xml
copy to core/res/res/values-mcc268-mnc03/config.xml
index c7dc960..0d5fe57 100644
--- a/core/res/res/values-mcc454-mnc03/config.xml
+++ b/core/res/res/values-mcc268-mnc03/config.xml
@@ -34,7 +34,7 @@
     <!-- String containing the apn value for tethering.  May be overriden by secure settings
          TETHER_DUN_APN.  Value is a comma separated series of strings:
          "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
-         note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
-    <string translatable="false" name="config_tether_apndata">3 Share,share.lte.three.com.hk,,,,,,,,,454,03,1,DUN</string>
+         note that empty fields can be ommitted: "name,apn,,,,,,,,,310,270,,DUN" -->
+    <string translatable="false" name="config_tether_apndata">Optimus HotSpot,modem,,,,,,,,,268,03,,DUN</string>
 
 </resources>
diff --git a/core/res/res/values-mcc454-mnc03/config.xml b/core/res/res/values-mcc334-mnc050/config.xml
similarity index 91%
rename from core/res/res/values-mcc454-mnc03/config.xml
rename to core/res/res/values-mcc334-mnc050/config.xml
index c7dc960..00c4155 100644
--- a/core/res/res/values-mcc454-mnc03/config.xml
+++ b/core/res/res/values-mcc334-mnc050/config.xml
@@ -35,6 +35,6 @@
          TETHER_DUN_APN.  Value is a comma separated series of strings:
          "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
          note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
-    <string translatable="false" name="config_tether_apndata">3 Share,share.lte.three.com.hk,,,,,,,,,454,03,1,DUN</string>
+    <string translatable="false" name="config_tether_apndata">Modem,modem.iusacellgsm.mx,,,iusacellgsm,iusacellgsm,,,,,334,050,1,DUN</string>
 
 </resources>
diff --git a/core/res/res/values-mcc340-mnc01/config.xml b/core/res/res/values-mcc340-mnc01/config.xml
index fb71f3bc..bbab4ad 100644
--- a/core/res/res/values-mcc340-mnc01/config.xml
+++ b/core/res/res/values-mcc340-mnc01/config.xml
@@ -34,5 +34,5 @@
          TETHER_DUN_APN.  Value is a comma separated series of strings:
          "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
          note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
-    <string translatable="false" name="config_tether_apndata">Orangeweb,orangeweb,,,,,,orange,orange,,340,01,1,DUN</string>
+    <string translatable="false" name="config_tether_apndata">Orangeweb,orangeweb,,,orange,orange,,,,,340,01,1,DUN</string>
 </resources>
diff --git a/core/res/res/values-mcc454-mnc00/config.xml b/core/res/res/values-mcc454-mnc00/config.xml
deleted file mode 100644
index c92b9c7..0000000
--- a/core/res/res/values-mcc454-mnc00/config.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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 my 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. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
-    <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
-    <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
-    <integer-array translatable="false" name="config_tether_upstream_types">
-      <item>1</item>
-      <item>4</item>
-      <item>7</item>
-      <item>9</item>
-    </integer-array>
-
-    <!-- String containing the apn value for tethering.  May be overriden by secure settings
-         TETHER_DUN_APN.  Value is a comma separated series of strings:
-         "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
-         note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
-    <string translatable="false" name="config_tether_apndata">1O1O tethering,lte.internet,,,,,,,,,454,00,3,DUN</string>
-
-</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 196be74..42ea384 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -588,6 +588,9 @@
     <!-- Disable lockscreen translucent decor by default -->
     <bool name="config_enableLockScreenTranslucentDecor">false</bool>
 
+    <!-- Enable translucent decor by default -->
+    <bool name="config_enableTranslucentDecor">true</bool>
+
     <!-- Enable puk unlockscreen by default.
          If unlock screen is disabled, the puk should be unlocked through Emergency Dialer -->
     <bool name="config_enable_puk_unlock_screen">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0b050c7..611c085 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1295,6 +1295,7 @@
   <java-symbol type="bool" name="config_enableLockBeforeUnlockScreen" />
   <java-symbol type="bool" name="config_enableLockScreenRotation" />
   <java-symbol type="bool" name="config_enableLockScreenTranslucentDecor" />
+  <java-symbol type="bool" name="config_enableTranslucentDecor" />
   <java-symbol type="bool" name="config_lidControlsSleep" />
   <java-symbol type="bool" name="config_reverseDefaultRotation" />
   <java-symbol type="bool" name="config_showNavigationBar" />
diff --git a/packages/DocumentsUI/res/values-sw720dp/styles.xml b/packages/DocumentsUI/res/values-sw720dp/styles.xml
index a581e08..19d2ebe 100644
--- a/packages/DocumentsUI/res/values-sw720dp/styles.xml
+++ b/packages/DocumentsUI/res/values-sw720dp/styles.xml
@@ -20,5 +20,6 @@
         <item name="android:windowBackground">@*android:drawable/dialog_full_holo_light</item>
         <item name="android:colorBackgroundCacheHint">@null</item>
         <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowAnimationStyle">@*android:style/Animation.Holo.Dialog</item>
     </style>
 </resources>
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 189e985..11ff2d8 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -27,6 +27,7 @@
 import android.os.ParcelFileDescriptor;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract;
 import android.provider.DocumentsProvider;
 import android.webkit.MimeTypeMap;
 
@@ -313,19 +314,7 @@
             String documentId, Point sizeHint, CancellationSignal signal)
             throws FileNotFoundException {
         final File file = getFileForDocId(documentId);
-        final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
-                file, ParcelFileDescriptor.MODE_READ_ONLY);
-
-        try {
-            final ExifInterface exif = new ExifInterface(file.getAbsolutePath());
-            final long[] thumb = exif.getThumbnailRange();
-            if (thumb != null) {
-                return new AssetFileDescriptor(pfd, thumb[0], thumb[1]);
-            }
-        } catch (IOException e) {
-        }
-
-        return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH);
+        return DocumentsContract.openImageThumbnail(file);
     }
 
     private static String getTypeForFile(File file) {
diff --git a/packages/Keyguard/res/values-mcc262-mnc08/bools.xml b/packages/Keyguard/res/values-mcc262-mnc08/bools.xml
new file mode 100644
index 0000000..6cd4c55
--- /dev/null
+++ b/packages/Keyguard/res/values-mcc262-mnc08/bools.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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>
+    <!-- Carriers in this locale are sensitive to capitalization of carrier text. 
+         This makes the entire interface consistent by switching back to normal case. -->
+    <bool name="kg_use_all_caps">false</bool>
+</resources>
diff --git a/packages/Keyguard/res/values-mcc262-mnc11/bools.xml b/packages/Keyguard/res/values-mcc262-mnc11/bools.xml
new file mode 100644
index 0000000..6cd4c55
--- /dev/null
+++ b/packages/Keyguard/res/values-mcc262-mnc11/bools.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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>
+    <!-- Carriers in this locale are sensitive to capitalization of carrier text. 
+         This makes the entire interface consistent by switching back to normal case. -->
+    <bool name="kg_use_all_caps">false</bool>
+</resources>
diff --git a/packages/PrintSpooler/res/drawable-hdpi/ic_menu_print.png b/packages/PrintSpooler/res/drawable-hdpi/ic_menu_print.png
new file mode 100644
index 0000000..09ab1a2
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-hdpi/ic_menu_print.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-mdpi/ic_menu_print.png b/packages/PrintSpooler/res/drawable-mdpi/ic_menu_print.png
new file mode 100644
index 0000000..637d94e
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-mdpi/ic_menu_print.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_print.png b/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_print.png
new file mode 100644
index 0000000..4d4b3cc
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_print.png
Binary files differ
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
index 83019b9..02740a3 100644
--- a/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
@@ -107,7 +107,7 @@
                     android:layout_marginStart="36dip"
                     android:textAppearance="@style/PrintOptionTitleTextAppearance"
                     android:labelFor="@+id/range_options_spinner"
-                    android:text="@string/label_pages">
+                    android:text="@string/page_count_unknown">
                 </TextView>
 
                 <Spinner
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 22a9950..2997707 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -1248,13 +1248,20 @@
                                     continue;
                                 }
 
+                                // If nothing changed - done.
+                                if (mCurrentPrinter.equals(printer)) {
+                                    return;
+                                }
+
                                 // If the current printer became available and has no
                                 // capabilities, we refresh it.
                                 if (mCurrentPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE
                                         && printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE
-                                        && printer.getCapabilities() == null
-                                        && !mCapabilitiesTimeout.isPosted()) {
-                                    mCapabilitiesTimeout.post();
+                                        && printer.getCapabilities() == null) {
+                                    if (!mCapabilitiesTimeout.isPosted()) {
+                                        mCapabilitiesTimeout.post();
+                                    }
+                                    mCurrentPrinter.copyFrom(printer);
                                     refreshCurrentPrinter();
                                     return;
                                 }
@@ -1268,10 +1275,10 @@
                                         && printer.getCapabilities() == null)) {
                                     if (!mCapabilitiesTimeout.isPosted()) {
                                         mCapabilitiesTimeout.post();
-                                        mCurrentPrinter.copyFrom(printer);
-                                        updateUi();
-                                        return;
                                     }
+                                    mCurrentPrinter.copyFrom(printer);
+                                    updateUi();
+                                    return;
                                 }
 
                                 // We just refreshed the current printer.
@@ -2168,10 +2175,17 @@
                 mIsPosted = false;
                 if (mDestinationSpinner.getSelectedItemPosition() >= 0) {
                     View itemView = mDestinationSpinner.getSelectedView();
-                    TextView titleView = (TextView) itemView.findViewById(R.id.title);
-                    String title = getString(R.string.printer_unavailable,
-                            mCurrentPrinter.getName());
-                    titleView.setText(title);
+                    TextView titleView = (TextView) itemView.findViewById(R.id.subtitle);
+                    try {
+                        PackageInfo packageInfo = getPackageManager().getPackageInfo(
+                                mCurrentPrinter.getId().getServiceName().getPackageName(), 0);
+                        CharSequence service = packageInfo.applicationInfo.loadLabel(
+                                getPackageManager());
+                        String subtitle = getString(R.string.printer_unavailable, service.toString());
+                        titleView.setText(subtitle);
+                    } catch (NameNotFoundException nnfe) {
+                        /* ignore */
+                    }
                 }
             }
         }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
index d688932..be94ba4 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
@@ -93,6 +93,7 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setHasOptionsMenu(true);
+        getActivity().getActionBar().setIcon(R.drawable.ic_menu_print);
     }
 
     @Override
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index ab2feb9..783aa03 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -8,7 +8,7 @@
                  android:process="system"
                  android:backupAgent="SettingsBackupAgent"
                  android:killAfterRestore="false"
-                 android:icon="@drawable/ic_launcher_settings">
+                 android:icon="@mipmap/ic_launcher_settings">
                  
     <!-- todo add: android:neverEncrypt="true" -->
 
diff --git a/packages/SettingsProvider/res/drawable-hdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/drawable-hdpi/ic_launcher_settings.png
deleted file mode 100644
index 8a5a2f7..0000000
--- a/packages/SettingsProvider/res/drawable-hdpi/ic_launcher_settings.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsProvider/res/drawable-mdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/drawable-mdpi/ic_launcher_settings.png
deleted file mode 100644
index 803439f..0000000
--- a/packages/SettingsProvider/res/drawable-mdpi/ic_launcher_settings.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsProvider/res/drawable-xhdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/drawable-xhdpi/ic_launcher_settings.png
deleted file mode 100644
index ec3c8ea..0000000
--- a/packages/SettingsProvider/res/drawable-xhdpi/ic_launcher_settings.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsProvider/res/mipmap-hdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/mipmap-hdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..a8ccc89
--- /dev/null
+++ b/packages/SettingsProvider/res/mipmap-hdpi/ic_launcher_settings.png
Binary files differ
diff --git a/packages/SettingsProvider/res/mipmap-mdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/mipmap-mdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..69709a8
--- /dev/null
+++ b/packages/SettingsProvider/res/mipmap-mdpi/ic_launcher_settings.png
Binary files differ
diff --git a/packages/SettingsProvider/res/mipmap-xhdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/mipmap-xhdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..c3adce61
--- /dev/null
+++ b/packages/SettingsProvider/res/mipmap-xhdpi/ic_launcher_settings.png
Binary files differ
diff --git a/packages/SettingsProvider/res/mipmap-xxhdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/mipmap-xxhdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..52fe978
--- /dev/null
+++ b/packages/SettingsProvider/res/mipmap-xxhdpi/ic_launcher_settings.png
Binary files differ
diff --git a/packages/SettingsProvider/res/mipmap-xxxhdpi/ic_launcher_settings.png b/packages/SettingsProvider/res/mipmap-xxxhdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..6b92795
--- /dev/null
+++ b/packages/SettingsProvider/res/mipmap-xxxhdpi/ic_launcher_settings.png
Binary files differ
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index bc02b0d..158227f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -47,6 +47,7 @@
 import android.os.DropBoxManager;
 import android.os.FileObserver;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -62,6 +63,8 @@
     private static final String TAG = "SettingsProvider";
     private static final boolean LOCAL_LOGV = false;
 
+    private static final boolean USER_CHECK_THROWS = true;
+
     private static final String TABLE_SYSTEM = "system";
     private static final String TABLE_SECURE = "secure";
     private static final String TABLE_GLOBAL = "global";
@@ -522,6 +525,14 @@
 
     // Lazy initialize the database helper and caches for this user, if necessary
     private DatabaseHelper getOrEstablishDatabase(int callingUser) {
+        if (callingUser >= Process.SYSTEM_UID) {
+            if (USER_CHECK_THROWS) {
+                throw new IllegalArgumentException("Uid rather than user handle: " + callingUser);
+            } else {
+                Slog.wtf(TAG, "establish db for uid rather than user: " + callingUser);
+            }
+        }
+
         long oldId = Binder.clearCallingIdentity();
         try {
             DatabaseHelper dbHelper = mOpenHelpers.get(callingUser);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index e6823ac..2026102 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -310,6 +310,7 @@
         refreshBrightnessTile();
         refreshRotationLockTile();
         refreshRssiTile();
+        refreshLocationTile();
     }
 
     // Settings
@@ -582,6 +583,12 @@
         mLocationCallback.refreshView(mLocationTile, mLocationState);
     }
 
+    void refreshLocationTile() {
+        if (mLocationTile != null) {
+            onLocationSettingsChanged(mLocationState.enabled);
+        }
+    }
+
     @Override
     public void onLocationSettingsChanged(boolean locationEnabled) {
         int textResId = locationEnabled ? R.string.quick_settings_location_label
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java
index 36cb438..af4199c 100644
--- a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java
+++ b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java
@@ -63,7 +63,7 @@
         // Guarded by locks
         public float scale;
         public int centerX, centerY;
-        int rotation;
+        public int rotation;
         public TileSource source;
         Runnable isReadyCallback;
 
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
index b4e715c..14f7c1d 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
@@ -17,9 +17,11 @@
 package com.android.wallpapercropper;
 
 import android.content.Context;
+import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.RectF;
 import android.util.AttributeSet;
+import android.util.FloatMath;
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
 import android.view.ScaleGestureDetector.OnScaleGestureListener;
@@ -36,10 +38,18 @@
     private long mTouchDownTime;
     private float mFirstX, mFirstY;
     private float mLastX, mLastY;
+    private float mCenterX, mCenterY;
     private float mMinScale;
     private boolean mTouchEnabled = true;
     private RectF mTempEdges = new RectF();
+    private float[] mTempPoint = new float[] { 0, 0 };
+    private float[] mTempCoef = new float[] { 0, 0 };
+    private float[] mTempAdjustment = new float[] { 0, 0 };
+    private float[] mTempImageDims = new float[] { 0, 0 };
+    private float[] mTempRendererCenter = new float[] { 0, 0 };
     TouchCallback mTouchCallback;
+    Matrix mRotateMatrix;
+    Matrix mInverseRotateMatrix;
 
     public interface TouchCallback {
         void onTouchDown();
@@ -54,17 +64,43 @@
     public CropView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mScaleGestureDetector = new ScaleGestureDetector(context, this);
+        mRotateMatrix = new Matrix();
+        mInverseRotateMatrix = new Matrix();
+    }
+
+    private float[] getImageDims() {
+        final float imageWidth = mRenderer.source.getImageWidth();
+        final float imageHeight = mRenderer.source.getImageHeight();
+        float[] imageDims = mTempImageDims;
+        imageDims[0] = imageWidth;
+        imageDims[1] = imageHeight;
+        mRotateMatrix.mapPoints(imageDims);
+        imageDims[0] = Math.abs(imageDims[0]);
+        imageDims[1] = Math.abs(imageDims[1]);
+        return imageDims;
     }
 
     private void getEdgesHelper(RectF edgesOut) {
         final float width = getWidth();
         final float height = getHeight();
-        final float imageWidth = mRenderer.source.getImageWidth();
-        final float imageHeight = mRenderer.source.getImageHeight();
+        final float[] imageDims = getImageDims();
+        final float imageWidth = imageDims[0];
+        final float imageHeight = imageDims[1];
+
+        float initialCenterX = mRenderer.source.getImageWidth() / 2f;
+        float initialCenterY = mRenderer.source.getImageHeight() / 2f;
+
+        float[] rendererCenter = mTempRendererCenter;
+        rendererCenter[0] = mCenterX - initialCenterX;
+        rendererCenter[1] = mCenterY - initialCenterY;
+        mRotateMatrix.mapPoints(rendererCenter);
+        rendererCenter[0] += imageWidth / 2;
+        rendererCenter[1] += imageHeight / 2;
+
         final float scale = mRenderer.scale;
-        float centerX = (width / 2f - mRenderer.centerX + (imageWidth - width) / 2f)
+        float centerX = (width / 2f - rendererCenter[0] + (imageWidth - width) / 2f)
                 * scale + width / 2f;
-        float centerY = (height / 2f - mRenderer.centerY + (imageHeight - height) / 2f)
+        float centerY = (height / 2f - rendererCenter[1] + (imageHeight - height) / 2f)
                 * scale + height / 2f;
         float leftEdge = centerX - imageWidth / 2f * scale;
         float rightEdge = centerX + imageWidth / 2f * scale;
@@ -77,6 +113,10 @@
         edgesOut.bottom = bottomEdge;
     }
 
+    public int getImageRotation() {
+        return mRenderer.rotation;
+    }
+
     public RectF getCrop() {
         final RectF edges = mTempEdges;
         getEdgesHelper(edges);
@@ -96,6 +136,12 @@
 
     public void setTileSource(TileSource source, Runnable isReadyCallback) {
         super.setTileSource(source, isReadyCallback);
+        mCenterX = mRenderer.centerX;
+        mCenterY = mRenderer.centerY;
+        mRotateMatrix.reset();
+        mRotateMatrix.setRotate(mRenderer.rotation);
+        mInverseRotateMatrix.reset();
+        mInverseRotateMatrix.setRotate(-mRenderer.rotation);
         updateMinScale(getWidth(), getHeight(), source, true);
     }
 
@@ -115,8 +161,10 @@
                 mRenderer.scale = 1;
             }
             if (source != null) {
-                mMinScale = Math.max(w / (float) source.getImageWidth(),
-                        h / (float) source.getImageHeight());
+                final float[] imageDims = getImageDims();
+                final float imageWidth = imageDims[0];
+                final float imageHeight = imageDims[1];
+                mMinScale = Math.max(w / imageWidth, h / imageHeight);
                 mRenderer.scale = Math.max(mMinScale, mRenderer.scale);
             }
         }
@@ -154,7 +202,13 @@
         final RectF edges = mTempEdges;
         getEdgesHelper(edges);
         final float scale = mRenderer.scale;
-        mRenderer.centerX += Math.ceil(edges.left / scale);
+        mCenterX += Math.ceil(edges.left / scale);
+        updateCenter();
+    }
+
+    private void updateCenter() {
+        mRenderer.centerX = Math.round(mCenterX);
+        mRenderer.centerY = Math.round(mCenterY);
     }
 
     public void setTouchEnabled(boolean enabled) {
@@ -200,7 +254,7 @@
             if (mTouchCallback != null) {
                 // only do this if it's a small movement
                 if (squaredDist < slop &&
-                    now < mTouchDownTime + ViewConfiguration.getTapTimeout()) {
+                        now < mTouchDownTime + ViewConfiguration.getTapTimeout()) {
                     mTouchCallback.onTap();
                 }
                 mTouchCallback.onTouchUp();
@@ -215,8 +269,13 @@
             mScaleGestureDetector.onTouchEvent(event);
             switch (action) {
                 case MotionEvent.ACTION_MOVE:
-                    mRenderer.centerX += (mLastX - x) / mRenderer.scale;
-                    mRenderer.centerY += (mLastY - y) / mRenderer.scale;
+                    float[] point = mTempPoint;
+                    point[0] = (mLastX - x) / mRenderer.scale;
+                    point[1] = (mLastY - y) / mRenderer.scale;
+                    mInverseRotateMatrix.mapPoints(point);
+                    mCenterX += point[0];
+                    mCenterY += point[1];
+                    updateCenter();
                     invalidate();
                     break;
             }
@@ -226,18 +285,32 @@
                 final RectF edges = mTempEdges;
                 getEdgesHelper(edges);
                 final float scale = mRenderer.scale;
+
+                float[] coef = mTempCoef;
+                coef[0] = 1;
+                coef[1] = 1;
+                mRotateMatrix.mapPoints(coef);
+                float[] adjustment = mTempAdjustment;
+                mTempAdjustment[0] = 0;
+                mTempAdjustment[1] = 0;
                 if (edges.left > 0) {
-                    mRenderer.centerX += Math.ceil(edges.left / scale);
-                }
-                if (edges.right < getWidth()) {
-                    mRenderer.centerX += (edges.right - getWidth()) / scale;
+                    adjustment[0] = edges.left / scale;
+                } else if (edges.right < getWidth()) {
+                    adjustment[0] = (edges.right - getWidth()) / scale;
                 }
                 if (edges.top > 0) {
-                    mRenderer.centerY += Math.ceil(edges.top / scale);
+                    adjustment[1] = FloatMath.ceil(edges.top / scale);
+                } else if (edges.bottom < getHeight()) {
+                    adjustment[1] = (edges.bottom - getHeight()) / scale;
                 }
-                if (edges.bottom < getHeight()) {
-                    mRenderer.centerY += (edges.bottom - getHeight()) / scale;
+                for (int dim = 0; dim <= 1; dim++) {
+                    if (coef[dim] > 0) adjustment[dim] = FloatMath.ceil(adjustment[dim]);
                 }
+
+                mInverseRotateMatrix.mapPoints(adjustment);
+                mCenterX += adjustment[0];
+                mCenterY += adjustment[1];
+                updateCenter();
             }
         }
 
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
index 710e8e4..1209e56 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -37,12 +37,14 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.util.FloatMath;
 import android.util.Log;
 import android.view.Display;
 import android.view.View;
 import android.view.WindowManager;
 
 import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.exif.ExifInterface;
 import com.android.photos.BitmapRegionTileSource;
 
 import java.io.BufferedInputStream;
@@ -85,10 +87,17 @@
 
         mCropView = (CropView) findViewById(R.id.cropView);
 
-        Intent cropIntent = this.getIntent();
+        Intent cropIntent = getIntent();
         final Uri imageUri = cropIntent.getData();
 
-        mCropView.setTileSource(new BitmapRegionTileSource(this, imageUri, 1024, 0), null);
+        if (imageUri == null) {
+            Log.e(LOGTAG, "No URI passed in intent, exiting WallpaperCropActivity");
+            finish();
+            return;
+        }
+
+        int rotation = getRotationFromExif(this, imageUri);
+        mCropView.setTileSource(new BitmapRegionTileSource(this, imageUri, 1024, rotation), null);
         mCropView.setTouchEnabled(true);
         // Action bar
         // Show the custom action bar view
@@ -102,8 +111,6 @@
                         cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone);
                     }
                 });
-        getWindow().addPrivateFlags(
-                WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR);
     }
 
     public boolean enableRotation() {
@@ -170,9 +177,47 @@
         return new Point(defaultWidth, defaultHeight);
     }
 
+    public static int getRotationFromExif(String path) {
+        return getRotationFromExifHelper(path, null, 0, null, null);
+    }
+
+    public static int getRotationFromExif(Context context, Uri uri) {
+        return getRotationFromExifHelper(null, null, 0, context, uri);
+    }
+
+    public static int getRotationFromExif(Resources res, int resId) {
+        return getRotationFromExifHelper(null, res, resId, null, null);
+    }
+
+    private static int getRotationFromExifHelper(
+            String path, Resources res, int resId, Context context, Uri uri) {
+        ExifInterface ei = new ExifInterface();
+        try {
+            if (path != null) {
+                ei.readExif(path);
+            } else if (uri != null) {
+                InputStream is = context.getContentResolver().openInputStream(uri);
+                BufferedInputStream bis = new BufferedInputStream(is);
+                ei.readExif(bis);
+            } else {
+                InputStream is = res.openRawResource(resId);
+                BufferedInputStream bis = new BufferedInputStream(is);
+                ei.readExif(bis);
+            }
+            Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION);
+            if (ori != null) {
+                return ExifInterface.getRotationForOrientationValue(ori.shortValue());
+            }
+        } catch (IOException e) {
+            Log.w(LOGTAG, "Getting exif data failed", e);
+        }
+        return 0;
+    }
+
     protected void setWallpaper(String filePath, final boolean finishActivityWhenDone) {
-        BitmapCropTask cropTask = new BitmapCropTask(this,
-                filePath, null, 0, 0, true, false, null);
+        int rotation = getRotationFromExif(filePath);
+        BitmapCropTask cropTask = new BitmapCropTask(
+                this, filePath, null, rotation, 0, 0, true, false, null);
         final Point bounds = cropTask.getImageBounds();
         Runnable onEndCrop = new Runnable() {
             public void run() {
@@ -192,6 +237,7 @@
             Resources res, int resId, final boolean finishActivityWhenDone) {
         // crop this image and scale it down to the default wallpaper size for
         // this device
+        int rotation = getRotationFromExif(res, resId);
         Point inSize = mCropView.getSourceDimensions();
         Point outSize = getDefaultWallpaperSize(getResources(),
                 getWindowManager());
@@ -209,8 +255,7 @@
             }
         };
         BitmapCropTask cropTask = new BitmapCropTask(this, res, resId,
-                crop, outSize.x, outSize.y,
-                true, false, onEndCrop);
+                crop, rotation, outSize.x, outSize.y, true, false, onEndCrop);
         cropTask.execute();
     }
 
@@ -222,8 +267,6 @@
     protected void cropImageAndSetWallpaper(Uri uri,
             OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) {
         // Get the crop
-        Point inSize = mCropView.getSourceDimensions();
-
         boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
 
         Point minDims = new Point();
@@ -262,12 +305,21 @@
         }
         // Get the crop
         RectF cropRect = mCropView.getCrop();
+        int cropRotation = mCropView.getImageRotation();
         float cropScale = mCropView.getWidth() / (float) cropRect.width();
 
+        Point inSize = mCropView.getSourceDimensions();
+        Matrix rotateMatrix = new Matrix();
+        rotateMatrix.setRotate(cropRotation);
+        float[] rotatedInSize = new float[] { inSize.x, inSize.y };
+        rotateMatrix.mapPoints(rotatedInSize);
+        rotatedInSize[0] = Math.abs(rotatedInSize[0]);
+        rotatedInSize[1] = Math.abs(rotatedInSize[1]);
+
         // ADJUST CROP WIDTH
         // Extend the crop all the way to the right, for parallax
         // (or all the way to the left, in RTL)
-        float extraSpace = ltr ? inSize.x - cropRect.right : cropRect.left;
+        float extraSpace = ltr ? rotatedInSize[0] - cropRect.right : cropRect.left;
         // Cap the amount of extra width
         float maxExtraSpace = defaultWallpaperWidth / cropScale - cropRect.width();
         extraSpace = Math.min(extraSpace, maxExtraSpace);
@@ -285,7 +337,7 @@
             float extraPortraitHeight =
                     portraitHeight / cropScale - cropRect.height();
             float expandHeight =
-                    Math.min(Math.min(inSize.y - cropRect.bottom, cropRect.top),
+                    Math.min(Math.min(rotatedInSize[1] - cropRect.bottom, cropRect.top),
                             extraPortraitHeight / 2);
             cropRect.top -= expandHeight;
             cropRect.bottom += expandHeight;
@@ -303,7 +355,7 @@
             }
         };
         BitmapCropTask cropTask = new BitmapCropTask(this, uri,
-                cropRect, outWidth, outHeight, true, false, onEndCrop);
+                cropRect, cropRotation, outWidth, outHeight, true, false, onEndCrop);
         if (onBitmapCroppedHandler != null) {
             cropTask.setOnBitmapCropped(onBitmapCroppedHandler);
         }
@@ -323,7 +375,7 @@
         InputStream mInStream;
         RectF mCropBounds = null;
         int mOutWidth, mOutHeight;
-        int mRotation = 0; // for now
+        int mRotation;
         String mOutputFormat = "jpg"; // for now
         boolean mSetWallpaper;
         boolean mSaveCroppedBitmap;
@@ -334,40 +386,45 @@
         boolean mNoCrop;
 
         public BitmapCropTask(Context c, String filePath,
-                RectF cropBounds, int outWidth, int outHeight,
+                RectF cropBounds, int rotation, int outWidth, int outHeight,
                 boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
             mContext = c;
             mInFilePath = filePath;
-            init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+            init(cropBounds, rotation,
+                    outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
         }
 
         public BitmapCropTask(byte[] imageBytes,
-                RectF cropBounds, int outWidth, int outHeight,
+                RectF cropBounds, int rotation, int outWidth, int outHeight,
                 boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
             mInImageBytes = imageBytes;
-            init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+            init(cropBounds, rotation,
+                    outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
         }
 
         public BitmapCropTask(Context c, Uri inUri,
-                RectF cropBounds, int outWidth, int outHeight,
+                RectF cropBounds, int rotation, int outWidth, int outHeight,
                 boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
             mContext = c;
             mInUri = inUri;
-            init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+            init(cropBounds, rotation,
+                    outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
         }
 
         public BitmapCropTask(Context c, Resources res, int inResId,
-                RectF cropBounds, int outWidth, int outHeight,
+                RectF cropBounds, int rotation, int outWidth, int outHeight,
                 boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
             mContext = c;
             mInResId = inResId;
             mResources = res;
-            init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+            init(cropBounds, rotation,
+                    outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
         }
 
-        private void init(RectF cropBounds, int outWidth, int outHeight,
+        private void init(RectF cropBounds, int rotation, int outWidth, int outHeight,
                 boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
             mCropBounds = cropBounds;
+            mRotation = rotation;
             mOutWidth = outWidth;
             mOutHeight = outHeight;
             mSetWallpaper = setWallpaper;
@@ -454,6 +511,29 @@
             if (mInStream != null) {
                 // Find crop bounds (scaled to original image size)
                 Rect roundedTrueCrop = new Rect();
+                Matrix rotateMatrix = new Matrix();
+                Matrix inverseRotateMatrix = new Matrix();
+                if (mRotation > 0) {
+                    rotateMatrix.setRotate(mRotation);
+                    inverseRotateMatrix.setRotate(-mRotation);
+
+                    mCropBounds.roundOut(roundedTrueCrop);
+                    mCropBounds = new RectF(roundedTrueCrop);
+
+                    Point bounds = getImageBounds();
+
+                    float[] rotatedBounds = new float[] { bounds.x, bounds.y };
+                    rotateMatrix.mapPoints(rotatedBounds);
+                    rotatedBounds[0] = Math.abs(rotatedBounds[0]);
+                    rotatedBounds[1] = Math.abs(rotatedBounds[1]);
+
+                    mCropBounds.offset(-rotatedBounds[0]/2, -rotatedBounds[1]/2);
+                    inverseRotateMatrix.mapRect(mCropBounds);
+                    mCropBounds.offset(bounds.x/2, bounds.y/2);
+
+                    regenerateInputStream();
+                }
+
                 mCropBounds.roundOut(roundedTrueCrop);
 
                 if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) {
@@ -497,6 +577,12 @@
                         fullSize = BitmapFactory.decodeStream(mInStream, null, options);
                     }
                     if (fullSize != null) {
+                        mCropBounds.left /= scaleDownSampleSize;
+                        mCropBounds.top /= scaleDownSampleSize;
+                        mCropBounds.bottom /= scaleDownSampleSize;
+                        mCropBounds.right /= scaleDownSampleSize;
+                        mCropBounds.roundOut(roundedTrueCrop);
+
                         crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left,
                                 roundedTrueCrop.top, roundedTrueCrop.width(),
                                 roundedTrueCrop.height());
@@ -508,16 +594,40 @@
                     failure = true;
                     return false;
                 }
-                if (mOutWidth > 0 && mOutHeight > 0) {
-                    Matrix m = new Matrix();
-                    RectF cropRect = new RectF(0, 0, crop.getWidth(), crop.getHeight());
-                    if (mRotation > 0) {
-                        m.setRotate(mRotation);
-                        m.mapRect(cropRect);
+                if (mOutWidth > 0 && mOutHeight > 0 || mRotation > 0) {
+                    float[] dimsAfter = new float[] { crop.getWidth(), crop.getHeight() };
+                    rotateMatrix.mapPoints(dimsAfter);
+                    dimsAfter[0] = Math.abs(dimsAfter[0]);
+                    dimsAfter[1] = Math.abs(dimsAfter[1]);
+
+                    if (!(mOutWidth > 0 && mOutHeight > 0)) {
+                        mOutWidth = Math.round(dimsAfter[0]);
+                        mOutHeight = Math.round(dimsAfter[1]);
                     }
+
+                    RectF cropRect = new RectF(0, 0, dimsAfter[0], dimsAfter[1]);
                     RectF returnRect = new RectF(0, 0, mOutWidth, mOutHeight);
-                    m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
-                    m.preRotate(mRotation);
+
+                    Matrix m = new Matrix();
+                    if (mRotation == 0) {
+                        m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
+                    } else {
+                        Matrix m1 = new Matrix();
+                        m1.setTranslate(-crop.getWidth() / 2f, -crop.getHeight() / 2f);
+                        Matrix m2 = new Matrix();
+                        m2.setRotate(mRotation);
+                        Matrix m3 = new Matrix();
+                        m3.setTranslate(dimsAfter[0] / 2f, dimsAfter[1] / 2f);
+                        Matrix m4 = new Matrix();
+                        m4.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
+
+                        Matrix c1 = new Matrix();
+                        c1.setConcat(m2, m1);
+                        Matrix c2 = new Matrix();
+                        c2.setConcat(m4, m3);
+                        m.setConcat(c2, c1);
+                    }
+
                     Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(),
                             (int) returnRect.height(), Bitmap.Config.ARGB_8888);
                     if (tmp != null) {
@@ -527,14 +637,6 @@
                         c.drawBitmap(crop, m, p);
                         crop = tmp;
                     }
-                } else if (mRotation > 0) {
-                    Matrix m = new Matrix();
-                    m.setRotate(mRotation);
-                    Bitmap tmp = Bitmap.createBitmap(crop, 0, 0, crop.getWidth(),
-                            crop.getHeight(), m, true);
-                    if (tmp != null) {
-                        crop = tmp;
-                    }
                 }
 
                 if (mSaveCroppedBitmap) {
@@ -603,8 +705,7 @@
             final SharedPreferences sharedPrefs,
             WindowManager windowManager,
             final WallpaperManager wallpaperManager) {
-        final Point defaultWallpaperSize =
-                WallpaperCropActivity.getDefaultWallpaperSize(res, windowManager);
+        final Point defaultWallpaperSize = getDefaultWallpaperSize(res, windowManager);
 
         new Thread("suggestWallpaperDimension") {
             public void run() {
@@ -616,7 +717,6 @@
         }.start();
     }
 
-
     protected static RectF getMaxCropRect(
             int inWidth, int inHeight, int outWidth, int outHeight, boolean leftAligned) {
         RectF cropRect = new RectF();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 5ac3ed0..1c43014 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -297,6 +297,7 @@
     int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     boolean mHasSoftInput = false;
     boolean mTouchExplorationEnabled = false;
+    boolean mTranslucentDecorEnabled = true;
 
     int mPointerLocationMode = 0; // guarded by mLock
 
@@ -901,6 +902,8 @@
                 com.android.internal.R.integer.config_lidNavigationAccessibility);
         mLidControlsSleep = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_lidControlsSleep);
+        mTranslucentDecorEnabled = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableTranslucentDecor);
         readConfigurationDependentBehaviors();
 
         // register for dock events
@@ -2703,7 +2706,7 @@
             boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
             boolean navAllowedHidden = immersive || immersiveSticky;
             navTranslucent &= !immersiveSticky;  // transient trumps translucent
-            navTranslucent &= isTranslucentNavigationAllowed();
+            navTranslucent &= areTranslucentBarsAllowed();
 
             // When the navigation bar isn't visible, we put up a fake
             // input window to catch all touch events.  This way we can
@@ -2824,6 +2827,7 @@
 
                 boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
                 boolean statusBarTranslucent = (sysui & View.STATUS_BAR_TRANSLUCENT) != 0;
+                statusBarTranslucent &= areTranslucentBarsAllowed();
 
                 // If the status bar is hidden, we don't want to cause
                 // windows behind it to scroll.
@@ -3565,7 +3569,8 @@
     }
 
     public boolean allowAppAnimationsLw() {
-        if (mKeyguard != null && mKeyguard.isVisibleLw() || mShowingDream) {
+        if (mKeyguard != null && mKeyguard.isVisibleLw() && !mKeyguard.isAnimatingLw()
+                || mShowingDream) {
             // If keyguard or dreams is currently visible, no reason to animate behind it.
             return false;
         }
@@ -5116,8 +5121,8 @@
             vis = (vis & ~flags) | (oldVis & flags);
         }
 
-        if (!isTranslucentNavigationAllowed()) {
-            vis &= ~View.NAVIGATION_BAR_TRANSLUCENT;
+        if (!areTranslucentBarsAllowed()) {
+            vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT);
         }
 
         // update status bar
@@ -5182,11 +5187,13 @@
     }
 
     /**
-     * @return whether the navigation bar can be made translucent, e.g. touch
-     *         exploration is not enabled
+     * @return whether the navigation or status bar can be made translucent
+     *
+     * This should return true unless touch exploration is not enabled or
+     * R.boolean.config_enableTranslucentDecor is false.
      */
-    private boolean isTranslucentNavigationAllowed() {
-        return !mTouchExplorationEnabled;
+    private boolean areTranslucentBarsAllowed() {
+        return mTranslucentDecorEnabled && !mTouchExplorationEnabled;
     }
 
     // Use this instead of checking config_showNavigationBar so that it can be consistently
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index b69a0c8..a64940c 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -1494,7 +1494,7 @@
                     } catch (Exception e) {
                         Slog.w(TAG, "Exception when unbinding service "
                                 + r.shortName, e);
-                        serviceDoneExecutingLocked(r, true, true);
+                        serviceProcessGoneLocked(r);
                     }
                 }
             }
@@ -1544,7 +1544,7 @@
                 } catch (Exception e) {
                     Slog.w(TAG, "Exception when destroying service "
                             + r.shortName, e);
-                    serviceDoneExecutingLocked(r, true, true);
+                    serviceProcessGoneLocked(r);
                 }
                 updateServiceForegroundLocked(r.app, false);
             } else {
@@ -1570,7 +1570,7 @@
             r.tracker.setStarted(false, memFactor, now);
             r.tracker.setBound(false, memFactor, now);
             if (r.executeNesting == 0) {
-                r.tracker.clearCurrentOwner(r);
+                r.tracker.clearCurrentOwner(r, false);
                 r.tracker = null;
             }
         }
@@ -1629,7 +1629,7 @@
                     s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
                 } catch (Exception e) {
                     Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
-                    serviceDoneExecutingLocked(s, true, true);
+                    serviceProcessGoneLocked(s);
                 }
             }
 
@@ -1708,6 +1708,16 @@
         }
     }
 
+    private void serviceProcessGoneLocked(ServiceRecord r) {
+        if (r.tracker != null) {
+            int memFactor = mAm.mProcessStats.getMemFactorLocked();
+            long now = SystemClock.uptimeMillis();
+            r.tracker.setExecuting(false, memFactor, now);
+            r.tracker.setBound(false, memFactor, now);
+        }
+        serviceDoneExecutingLocked(r, true, true);
+    }
+
     private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
             boolean finishing) {
         if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r
@@ -1747,7 +1757,7 @@
                 r.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(),
                         SystemClock.uptimeMillis());
                 if (finishing) {
-                    r.tracker.clearCurrentOwner(r);
+                    r.tracker.clearCurrentOwner(r, false);
                     r.tracker = null;
                 }
             }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index a510c64..f1c2025 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6413,9 +6413,8 @@
             final int callingUid = Binder.getCallingUid();
             final UriPermission perm = findUriPermissionLocked(callingUid, uri);
             if (perm == null) {
-                Slog.w(TAG, "No permission grant found for UID " + callingUid + " and Uri "
-                        + uri.toSafeString());
-                return;
+                throw new SecurityException("No permission grant found for UID " + callingUid
+                        + " and Uri " + uri.toSafeString());
             }
 
             boolean persistChanged = perm.takePersistableModes(modeFlags);
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index c47c1ac..cc1172a 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -335,12 +335,7 @@
 
     public void forceClearTracker() {
         if (tracker != null) {
-            int memFactor = ams.mProcessStats.getMemFactorLocked();
-            long now = SystemClock.uptimeMillis();
-            tracker.setStarted(false, memFactor, now);
-            tracker.setBound(false, memFactor, now);
-            tracker.setExecuting(false, memFactor, now);
-            tracker.clearCurrentOwner(this);
+            tracker.clearCurrentOwner(this, true);
             tracker = null;
         }
     }
diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java
index 684f247..1f12b74 100644
--- a/services/java/com/android/server/am/UriPermission.java
+++ b/services/java/com/android/server/am/UriPermission.java
@@ -21,7 +21,6 @@
 import android.os.UserHandle;
 import android.util.Log;
 
-import com.android.internal.util.Preconditions;
 import com.google.android.collect.Sets;
 
 import java.io.PrintWriter;
@@ -131,7 +130,11 @@
      * @return if mode changes should trigger persisting.
      */
     boolean takePersistableModes(int modeFlags) {
-        Preconditions.checkFlagsArgument(modeFlags, persistableModeFlags);
+        if ((modeFlags & persistableModeFlags) != modeFlags) {
+            throw new SecurityException("Requested flags 0x"
+                    + Integer.toHexString(modeFlags) + ", but only 0x"
+                    + Integer.toHexString(persistableModeFlags) + " are allowed");
+        }
 
         final int before = persistedModeFlags;
         persistedModeFlags |= (persistableModeFlags & modeFlags);
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 377c390..92fc6a4 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -2473,7 +2473,8 @@
                 } else if (tagName.equals("signing-keyset")) {
                     long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
                     packageSetting.keySetData.addSigningKeySet(id);
-                    Slog.d(TAG, "Adding signing keyset " + Long.toString(id) + " to " + name);
+                    if (false) Slog.d(TAG, "Adding signing keyset " + Long.toString(id)
+                            + " to " + name);
                 } else if (tagName.equals("defined-keyset")) {
                     long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
                     String alias = parser.getAttributeValue(null, "alias");
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 0908563..00a653b 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -187,7 +187,7 @@
     static final boolean DEBUG_SURFACE_TRACE = false;
     static final boolean DEBUG_WINDOW_TRACE = false;
     static final boolean DEBUG_TASK_MOVEMENT = false;
-    static final boolean DEBUG_STACK = true;
+    static final boolean DEBUG_STACK = false;
     static final boolean SHOW_SURFACE_ALLOC = false;
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS;
@@ -1852,13 +1852,21 @@
                     }
                 }
 
-                // Now stick it in.
+                // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
+                // layer. For keyguard over wallpaper put the wallpaper under the keyguard.
+                int insertionIndex = 0;
+                if (visible && foundW != null) {
+                    final int type = foundW.mAttrs.type;
+                    if (type == TYPE_KEYGUARD || type == TYPE_KEYGUARD_SCRIM) {
+                        insertionIndex = windows.indexOf(foundW);
+                    }
+                }
                 if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
                     Slog.v(TAG, "Moving wallpaper " + wallpaper
-                            + " from " + oldIndex + " to " + 0);
+                            + " from " + oldIndex + " to " + insertionIndex);
                 }
 
-                windows.add(0, wallpaper);
+                windows.add(insertionIndex, wallpaper);
                 mWindowsChanged = true;
                 changed |= ADJUST_WALLPAPER_LAYERS_CHANGED;
             }
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index 190fea2..c945094 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -331,10 +331,12 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         if (DBG) log("writeToParcel(Parcel, int): " + toString());
-        dest.writeInt(mCdmaDbm);
-        dest.writeInt(mCdmaEcio);
-        dest.writeInt(mEvdoDbm);
-        dest.writeInt(mEvdoEcio);
+        // Need to multiply CdmaDbm, CdmaEcio, EvdoDbm and EvdoEcio by -1
+        // to ensure consistency when reading values written here
+        dest.writeInt(mCdmaDbm * -1);
+        dest.writeInt(mCdmaEcio * -1);
+        dest.writeInt(mEvdoDbm * -1);
+        dest.writeInt(mEvdoEcio * -1);
         dest.writeInt(mEvdoSnr);
     }
 
@@ -343,10 +345,13 @@
      * where the TYPE_LTE token is already been processed.
      */
     private CellSignalStrengthCdma(Parcel in) {
-        mCdmaDbm = in.readInt();
-        mCdmaEcio = in.readInt();
-        mEvdoDbm = in.readInt();
-        mEvdoEcio = in.readInt();
+        // CdmaDbm, CdmaEcio, EvdoDbm and EvdoEcio are written into
+        // the parcel as positive values.
+        // Need to convert into negative values
+        mCdmaDbm = in.readInt() * -1;
+        mCdmaEcio = in.readInt() * -1;
+        mEvdoDbm = in.readInt() * -1;
+        mEvdoEcio = in.readInt() * -1;
         mEvdoSnr = in.readInt();
         if (DBG) log("CellSignalStrengthCdma(Parcel): " + toString());
     }
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index b456bb3..5a1559a 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -247,8 +247,10 @@
     public void writeToParcel(Parcel dest, int flags) {
         if (DBG) log("writeToParcel(Parcel, int): " + toString());
         dest.writeInt(mSignalStrength);
-        dest.writeInt(mRsrp);
-        dest.writeInt(mRsrq);
+        // Need to multiply rsrp and rsrq by -1
+        // to ensure consistency when reading values written here
+        dest.writeInt(mRsrp * -1);
+        dest.writeInt(mRsrq * -1);
         dest.writeInt(mRssnr);
         dest.writeInt(mCqi);
         dest.writeInt(mTimingAdvance);
@@ -260,8 +262,10 @@
      */
     private CellSignalStrengthLte(Parcel in) {
         mSignalStrength = in.readInt();
-        mRsrp = in.readInt();
-        mRsrq = in.readInt();
+        // rsrp and rsrq are written into the parcel as positive values.
+        // Need to convert into negative values
+        mRsrp = in.readInt() * -1;
+        mRsrq = in.readInt() * -1;
         mRssnr = in.readInt();
         mCqi = in.readInt();
         mTimingAdvance = in.readInt();
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ea0d220..8f17e72 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -127,19 +127,40 @@
 
     /**
      * The Phone app sends this intent when a user opts to respond-via-message during an incoming
-     * call. By default, the MMS app consumes this message and sends a text message to the caller. A
-     * third party app can provide this functionality in lieu of MMS app by consuming this Intent
-     * and sending the message using their own messaging system.  The intent contains a URI
-     * describing the recipient, and an EXTRA containing the message itself.
-     * <p class="note"><strong>Note:</strong>
-     * The intent-filter which consumes this Intent needs to be in a service which requires the
-     * permission {@link android.Manifest.permission#SEND_RESPOND_VIA_MESSAGE}.</p>
+     * call. By default, the device's default SMS app consumes this message and sends a text message
+     * to the caller. A third party app can also provide this functionality by consuming this Intent
+     * with a {@link android.app.Service} and sending the message using its own messaging system.
+     * <p>The intent contains a URI (available from {@link android.content.Intent#getData})
+     * describing the recipient, using either the {@code sms:}, {@code smsto:}, {@code mms:},
+     * or {@code mmsto:} URI schema. Each of these URI schema carry the recipient information the
+     * same way: the path part of the URI contains the recipient's phone number or a comma-separated
+     * set of phone numbers if there are multiple recipients. For example, {@code
+     * smsto:2065551234}.</p>
      *
-     * <p>
-     * {@link android.content.Intent#getData} is a URI describing the recipient of the message.
-     * <p>
-     * The {@link android.content.Intent#EXTRA_TEXT} extra contains the message
-     * to send.
+     * <p>The intent may also contain extras for the message text (in {@link
+     * android.content.Intent#EXTRA_TEXT}) and a message subject
+     * (in {@link android.content.Intent#EXTRA_SUBJECT}).</p>
+     *
+     * <p class="note"><strong>Note:</strong>
+     * The intent-filter that consumes this Intent needs to be in a {@link android.app.Service}
+     * that requires the
+     * permission {@link android.Manifest.permission#SEND_RESPOND_VIA_MESSAGE}.</p>
+     * <p>For example, the service that receives this intent can be declared in the manifest file
+     * with an intent filter like this:</p>
+     * <pre>
+     * &lt;!-- Service that delivers SMS messages received from the phone "quick response" -->
+     * &lt;service android:name=".HeadlessSmsSendService"
+     *          android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
+     *          android:exported="true" >
+     *   &lt;intent-filter>
+     *     &lt;action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
+     *     &lt;category android:name="android.intent.category.DEFAULT" />
+     *     &lt;data android:scheme="sms" />
+     *     &lt;data android:scheme="smsto" />
+     *     &lt;data android:scheme="mms" />
+     *     &lt;data android:scheme="mmsto" />
+     *   &lt;/intent-filter>
+     * &lt;/service></pre>
      * <p>
      * Output: nothing.
      */