Merge "Make behavior of ABSOLUTE pivot values more intuitive"
diff --git a/api/16.txt b/api/16.txt
index 6b41477..13fba29 100644
--- a/api/16.txt
+++ b/api/16.txt
@@ -12611,7 +12611,6 @@
     method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], java.lang.String[][]);
     method public deprecated void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
     method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
-    method public static deprecated android.nfc.NfcAdapter getDefaultAdapter();
     method public boolean isEnabled();
     method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
     method public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...);
diff --git a/api/current.txt b/api/current.txt
index b2f20c7..db3b30d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12602,10 +12602,12 @@
   public class FormatException extends java.lang.Exception {
     ctor public FormatException();
     ctor public FormatException(java.lang.String);
+    ctor public FormatException(java.lang.String, java.lang.Throwable);
   }
 
   public final class NdefMessage implements android.os.Parcelable {
     ctor public NdefMessage(byte[]) throws android.nfc.FormatException;
+    ctor public NdefMessage(android.nfc.NdefRecord, android.nfc.NdefRecord...);
     ctor public NdefMessage(android.nfc.NdefRecord[]);
     method public int describeContents();
     method public android.nfc.NdefRecord[] getRecords();
@@ -12616,8 +12618,10 @@
 
   public final class NdefRecord implements android.os.Parcelable {
     ctor public NdefRecord(short, byte[], byte[], byte[]);
-    ctor public NdefRecord(byte[]) throws android.nfc.FormatException;
+    ctor public deprecated NdefRecord(byte[]) throws android.nfc.FormatException;
     method public static android.nfc.NdefRecord createApplicationRecord(java.lang.String);
+    method public static android.nfc.NdefRecord createExternal(java.lang.String, java.lang.String, byte[]);
+    method public static android.nfc.NdefRecord createMime(java.lang.String, byte[]);
     method public static android.nfc.NdefRecord createUri(android.net.Uri);
     method public static android.nfc.NdefRecord createUri(java.lang.String);
     method public int describeContents();
@@ -12625,7 +12629,7 @@
     method public byte[] getPayload();
     method public short getTnf();
     method public byte[] getType();
-    method public byte[] toByteArray();
+    method public deprecated byte[] toByteArray();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final byte[] RTD_ALTERNATIVE_CARRIER;
@@ -12650,7 +12654,6 @@
     method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], java.lang.String[][]);
     method public deprecated void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
     method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
-    method public static deprecated android.nfc.NfcAdapter getDefaultAdapter();
     method public boolean isEnabled();
     method public boolean isNdefPushEnabled();
     method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
diff --git a/core/java/android/nfc/FormatException.java b/core/java/android/nfc/FormatException.java
index 7045a03..a57de1e 100644
--- a/core/java/android/nfc/FormatException.java
+++ b/core/java/android/nfc/FormatException.java
@@ -24,4 +24,8 @@
     public FormatException(String message) {
         super(message);
     }
+
+    public FormatException(String message, Throwable e) {
+        super(message, e);
+    }
 }
diff --git a/core/java/android/nfc/NdefMessage.java b/core/java/android/nfc/NdefMessage.java
index c79fabf..38bc16d 100644
--- a/core/java/android/nfc/NdefMessage.java
+++ b/core/java/android/nfc/NdefMessage.java
@@ -16,90 +16,170 @@
 
 package android.nfc;
 
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
 import android.os.Parcel;
 import android.os.Parcelable;
 
+
 /**
- * Represents an NDEF (NFC Data Exchange Format) data message that contains one or more {@link
- * NdefRecord}s.
- * <p>An NDEF message includes "records" that can contain different sets of data, such as
- * MIME-type media, a URI, or one of the supported RTD types (see {@link NdefRecord}). An NDEF
- * message always contains zero or more NDEF records.</p>
- * <p>This is an immutable data class.
+ * Represents an immutable NDEF Message.
+ * <p>
+ * NDEF (NFC Data Exchange Format) is a light-weight binary format,
+ * used to encapsulate typed data. It is specified by the NFC Forum,
+ * for transmission and storage with NFC, however it is transport agnostic.
+ * <p>
+ * NDEF defines messages and records. An NDEF Record contains
+ * typed data, such as MIME-type media, a URI, or a custom
+ * application payload. An NDEF Message is a container for
+ * one or more NDEF Records.
+ * <p>
+ * When an Android device receives an NDEF Message
+ * (for example by reading an NFC tag) it processes it through
+ * a dispatch mechanism to determine an activity to launch.
+ * The type of the <em>first</em> record in the message has
+ * special importance for message dispatch, so design this record
+ * carefully.
+ * <p>
+ * Use {@link #NdefMessage(byte[])} to construct an NDEF Message from
+ * binary data, or {@link #NdefMessage(NdefRecord[])} to
+ * construct from one or more {@link NdefRecord}s.
+ * <p class="note">
+ * {@link NdefMessage} and {@link NdefRecord} implementations are
+ * always available, even on Android devices that do not have NFC hardware.
+ * <p class="note">
+ * {@link NdefRecord}s are intended to be immutable (and thread-safe),
+ * however they may contain mutable fields. So take care not to modify
+ * mutable fields passed into constructors, or modify mutable fields
+ * obtained by getter methods, unless such modification is explicitly
+ * marked as safe.
+ *
+ * @see NfcAdapter#ACTION_NDEF_DISCOVERED
+ * @see NdefRecord
  */
 public final class NdefMessage implements Parcelable {
-    private static final byte FLAG_MB = (byte) 0x80;
-    private static final byte FLAG_ME = (byte) 0x40;
-
     private final NdefRecord[] mRecords;
 
     /**
-     * Create an NDEF message from raw bytes.
-     * <p>
-     * Validation is performed to make sure the Record format headers are valid,
-     * and the ID + TYPE + PAYLOAD fields are of the correct size.
-     * @throws FormatException
+     * Construct an NDEF Message by parsing raw bytes.<p>
+     * Strict validation of the NDEF binary structure is performed:
+     * there must be at least one record, every record flag must
+     * be correct, and the total length of the message must match
+     * the length of the input data.<p>
+     * This parser can handle chunked records, and converts them
+     * into logical {@link NdefRecord}s within the message.<p>
+     * Once the input data has been parsed to one or more logical
+     * records, basic validation of the tnf, type, id, and payload fields
+     * of each record is performed, as per the documentation on
+     * on {@link NdefRecord#NdefRecord(short, byte[], byte[], byte[])}<p>
+     * If either strict validation of the binary format fails, or
+     * basic validation during record construction fails, a
+     * {@link FormatException} is thrown<p>
+     * Deep inspection of the type, id and payload fields of
+     * each record is not performed, so it is possible to parse input
+     * that has a valid binary format and confirms to the basic
+     * validation requirements of
+     * {@link NdefRecord#NdefRecord(short, byte[], byte[], byte[])},
+     * but fails more strict requirements as specified by the
+     * NFC Forum.
+     *
+     * <p class="note">
+     * It is safe to re-use the data byte array after construction:
+     * this constructor will make an internal copy of all necessary fields.
+     *
+     * @param data raw bytes to parse
+     * @throws FormatException if the data cannot be parsed
      */
     public NdefMessage(byte[] data) throws FormatException {
-        mRecords = null;  // stop compiler complaints about final field
-        if (parseNdefMessage(data) == -1) {
-            throw new FormatException("Error while parsing NDEF message");
+        if (data == null) {
+            throw new NullPointerException("null data");
+        }
+        ByteBuffer buffer = ByteBuffer.wrap(data);
+
+        mRecords = NdefRecord.parse(buffer, false);
+
+        if (buffer.remaining() > 0) {
+            throw new FormatException("trailing data");
         }
     }
 
     /**
-     * Create an NDEF message from NDEF records.
+     * Construct an NDEF Message from one or more NDEF Records.
+     *
+     * @param record first record (mandatory)
+     * @param records additional records (optional)
+     */
+    public NdefMessage(NdefRecord record, NdefRecord ... records) {
+        // validate
+        if (record == null) {
+            throw new NullPointerException("record cannot be null");
+        }
+        for (NdefRecord r : records) {
+            if (r == null) {
+                throw new NullPointerException("record cannot be null");
+            }
+        }
+
+        mRecords = new NdefRecord[1 + records.length];
+        mRecords[0] = record;
+        System.arraycopy(records, 0, mRecords, 1, records.length);
+    }
+
+    /**
+     * Construct an NDEF Message from one or more NDEF Records.
+     *
+     * @param records one or more records
      */
     public NdefMessage(NdefRecord[] records) {
-        mRecords = new NdefRecord[records.length];
-        System.arraycopy(records, 0, mRecords, 0, records.length);
-    }
-
-    /**
-     * Get the NDEF records inside this NDEF message.
-     *
-     * @return array of zero or more NDEF records.
-     */
-    public NdefRecord[] getRecords() {
-        return mRecords.clone();
-    }
-
-    /**
-     * Returns a byte array representation of this entire NDEF message.
-     */
-    public byte[] toByteArray() {
-        //TODO: allocate the byte array once, copy each record once
-        //TODO: process MB and ME flags outside loop
-        if ((mRecords == null) || (mRecords.length == 0))
-            return new byte[0];
-
-        byte[] msg = {};
-
-        for (int i = 0; i < mRecords.length; i++) {
-            byte[] record = mRecords[i].toByteArray();
-            byte[] tmp = new byte[msg.length + record.length];
-
-            /* Make sure the Message Begin flag is set only for the first record */
-            if (i == 0) {
-                record[0] |= FLAG_MB;
-            } else {
-                record[0] &= ~FLAG_MB;
+        // validate
+        if (records.length < 1) {
+            throw new IllegalArgumentException("must have at least one record");
+        }
+        for (NdefRecord r : records) {
+            if (r == null) {
+                throw new NullPointerException("records cannot contain null");
             }
-
-            /* Make sure the Message End flag is set only for the last record */
-            if (i == (mRecords.length - 1)) {
-                record[0] |= FLAG_ME;
-            } else {
-                record[0] &= ~FLAG_ME;
-            }
-
-            System.arraycopy(msg, 0, tmp, 0, msg.length);
-            System.arraycopy(record, 0, tmp, msg.length, record.length);
-
-            msg = tmp;
         }
 
-        return msg;
+        mRecords = records;
+    }
+
+    /**
+     * Get the NDEF Records inside this NDEF Message.<p>
+     * An NDEF Message always has one or more NDEF Records.
+     *
+     * @return array of one or more NDEF records.
+     */
+    public NdefRecord[] getRecords() {
+        return mRecords;
+    }
+
+    /**
+     * Return this NDEF MEssage as raw bytes.<p>
+     * The NDEF Message is formatted as per the NDEF 1.0 specification,
+     * and the byte array is suitable for network transmission or storage
+     * in an NFC Forum NDEF compatible tag.<p>
+     * This method will not chunk any records, and will always use the
+     * short record (SR) format and omit the identifier field when possible.
+     *
+     * @return NDEF Message in binary format
+     */
+    public byte[] toByteArray() {
+        int length = 0;
+        for (NdefRecord r : mRecords) {
+            length += r.getByteLength();
+        }
+
+        ByteBuffer buffer = ByteBuffer.allocate(length);
+
+        for (int i=0; i<mRecords.length; i++) {
+            boolean mb = (i == 0);  // first record
+            boolean me = (i == mRecords.length - 1);  // last record
+            mRecords[i].writeToByteBuffer(buffer, mb, me);
+        }
+
+        return buffer.array();
     }
 
     @Override
@@ -128,5 +208,26 @@
         }
     };
 
-    private native int parseNdefMessage(byte[] data);
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(mRecords);
+    }
+
+    /**
+     * Returns true if the specified NDEF Message contains
+     * identical NDEF Records.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        NdefMessage other = (NdefMessage) obj;
+        return Arrays.equals(mRecords, other.mRecords);
+    }
+
+    @Override
+    public String toString() {
+        return "NdefMessage " + Arrays.toString(mRecords);
+    }
 }
\ No newline at end of file
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 26571ff..b4c488b 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -19,80 +19,139 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
-
-import java.lang.UnsupportedOperationException;
-import java.nio.charset.Charset;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
 import java.nio.charset.Charsets;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 /**
- * Represents a logical (unchunked) NDEF (NFC Data Exchange Format) record.
- * <p>An NDEF record always contains:
+ * Represents an immutable NDEF Record.
+ * <p>
+ * NDEF (NFC Data Exchange Format) is a light-weight binary format,
+ * used to encapsulate typed data. It is specified by the NFC Forum,
+ * for transmission and storage with NFC, however it is transport agnostic.
+ * <p>
+ * NDEF defines messages and records. An NDEF Record contains
+ * typed data, such as MIME-type media, a URI, or a custom
+ * application payload. An NDEF Message is a container for
+ * one or more NDEF Records.
+ * <p>
+ * This class represents logical (complete) NDEF Records, and can not be
+ * used to represent chunked (partial) NDEF Records. However
+ * {@link NdefMessage#NdefMessage(byte[])} can be used to parse a message
+ * containing chunked records, and will return a message with unchunked
+ * (complete) records.
+ * <p>
+ * A logical NDEF Record always contains a 3-bit TNF (Type Name Field)
+ * that provides high level typing for the rest of the record. The
+ * remaining fields are variable length and not always present:
  * <ul>
- * <li>3-bit TNF (Type Name Format) field: Indicates how to interpret the type field
- * <li>Variable length type: Describes the record format
- * <li>Variable length ID: A unique identifier for the record
- * <li>Variable length payload: The actual data payload
+ * <li><em>type</em>: detailed typing for the payload</li>
+ * <li><em>id</em>: identifier meta-data, not commonly used</li>
+ * <li><em>payload</em>: the actual payload</li>
  * </ul>
- * <p>The underlying record
- * representation may be chunked across several NDEF records when the payload is
- * large.
- * <p>This is an immutable data class.
+ * <p>
+ * Helpers such as {@link NdefRecord#createUri}, {@link NdefRecord#createMime}
+ * and {@link NdefRecord#createExternal} are included to create well-formatted
+ * NDEF Records with correctly set tnf, type, id and payload fields, please
+ * use these helpers whenever possible.
+ * <p>
+ * Use the constructor {@link #NdefRecord(short, byte[], byte[], byte[])}
+ * if you know what you are doing and what to set the fields individually.
+ * Only basic validation is performed with this constructor, so it is possible
+ * to create records that do not confirm to the strict NFC Forum
+ * specifications.
+ * <p>
+ * The binary representation of an NDEF Record includes additional flags to
+ * indicate location with an NDEF message, provide support for chunking of
+ * NDEF records, and to pack optional fields. This class does not expose
+ * those details. To write an NDEF Record as binary you must first put it
+ * into an @{link NdefMessage}, then call {@link NdefMessage#toByteArray()}.
+ * <p class="note">
+ * {@link NdefMessage} and {@link NdefRecord} implementations are
+ * always available, even on Android devices that do not have NFC hardware.
+ * <p class="note">
+ * {@link NdefRecord}s are intended to be immutable (and thread-safe),
+ * however they may contain mutable fields. So take care not to modify
+ * mutable fields passed into constructors, or modify mutable fields
+ * obtained by getter methods, unless such modification is explicitly
+ * marked as safe.
+ *
+ * @see NfcAdapter#ACTION_NDEF_DISCOVERED
+ * @see NdefMessage
  */
 public final class NdefRecord implements Parcelable {
     /**
-     * Indicates no type, id, or payload is associated with this NDEF Record.
-     * <p>
-     * Type, id and payload fields must all be empty to be a valid TNF_EMPTY
-     * record.
+     * Indicates the record is empty.<p>
+     * Type, id and payload fields are empty in a {@literal TNF_EMPTY} record.
      */
     public static final short TNF_EMPTY = 0x00;
 
     /**
-     * Indicates the type field uses the RTD type name format.
+     * Indicates the type field contains a well-known RTD type name.<p>
+     * Use this tnf with RTD types such as {@link #RTD_TEXT}, {@link #RTD_URI}.
      * <p>
-     * Use this TNF with RTD types such as RTD_TEXT, RTD_URI.
+     * The RTD type name format is specified in NFCForum-TS-RTD_1.0.
+     *
+     * @see #RTD_URI
+     * @see #RTD_TEXT
+     * @see #RTD_SMART_POSTER
+     * @see #createUri
      */
     public static final short TNF_WELL_KNOWN = 0x01;
 
     /**
-     * Indicates the type field contains a value that follows the media-type BNF
-     * construct defined by RFC 2046.
+     * Indicates the type field contains a media-type BNF
+     * construct, defined by RFC 2046.<p>
+     * Use this with MIME type names such as {@literal "image/jpeg"}, or
+     * using the helper {@link #createMime}.
+     *
+     * @see #createMime
      */
     public static final short TNF_MIME_MEDIA = 0x02;
 
     /**
-     * Indicates the type field contains a value that follows the absolute-URI
-     * BNF construct defined by RFC 3986.
+     * Indicates the type field contains an absolute-URI
+     * BNF construct defined by RFC 3986.<p>
+     * When creating new records prefer {@link #createUri},
+     * since it offers more compact URI encoding
+     * ({@literal #RTD_URI} allows compression of common URI prefixes).
+     *
+     * @see #createUri
      */
     public static final short TNF_ABSOLUTE_URI = 0x03;
 
     /**
-     * Indicates the type field contains a value that follows the RTD external
-     * name specification.
+     * Indicates the type field contains an external type name.<p>
+     * Used to encode custom payloads. When creating new records
+     * use the helper {@link #createExternal}.<p>
+     * The external-type RTD format is specified in NFCForum-TS-RTD_1.0.<p>
      * <p>
      * Note this TNF should not be used with RTD_TEXT or RTD_URI constants.
      * Those are well known RTD constants, not external RTD constants.
+     *
+     * @see #createExternal
      */
     public static final short TNF_EXTERNAL_TYPE = 0x04;
 
     /**
-     * Indicates the payload type is unknown.
+     * Indicates the payload type is unknown.<p>
+     * NFC Forum explains this should be treated similarly to the
+     * "application/octet-stream" MIME type. The payload
+     * type is not explicitly encoded within the record.
      * <p>
-     * This is similar to the "application/octet-stream" MIME type. The payload
-     * type is not explicitly encoded within the NDEF Message.
-     * <p>
-     * The type field must be empty to be a valid TNF_UNKNOWN record.
+     * The type field is empty in an {@literal TNF_UNKNOWN} record.
      */
     public static final short TNF_UNKNOWN = 0x05;
 
     /**
      * Indicates the payload is an intermediate or final chunk of a chunked
-     * NDEF Record.
-     * <p>
-     * The payload type is specified in the first chunk, and subsequent chunks
-     * must use TNF_UNCHANGED with an empty type field. TNF_UNCHANGED must not
-     * be used in any other situation.
+     * NDEF Record.<p>
+     * {@literal TNF_UNCHANGED} can not be used with this class
+     * since all {@link NdefRecord}s are already unchunked, however they
+     * may appear in the binary format.
      */
     public static final short TNF_UNCHANGED = 0x06;
 
@@ -106,42 +165,49 @@
     public static final short TNF_RESERVED = 0x07;
 
     /**
-     * RTD Text type. For use with TNF_WELL_KNOWN.
+     * RTD Text type. For use with {@literal TNF_WELL_KNOWN}.
+     * @see #TNF_WELL_KNOWN
      */
     public static final byte[] RTD_TEXT = {0x54};  // "T"
 
     /**
-     * RTD URI type. For use with TNF_WELL_KNOWN.
+     * RTD URI type. For use with {@literal TNF_WELL_KNOWN}.
+     * @see #TNF_WELL_KNOWN
      */
     public static final byte[] RTD_URI = {0x55};   // "U"
 
     /**
-     * RTD Smart Poster type. For use with TNF_WELL_KNOWN.
+     * RTD Smart Poster type. For use with {@literal TNF_WELL_KNOWN}.
+     * @see #TNF_WELL_KNOWN
      */
     public static final byte[] RTD_SMART_POSTER = {0x53, 0x70};  // "Sp"
 
     /**
-     * RTD Alternative Carrier type. For use with TNF_WELL_KNOWN.
+     * RTD Alternative Carrier type. For use with {@literal TNF_WELL_KNOWN}.
+     * @see #TNF_WELL_KNOWN
      */
     public static final byte[] RTD_ALTERNATIVE_CARRIER = {0x61, 0x63};  // "ac"
 
     /**
-     * RTD Handover Carrier type. For use with TNF_WELL_KNOWN.
+     * RTD Handover Carrier type. For use with {@literal TNF_WELL_KNOWN}.
+     * @see #TNF_WELL_KNOWN
      */
     public static final byte[] RTD_HANDOVER_CARRIER = {0x48, 0x63};  // "Hc"
 
     /**
-     * RTD Handover Request type. For use with TNF_WELL_KNOWN.
+     * RTD Handover Request type. For use with {@literal TNF_WELL_KNOWN}.
+     * @see #TNF_WELL_KNOWN
      */
     public static final byte[] RTD_HANDOVER_REQUEST = {0x48, 0x72};  // "Hr"
 
     /**
-     * RTD Handover Select type. For use with TNF_WELL_KNOWN.
+     * RTD Handover Select type. For use with {@literal TNF_WELL_KNOWN}.
+     * @see #TNF_WELL_KNOWN
      */
     public static final byte[] RTD_HANDOVER_SELECT = {0x48, 0x73}; // "Hs"
 
     /**
-     * RTD Android app type. For use with TNF_EXTERNAL.
+     * RTD Android app type. For use with {@literal TNF_EXTERNAL}.
      * <p>
      * The payload of a record with type RTD_ANDROID_APP
      * should be the package name identifying an application.
@@ -161,8 +227,7 @@
     private static final byte FLAG_IL = (byte) 0x08;
 
     /**
-     * NFC Forum "URI Record Type Definition"
-     *
+     * NFC Forum "URI Record Type Definition"<p>
      * This is a mapping of "URI Identifier Codes" to URI string prefixes,
      * per section 3.2.2 of the NFC Forum URI Record Type Definition document.
      */
@@ -204,84 +269,247 @@
             "urn:epc:", // 0x22
     };
 
-    private final byte mFlags;
+    private static final int MAX_PAYLOAD_SIZE = 10 * (1 << 20);  // 10 MB payload limit
+
+    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+
     private final short mTnf;
     private final byte[] mType;
     private final byte[] mId;
     private final byte[] mPayload;
 
     /**
-     * Construct an NDEF Record.
+     * Create a new Android Application Record (AAR).
      * <p>
-     * Applications should not attempt to manually chunk NDEF Records - the
-     * implementation of android.nfc will automatically chunk an NDEF Record
-     * when necessary (and only present a single logical NDEF Record to the
-     * application). So applications should not use TNF_UNCHANGED.
+     * This record indicates to other Android devices the package
+     * that should be used to handle the entire NDEF message.
+     * You can embed this record anywhere into your message
+     * to ensure that the intended package receives the message.
+     * <p>
+     * When an Android device dispatches an {@link NdefMessage}
+     * containing one or more Android application records,
+     * the applications contained in those records will be the
+     * preferred target for the {@link NfcAdapter#ACTION_NDEF_DISCOVERED}
+     * intent, in the order in which they appear in the message.
+     * This dispatch behavior was first added to Android in
+     * Ice Cream Sandwich.
+     * <p>
+     * If none of the applications have a are installed on the device,
+     * a Market link will be opened to the first application.
+     * <p>
+     * Note that Android application records do not overrule
+     * applications that have called
+     * {@link NfcAdapter#enableForegroundDispatch}.
+     *
+     * @param packageName Android package name
+     * @return Android application NDEF record
+     */
+    public static NdefRecord createApplicationRecord(String packageName) {
+        if (packageName.length() == 0) {
+            throw new IllegalArgumentException("empty package name");
+        }
+        return new NdefRecord(TNF_EXTERNAL_TYPE, RTD_ANDROID_APP, null,
+                packageName.getBytes(Charsets.UTF_8));
+    }
+
+    /**
+     * Create a new NDEF Record containing a URI.<p>
+     * Use this method to encode a URI (or URL) into an NDEF Record.<p>
+     * Uses the well known URI type representation: {@link #TNF_WELL_KNOWN}
+     * and {@link #RTD_URI}. This is the most efficient encoding
+     * of a URI into NDEF.<p>
+     * Reference specification: NFCForum-TS-RTD_URI_1.0
+     *
+     * @param uri URI to encode.
+     * @return an NDEF Record containing the URI
+     * @throws IllegalArugmentException if a valid record cannot be created
+     */
+    public static NdefRecord createUri(Uri uri) {
+        return createUri(uri.toString());
+    }
+
+    /**
+     * Create a new NDEF Record containing a URI.<p>
+     * Use this method to encode a URI (or URL) into an NDEF Record.<p>
+     * Uses the well known URI type representation: {@link #TNF_WELL_KNOWN}
+     * and {@link #RTD_URI}. This is the most efficient encoding
+     * of a URI into NDEF.<p>
+     * Reference specification: NFCForum-TS-RTD_URI_1.0
+     *
+     * @param uriString string URI to encode.
+     * @return an NDEF Record containing the URI
+     * @throws IllegalArugmentException if a valid record cannot be created
+     */
+    public static NdefRecord createUri(String uriString) {
+        if (uriString.length() == 0) {
+            throw new IllegalArgumentException("empty uriString");
+        }
+
+        byte prefix = 0;
+        for (int i = 1; i < URI_PREFIX_MAP.length; i++) {
+            if (uriString.startsWith(URI_PREFIX_MAP[i])) {
+                prefix = (byte) i;
+                uriString = uriString.substring(URI_PREFIX_MAP[i].length());
+                break;
+            }
+        }
+        byte[] uriBytes = uriString.getBytes(Charsets.UTF_8);
+        byte[] recordBytes = new byte[uriBytes.length + 1];
+        recordBytes[0] = prefix;
+        System.arraycopy(uriBytes, 0, recordBytes, 1, uriBytes.length);
+        return new NdefRecord(TNF_WELL_KNOWN, RTD_URI, null, recordBytes);
+    }
+
+    /**
+     * Create a new NDEF Record containing MIME data.<p>
+     * Use this method to encode MIME-typed data into an NDEF Record,
+     * such as "text/plain", or "image/jpeg".<p>
+     * Expects US-ASCII characters in mimeType. The encoding of the
+     * mimeData depends on the mimeType.<p>
+     * For efficiency, This method might not make an internal copy of the
+     * mimeData byte array, so take care not
+     * to re-use the mimeData byte array while still using the returned
+     * NdefRecord.
+     *
+     * @param mimeType MIME type, expects US-ASCII characters only
+     * @param mimeData MIME data as bytes
+     * @return an NDEF Record containing the MIME-typed data
+     * @throws IllegalArugmentException if a valid record cannot be created
+     */
+    public static NdefRecord createMime(String mimeType, byte[] mimeData) {
+        if (mimeType.length() == 0) {
+            throw new IllegalArgumentException("empty mimeType");
+        }
+
+        return new NdefRecord(TNF_MIME_MEDIA, mimeType.getBytes(Charsets.US_ASCII), null,
+                mimeData);
+    }
+
+    /**
+     * Create a new NDEF Record containing external (application-specific) data.<p>
+     * Use this method to encode application specific data into an NDEF Record.
+     * The data is typed by a domain name (usually your Android package name) and
+     * a domain-specific type. This data is packaged into a "NFC Forum External
+     * Type" NDEF Record.<p>
+     * Both the domain and type used to construct an external record are case
+     * insensitive, and this implementation will encode all characters to lower
+     * case. Only a subset of ASCII characters are allowed for the domain
+     * and type. There are no restrictions on the payload data.<p>
+     * For efficiency, This method might not make an internal copy of the
+     * data byte array, so take care not
+     * to re-use the data byte array while still using the returned
+     * NdefRecord.
+     *
+     * Reference specification: NFCForum-TS-RTD_1.0
+     * @param domain domain-name of issuing organization
+     * @param type domain-specific type of data
+     * @param data payload as bytes
+     * @throws IllegalArugmentException if a valid record cannot be created
+     */
+    public static NdefRecord createExternal(String domain, String type, byte[] data) {
+        if (domain.length() == 0 || type.length() == 0) {
+            throw new IllegalArgumentException("empty domain or type");
+        }
+        byte[] byteDomain = domain.getBytes(Charsets.US_ASCII);
+        ensureValidDomain(byteDomain);
+        toLowerCase(byteDomain);
+        byte[] byteType = type.getBytes(Charsets.US_ASCII);
+        ensureValidWkt(byteType);
+        toLowerCase(byteType);
+
+        byte[] b = new byte[byteDomain.length + 1 + byteType.length];
+        System.arraycopy(byteDomain, 0, b, 0, byteDomain.length);
+        b[byteDomain.length] = ':';
+        System.arraycopy(byteType, 0, b, byteDomain.length + 1, byteType.length);
+
+        return new NdefRecord(TNF_EXTERNAL_TYPE, b, null, data);
+    }
+
+    /**
+     * Construct an NDEF Record from its component fields.<p>
+     * Recommend to use helpers such as {#createUri} or
+     * {{@link #createExternal} where possible, since they perform
+     * stricter validation that the record is correctly formatted
+     * as per NDEF specifications. However if you know what you are
+     * doing then this constructor offers the most flexibility.<p>
+     * An {@link NdefRecord} represents a logical (complete)
+     * record, and cannot represent NDEF Record chunks.<p>
+     * Basic validation of the tnf, type, id and payload is performed
+     * as per the following rules:
+     * <ul>
+     * <li>The tnf paramter must be a 3-bit value.</li>
+     * <li>Records with a tnf of {@link #TNF_EMPTY} cannot have a type,
+     * id or payload.</li>
+     * <li>Records with a tnf of {@link #TNF_UNKNOWN} or {@literal 0x07}
+     * cannot have a type.</li>
+     * <li>Records with a tnf of {@link #TNF_UNCHANGED} are not allowed
+     * since this class only represents complete (unchunked) records.</li>
+     * </ul>
+     * This minimal validation is specified by
+     * NFCForum-TS-NDEF_1.0 section 3.2.6 (Type Name Format).<p>
+     * If any of the above validation
+     * steps fail then {@link IllegalArgumentException} is thrown.<p>
+     * Deep inspection of the type, id and payload fields is not
+     * performed, so it is possible to create NDEF Records
+     * that conform to section 3.2.6
+     * but fail other more strict NDEF specification requirements. For
+     * example, the payload may be invalid given the tnf and type.
+     * <p>
+     * To omit a type, id or payload field, set the parameter to an
+     * empty byte array or null.
      *
      * @param tnf  a 3-bit TNF constant
-     * @param type byte array, containing zero to 255 bytes, must not be null
-     * @param id   byte array, containing zero to 255 bytes, must not be null
+     * @param type byte array, containing zero to 255 bytes, or null
+     * @param id   byte array, containing zero to 255 bytes, or null
      * @param payload byte array, containing zero to (2 ** 32 - 1) bytes,
-     *                must not be null
+     *                or null
+     * @throws IllegalArugmentException if a valid record cannot be created
      */
     public NdefRecord(short tnf, byte[] type, byte[] id, byte[] payload) {
-        /* New NDEF records created by applications will have FLAG_MB|FLAG_ME
-         * set by default; when multiple records are stored in a
-         * {@link NdefMessage}, these flags will be corrected when the {@link NdefMessage}
-         * is serialized to bytes.
-         */
-        this(tnf, type, id, payload, (byte)(FLAG_MB|FLAG_ME));
-    }
+        /* convert nulls */
+        if (type == null) type = EMPTY_BYTE_ARRAY;
+        if (id == null) id = EMPTY_BYTE_ARRAY;
+        if (payload == null) payload = EMPTY_BYTE_ARRAY;
 
-    /**
-     * @hide
-     */
-    /*package*/ NdefRecord(short tnf, byte[] type, byte[] id, byte[] payload, byte flags) {
-        /* check arguments */
-        if ((type == null) || (id == null) || (payload == null)) {
-            throw new IllegalArgumentException("Illegal null argument");
+        String message = validateTnf(tnf, type, id, payload);
+        if (message != null) {
+            throw new IllegalArgumentException(message);
         }
 
-        if (tnf < 0 || tnf > 0x07) {
-            throw new IllegalArgumentException("TNF out of range " + tnf);
-        }
-
-        /* Determine if it is a short record */
-        if(payload.length < 0xFF) {
-            flags |= FLAG_SR;
-        }
-
-        /* Determine if an id is present */
-        if(id.length != 0) {
-            flags |= FLAG_IL;
-        }
-
-        mFlags = flags;
         mTnf = tnf;
-        mType = type.clone();
-        mId = id.clone();
-        mPayload = payload.clone();
+        mType = type;
+        mId = id;
+        mPayload = payload;
     }
 
     /**
-     * Construct an NDEF Record from raw bytes.
-     * <p>
-     * Validation is performed to make sure the header is valid, and that
-     * the id, type and payload sizes appear to be valid.
+     * Construct an NDEF Record from raw bytes.<p>
+     * This method is deprecated, use {@link NdefMessage#NdefMessage(byte[])}
+     * instead. This is because it does not make sense to parse a record:
+     * the NDEF binary format is only defined for a message, and the
+     * record flags MB and ME do not make sense outside of the context of
+     * an entire message.<p>
+     * This implementation will attempt to parse a single record by ignoring
+     * the MB and ME flags, and otherwise following the rules of
+     * {@link NdefMessage#NdefMessage(byte[])}.<p>
      *
-     * @throws FormatException if the data is not a valid NDEF record
+     * @param data raw bytes to parse
+     * @throws FormatException if the data cannot be parsed into a valid record
+     * @deprecated use {@link NdefMessage#NdefMessage(byte[])} instead.
      */
+    @Deprecated
     public NdefRecord(byte[] data) throws FormatException {
-        /* Prevent compiler to complain about unassigned final fields */
-        mFlags = 0;
-        mTnf = 0;
-        mType = null;
-        mId = null;
-        mPayload = null;
-        /* Perform actual parsing */
-        if (parseNdefRecord(data) == -1) {
-            throw new FormatException("Error while parsing NDEF record");
+        ByteBuffer buffer = ByteBuffer.wrap(data);
+        NdefRecord[] rs = parse(buffer, true);
+
+        if (buffer.remaining() > 0) {
+            throw new FormatException("data too long");
         }
+
+        mTnf = rs[0].mTnf;
+        mType = rs[0].mType;
+        mId = rs[0].mId;
+        mPayload = rs[0].mPayload;
     }
 
     /**
@@ -298,6 +526,9 @@
      * <p>
      * This should be used in conjunction with the TNF field to determine the
      * payload format.
+     * <p>
+     * Returns an empty byte array if this record
+     * does not have a type field.
      */
     public byte[] getType() {
         return mType.clone();
@@ -305,6 +536,9 @@
 
     /**
      * Returns the variable length ID.
+     * <p>
+     * Returns an empty byte array if this record
+     * does not have an id field.
      */
     public byte[] getId() {
         return mId.clone();
@@ -312,12 +546,34 @@
 
     /**
      * Returns the variable length payload.
+     * <p>
+     * Returns an empty byte array if this record
+     * does not have a payload field.
      */
     public byte[] getPayload() {
         return mPayload.clone();
     }
 
     /**
+     * Return this NDEF Record as a byte array.<p>
+     * This method is deprecated, use {@link NdefMessage#toByteArray}
+     * instead. This is because the NDEF binary format is not defined for
+     * a record outside of the context of a message: the MB and ME flags
+     * cannot be set without knowing the location inside a message.<p>
+     * This implementation will attempt to serialize a single record by
+     * always setting the MB and ME flags (in other words, assume this
+     * is a single-record NDEF Message).<p>
+     *
+     * @deprecated use {@link NdefMessage#toByteArray()} instead
+     */
+    @Deprecated
+    public byte[] toByteArray() {
+        ByteBuffer buffer = ByteBuffer.allocate(getByteLength());
+        writeToByteBuffer(buffer, true, true);
+        return buffer.array();
+    }
+
+    /**
      * Helper to return the NdefRecord as a URI.
      * TODO: Consider making a member method instead of static
      * TODO: Consider more validation that this is a URI record
@@ -347,63 +603,6 @@
         return Uri.parse(new String(fullUri, Charsets.UTF_8));
     }
 
-    /**
-     * Creates an Android application NDEF record.
-     * <p>
-     * This record indicates to other Android devices the package
-     * that should be used to handle the rest of the NDEF message.
-     * You can embed this record anywhere into your NDEF message
-     * to ensure that the intended package receives the message.
-     * <p>
-     * When an Android device dispatches an {@link NdefMessage}
-     * containing one or more Android application records,
-     * the applications contained in those records will be the
-     * preferred target for the NDEF_DISCOVERED intent, in
-     * the order in which they appear in the {@link NdefMessage}.
-     * This dispatch behavior was first added to Android in
-     * Ice Cream Sandwich.
-     * <p>
-     * If none of the applications are installed on the device,
-     * a Market link will be opened to the first application.
-     * <p>
-     * Note that Android application records do not overrule
-     * applications that have called
-     * {@link NfcAdapter#enableForegroundDispatch}.
-     *
-     * @param packageName Android package name
-     * @return Android application NDEF record
-     */
-    public static NdefRecord createApplicationRecord(String packageName) {
-        return new NdefRecord(TNF_EXTERNAL_TYPE, RTD_ANDROID_APP, new byte[] {},
-                packageName.getBytes(Charsets.US_ASCII));
-    }
-
-    /**
-     * Creates an NDEF record of well known type URI.
-     */
-    public static NdefRecord createUri(Uri uri) {
-        return createUri(uri.toString());
-    }
-
-    /**
-     * Creates an NDEF record of well known type URI.
-     */
-    public static NdefRecord createUri(String uriString) {
-        byte prefix = 0x0;
-        for (int i = 1; i < URI_PREFIX_MAP.length; i++) {
-            if (uriString.startsWith(URI_PREFIX_MAP[i])) {
-                prefix = (byte) i;
-                uriString = uriString.substring(URI_PREFIX_MAP[i].length());
-                break;
-            }
-        }
-        byte[] uriBytes = uriString.getBytes(Charsets.UTF_8);
-        byte[] recordBytes = new byte[uriBytes.length + 1];
-        recordBytes[0] = prefix;
-        System.arraycopy(uriBytes, 0, recordBytes, 1, uriBytes.length);
-        return new NdefRecord(TNF_WELL_KNOWN, RTD_URI, new byte[0], recordBytes);
-    }
-
     private static byte[] concat(byte[]... arrays) {
         int length = 0;
         for (byte[] array : arrays) {
@@ -419,18 +618,215 @@
     }
 
     /**
-     * Returns this entire NDEF Record as a byte array.
+     * Main parsing method.<p>
+     * Expects NdefMessage to begin immediately, allows trailing data.<p>
+     * Currently has strict validation of all fields as per NDEF 1.0
+     * specification section 2.5. We will attempt to keep this as strict as
+     * possible to encourage well-formatted NDEF.<p>
+     * Always returns 1 or more NdefRecord's, or throws FormatException.
+     *
+     * @param buffer ByteBuffer to read from
+     * @param ignoreMbMe ignore MB and ME flags, and read only 1 complete record
+     * @return one or more records
+     * @throws FormatException on any parsing error
      */
-    public byte[] toByteArray() {
-        return generate(mFlags, mTnf, mType, mId, mPayload);
+    static NdefRecord[] parse(ByteBuffer buffer, boolean ignoreMbMe) throws FormatException {
+        List<NdefRecord> records = new ArrayList<NdefRecord>();
+
+        try {
+            byte[] type = null;
+            byte[] id = null;
+            byte[] payload = null;
+            ArrayList<byte[]> chunks = new ArrayList<byte[]>();
+            boolean inChunk = false;
+            short chunkTnf = -1;
+            boolean me = false;
+
+            while (!me) {
+                byte flag = buffer.get();
+
+                boolean mb = (flag & NdefRecord.FLAG_MB) != 0;
+                me = (flag & NdefRecord.FLAG_ME) != 0;
+                boolean cf = (flag & NdefRecord.FLAG_CF) != 0;
+                boolean sr = (flag & NdefRecord.FLAG_SR) != 0;
+                boolean il = (flag & NdefRecord.FLAG_IL) != 0;
+                short tnf = (short)(flag & 0x07);
+
+                if (!mb && records.size() == 0 && !inChunk && !ignoreMbMe) {
+                    throw new FormatException("expected MB flag");
+                } else if (mb && records.size() != 0 && !ignoreMbMe) {
+                    throw new FormatException("unexpected MB flag");
+                } else if (inChunk && il) {
+                    throw new FormatException("unexpected IL flag in non-leading chunk");
+                } else if (cf && me) {
+                    throw new FormatException("unexpected ME flag in non-trailing chunk");
+                } else if (inChunk && tnf != NdefRecord.TNF_UNCHANGED) {
+                    throw new FormatException("expected TNF_UNCHANGED in non-leading chunk");
+                } else if (!inChunk && tnf == NdefRecord.TNF_UNCHANGED) {
+                    throw new FormatException("" +
+                    		"unexpected TNF_UNCHANGED in first chunk or unchunked record");
+                }
+
+                int typeLength = buffer.get() & 0xFF;
+                long payloadLength = sr ? (buffer.get() & 0xFF) : (buffer.getInt() & 0xFFFFFFFFL);
+                int idLength = il ? (buffer.get() & 0xFF) : 0;
+
+                if (inChunk && typeLength != 0) {
+                    throw new FormatException("expected zero-length type in non-leading chunk");
+                }
+
+                if (!inChunk) {
+                    type = (typeLength > 0 ? new byte[typeLength] : EMPTY_BYTE_ARRAY);
+                    id = (idLength > 0 ? new byte[idLength] : EMPTY_BYTE_ARRAY);
+                    buffer.get(type);
+                    buffer.get(id);
+                }
+
+                ensureSanePayloadSize(payloadLength);
+                payload = (payloadLength > 0 ? new byte[(int)payloadLength] : EMPTY_BYTE_ARRAY);
+                buffer.get(payload);
+
+                if (cf && !inChunk) {
+                    // first chunk
+                    chunks.clear();
+                    chunkTnf = tnf;
+                }
+                if (cf || inChunk) {
+                    // any chunk
+                    chunks.add(payload);
+                }
+                if (!cf && inChunk) {
+                    // last chunk, flatten the payload
+                    payloadLength = 0;
+                    for (byte[] p : chunks) {
+                        payloadLength += p.length;
+                    }
+                    ensureSanePayloadSize(payloadLength);
+                    payload = new byte[(int)payloadLength];
+                    int i = 0;
+                    for (byte[] p : chunks) {
+                        System.arraycopy(p, 0, payload, i, p.length);
+                        i += p.length;
+                    }
+                    tnf = chunkTnf;
+                }
+                if (cf) {
+                    // more chunks to come
+                    inChunk = true;
+                    continue;
+                } else {
+                    inChunk = false;
+                }
+
+                String error = validateTnf(tnf, type, id, payload);
+                if (error != null) {
+                    throw new FormatException(error);
+                }
+                records.add(new NdefRecord(tnf, type, id, payload));
+                if (ignoreMbMe) {  // for parsing a single NdefRecord
+                    break;
+                }
+            }
+        } catch (BufferUnderflowException e) {
+            throw new FormatException("expected more data", e);
+        }
+        return records.toArray(new NdefRecord[records.size()]);
     }
 
+    private static void ensureSanePayloadSize(long size) throws FormatException {
+        if (size > MAX_PAYLOAD_SIZE) {
+            throw new FormatException(
+                    "payload above max limit: " + size + " > " + MAX_PAYLOAD_SIZE);
+        }
+    }
+
+    /**
+     * Perform simple validation that the tnf is valid.<p>
+     * Validates the requirements of NFCForum-TS-NDEF_1.0 section
+     * 3.2.6 (Type Name Format). This just validates that the tnf
+     * is valid, and that the relevant type, id and payload
+     * fields are present (or empty) for this tnf. It does not
+     * perform any deep inspection of the type, id and payload fields.<p>
+     * Also does not allow TNF_UNCHANGED since this class is only used
+     * to present logical (unchunked) records.
+     *
+     * @return null if valid, or a string error if invalid.
+     */
+    static String validateTnf(short tnf, byte[] type, byte[] id, byte[] payload) {
+        switch (tnf) {
+            case TNF_EMPTY:
+                if (type.length != 0 || id.length != 0 || payload.length != 0) {
+                    return "unexpected data in TNF_EMPTY record";
+                }
+                return null;
+            case TNF_WELL_KNOWN:
+            case TNF_MIME_MEDIA:
+            case TNF_ABSOLUTE_URI:
+            case TNF_EXTERNAL_TYPE:
+                return null;
+            case TNF_UNKNOWN:
+            case TNF_RESERVED:
+                if (type.length != 0) {
+                    return "unexpected type field in TNF_UNKNOWN or TNF_RESERVEd record";
+                }
+                return null;
+            case TNF_UNCHANGED:
+                return "unexpected TNF_UNCHANGED in first chunk or logical record";
+            default:
+                return String.format("unexpected tnf value: 0x%02x", tnf);
+        }
+    }
+
+    /**
+     * Serialize record for network transmission.<p>
+     * Uses specified MB and ME flags.<p>
+     * Does not chunk records.
+     */
+    void writeToByteBuffer(ByteBuffer buffer, boolean mb, boolean me) {
+        boolean sr = mPayload.length < 256;
+        boolean il = mId.length > 0;
+
+        byte flags = (byte)((mb ? FLAG_MB : 0) | (me ? FLAG_ME : 0) |
+                (sr ? FLAG_SR : 0) | (il ? FLAG_IL : 0) | mTnf);
+        buffer.put(flags);
+
+        buffer.put((byte)mType.length);
+        if (sr) {
+            buffer.put((byte)mPayload.length);
+        } else {
+            buffer.putInt(mPayload.length);
+        }
+        if (il) {
+            buffer.put((byte)mId.length);
+        }
+
+        buffer.put(mType);
+        buffer.put(mId);
+        buffer.put(mPayload);
+    }
+
+    /**
+     * Get byte length of serialized record.
+     */
+    int getByteLength() {
+        int length = 3 + mType.length + mId.length + mPayload.length;
+
+        boolean sr = mPayload.length < 256;
+        boolean il = mId.length > 0;
+
+        if (!sr) length += 3;
+        if (il) length += 1;
+
+        return length;
+    }
+
+    @Override
     public int describeContents() {
         return 0;
     }
 
+    @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mFlags);
         dest.writeInt(mTnf);
         dest.writeInt(mType.length);
         dest.writeByteArray(mType);
@@ -442,8 +838,8 @@
 
     public static final Parcelable.Creator<NdefRecord> CREATOR =
             new Parcelable.Creator<NdefRecord>() {
+        @Override
         public NdefRecord createFromParcel(Parcel in) {
-            byte flags = (byte)in.readInt();
             short tnf = (short)in.readInt();
             int typeLength = in.readInt();
             byte[] type = new byte[typeLength];
@@ -455,13 +851,93 @@
             byte[] payload = new byte[payloadLength];
             in.readByteArray(payload);
 
-            return new NdefRecord(tnf, type, id, payload, flags);
+            return new NdefRecord(tnf, type, id, payload);
         }
+        @Override
         public NdefRecord[] newArray(int size) {
             return new NdefRecord[size];
         }
     };
 
-    private native int parseNdefRecord(byte[] data);
-    private native byte[] generate(short flags, short tnf, byte[] type, byte[] id, byte[] data);
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(mId);
+        result = prime * result + Arrays.hashCode(mPayload);
+        result = prime * result + mTnf;
+        result = prime * result + Arrays.hashCode(mType);
+        return result;
+    }
+
+    /**
+     * Returns true if the specified NDEF Record contains
+     * identical tnf, type, id and payload fields.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        NdefRecord other = (NdefRecord) obj;
+        if (!Arrays.equals(mId, other.mId)) return false;
+        if (!Arrays.equals(mPayload, other.mPayload)) return false;
+        if (mTnf != other.mTnf) return false;
+        return Arrays.equals(mType, other.mType);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder b = new StringBuilder(String.format("NdefRecord tnf=%X", mTnf));
+        if (mType.length > 0) b.append(" type=").append(bytesToString(mType));
+        if (mId.length > 0) b.append(" id=").append(bytesToString(mId));
+        if (mPayload.length > 0) b.append(" payload=").append(bytesToString(mPayload));
+        return b.toString();
+    }
+
+    private static StringBuilder bytesToString(byte[] bs) {
+        StringBuilder s = new StringBuilder();
+        for (byte b : bs) {
+            s.append(String.format("%02X", b));
+        }
+        return s;
+    }
+
+    /** Ensure valid 'DNS-char' as per RFC2234 */
+    private static void ensureValidDomain(byte[] bs) {
+        for (int i = 0; i < bs.length; i++) {
+            byte b = bs[i];
+            if ((b >= 'A' && b <= 'Z') ||
+                    (b >= 'a' && b <= 'z') ||
+                    (b >= '0' && b <= '9') ||
+                    b == '.' || b == '-') {
+                continue;
+            }
+            throw new IllegalArgumentException("invalid character in domain");
+        }
+    }
+
+    /** Ensure valid 'WKT-char' as per RFC2234 */
+    private static void ensureValidWkt(byte[] bs) {
+        for (int i = 0; i < bs.length; i++) {
+            byte b = bs[i];
+            if ((b >= 'A' && b <= 'Z') ||
+                    (b >= 'a' && b <= 'z') ||
+                    (b >= '0' && b <= '9') ||
+                    b == '(' || b == ')' || b == '+' || b == ',' || b == '-' ||
+                    b == ':' || b == '=' || b == '@' || b == ';' || b == '$' ||
+                    b == '_' || b == '!' || b == '*' || b == '\'' || b == '.') {
+                continue;
+            }
+            throw new IllegalArgumentException("invalid character in type");
+        }
+    }
+
+    private static void toLowerCase(byte[] b) {
+        for (int i = 0; i < b.length; i++) {
+            if (b[i] >= 'A' && b[i] <= 'Z') {
+                b[i] += 0x20;
+            }
+        }
+    }
 }
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 02096f2..f3c884d 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -376,9 +376,14 @@
      * for many NFC API methods. Those methods will fail when called on an NfcAdapter
      * object created from this method.<p>
      * @deprecated use {@link #getDefaultAdapter(Context)}
+     * @hide
      */
     @Deprecated
     public static NfcAdapter getDefaultAdapter() {
+        // introduce in API version 9 (GB 2.3)
+        // deprecated in API version 10 (GB 2.3.3)
+        // removed from public API in version 16 (ICS MR2)
+        // will need to maintain this as a hidden API for a while longer...
         Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " +
                 "NfcAdapter.getDefaultAdapter(Context) instead", new Exception());
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0d34b90..09901ff 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3056,8 +3056,14 @@
     }
 
     /**
-     * {@inheritDoc}
+     * Sets  <code>t</code> to be the static transformation of the child, if set, returning a
+     * boolean to indicate whether a static transform was set. The default implementation
+     * simply returns <code>false</code>; subclasses may override this method for different
+     * behavior.
      *
+     * @param child The child view whose static transform is being requested
+     * @param t The Transformation which will hold the result
+     * @return true if the transformation was set, false otherwise
      * @see #setStaticTransformationsEnabled(boolean)
      */
     protected boolean getChildStaticTransformation(View child, Transformation t) {
diff --git a/core/java/android/view/animation/AnimationSet.java b/core/java/android/view/animation/AnimationSet.java
index 2cf8ea8..def4d70 100644
--- a/core/java/android/view/animation/AnimationSet.java
+++ b/core/java/android/view/animation/AnimationSet.java
@@ -224,7 +224,9 @@
         }
 
         boolean changeBounds = (mFlags & PROPERTY_CHANGE_BOUNDS_MASK) == 0;
-        if (changeBounds && a.willChangeTransformationMatrix()) {
+
+
+        if (changeBounds && a.willChangeBounds()) {
             mFlags |= PROPERTY_CHANGE_BOUNDS_MASK;
         }
 
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index 32ff647..38043b2 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -133,6 +133,14 @@
 
     }
 
+    /**
+     * Loads a {@link LayoutAnimationController} object from a resource
+     *
+     * @param context Application context used to access resources
+     * @param id The resource id of the animation to load
+     * @return The animation object reference by the specified id
+     * @throws NotFoundException when the layout animation controller cannot be loaded
+     */
     public static LayoutAnimationController loadLayoutAnimation(Context context, int id)
             throws NotFoundException {
         
diff --git a/core/java/android/webkit/HttpAuthHandlerImpl.java b/core/java/android/webkit/HttpAuthHandlerImpl.java
index ac05125..01e8eb8 100644
--- a/core/java/android/webkit/HttpAuthHandlerImpl.java
+++ b/core/java/android/webkit/HttpAuthHandlerImpl.java
@@ -270,7 +270,6 @@
 
     /**
      * Informs the WebView of a new set of credentials.
-     * @hide Pending API council review
      */
     public static void onReceivedCredentials(LoadListener loader,
             String host, String realm, String username, String password) {
diff --git a/core/java/android/webkit/SearchBox.java b/core/java/android/webkit/SearchBox.java
index 6512c4b..38a1740 100644
--- a/core/java/android/webkit/SearchBox.java
+++ b/core/java/android/webkit/SearchBox.java
@@ -29,7 +29,7 @@
  * SearchBox.query() and receive suggestions by registering a listener on the
  * SearchBox object.
  *
- * @hide pending API council approval.
+ * @hide
  */
 public interface SearchBox {
     /**
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index f947f95..61eedac 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1459,7 +1459,7 @@
      * @param flag True if the WebView should enable WebWorkers.
      * Note that this flag only affects V8. JSC does not have
      * an equivalent setting.
-     * @hide pending api council approval
+     * @hide
      */
     public synchronized void setWorkersEnabled(boolean flag) {
         if (mWorkersEnabled != flag) {
@@ -1710,7 +1710,7 @@
      * Specify the maximum decoded image size. The default is
      * 2 megs for small memory devices and 8 megs for large memory devices.
      * @param size The maximum decoded size, or zero to set to the default.
-     * @hide pending api council approval
+     * @hide
      */
     public void setMaximumDecodedImageSize(long size) {
         if (mMaximumDecodedImageSize != size) {
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 8eb1524..c079404 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -362,7 +362,7 @@
     /**
      * Sets the maximum size of the ApplicationCache.
      * This should only ever be called on the WebKit thread.
-     * @hide Pending API council approval
+     * @hide
      */
     public void setAppCacheMaximumSize(long size) {
         nativeSetAppCacheMaximumSize(size);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index b1e1132..baa7c0f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1069,7 +1069,7 @@
      * @param defStyle The default style resource ID.
      * @param javaScriptInterfaces is a Map of interface names, as keys, and
      * object implementing those interfaces, as values.
-     * @hide pending API council approval.
+     * @hide This is an implementation detail.
      */
     protected WebView(Context context, AttributeSet attrs, int defStyle,
             Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) {
@@ -1734,7 +1734,7 @@
      *
      * @param flags JS engine flags in a String
      *
-     * @hide pending API solidification
+     * @hide This is an implementation detail.
      */
     public void setJsFlags(String flags) {
         checkThread();
@@ -4016,7 +4016,7 @@
      * Gets the WebViewClient
      * @return the current WebViewClient instance.
      *
-     *@hide pending API council approval.
+     * @hide This is an implementation detail.
      */
     public WebViewClient getWebViewClient() {
         return mCallbackProxy.getWebViewClient();
@@ -4048,7 +4048,7 @@
      * Gets the chrome handler.
      * @return the current WebChromeClient instance.
      *
-     * @hide API council approval.
+     * @hide This is an implementation detail.
      */
     public WebChromeClient getWebChromeClient() {
         return mCallbackProxy.getWebChromeClient();
@@ -4431,7 +4431,7 @@
     /**
      * Select the word at the last click point.
      *
-     * @hide pending API council approval
+     * @hide This is an implementation detail.
      */
     public boolean selectText() {
         int x = viewToContentX(mLastTouchX + mScrollX);
@@ -5569,7 +5569,7 @@
     /**
      * Select all of the text in this WebView.
      *
-     * @hide pending API council approval.
+     * @hide This is an implementation detail.
      */
     public void selectAll() {
         if (0 == mNativeClass) return; // client isn't initialized
@@ -5612,7 +5612,7 @@
     /**
      * Copy the selection to the clipboard
      *
-     * @hide pending API council approval.
+     * @hide This is an implementation detail.
      */
     public boolean copySelection() {
         boolean copiedSomething = false;
@@ -5634,7 +5634,7 @@
     }
 
     /**
-     * @hide pending API Council approval.
+     * @hide This is an implementation detail.
      */
     public SearchBox getSearchBox() {
         if ((mWebViewCore == null) || (mWebViewCore.getBrowserFrame() == null)) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a178087..81fc069 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1202,14 +1202,17 @@
                 imm.hideSoftInputFromWindow(getWindowToken(), 0);
             }
         }
+
         super.setEnabled(enabled);
-        prepareCursorControllers();
+
         if (enabled) {
             // Make sure IME is updated with current editor info.
             InputMethodManager imm = InputMethodManager.peekInstance();
             if (imm != null) imm.restartInput(this);
         }
 
+        prepareCursorControllers();
+
         // start or stop the cursor blinking as appropriate
         makeBlink();
     }
@@ -8581,7 +8584,7 @@
      * @return True when the TextView isFocused and has a valid zero-length selection (cursor).
      */
     private boolean shouldBlink() {
-        if (!isFocused()) return false;
+        if (!isCursorVisible() || !isFocused()) return false;
 
         final int start = getSelectionStart();
         if (start < 0) return false;
@@ -8593,13 +8596,11 @@
     }
 
     private void makeBlink() {
-        if (isCursorVisible()) {
-            if (shouldBlink()) {
-                mShowCursor = SystemClock.uptimeMillis();
-                if (mBlink == null) mBlink = new Blink(this);
-                mBlink.removeCallbacks(mBlink);
-                mBlink.postAtTime(mBlink, mShowCursor + BLINK);
-            }
+        if (shouldBlink()) {
+            mShowCursor = SystemClock.uptimeMillis();
+            if (mBlink == null) mBlink = new Blink(this);
+            mBlink.removeCallbacks(mBlink);
+            mBlink.postAtTime(mBlink, mShowCursor + BLINK);
         } else {
             if (mBlink != null) mBlink.removeCallbacks(mBlink);
         }
diff --git a/core/java/android/widget/ViewAnimator.java b/core/java/android/widget/ViewAnimator.java
index 3c683d6..71ff66b 100644
--- a/core/java/android/widget/ViewAnimator.java
+++ b/core/java/android/widget/ViewAnimator.java
@@ -185,6 +185,10 @@
         } else {
             child.setVisibility(View.GONE);
         }
+        if (index >= 0 && mWhichChild >= index) {
+            // Added item above current one, increment the index of the displayed child
+            setDisplayedChild(mWhichChild + 1);
+        }
     }
 
     @Override
diff --git a/core/java/com/google/android/mms/pdu/PduParser.java b/core/java/com/google/android/mms/pdu/PduParser.java
index f7f71ed..015d864 100755
--- a/core/java/com/google/android/mms/pdu/PduParser.java
+++ b/core/java/com/google/android/mms/pdu/PduParser.java
@@ -934,6 +934,9 @@
         int temp = pduDataStream.read();
         assert(-1 != temp);
         int first = temp & 0xFF;
+        if (first == 0) {
+            return null;    //  Blank subject, bail.
+        }
 
         pduDataStream.reset();
         if (first < TEXT_MIN) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index bafee0e..8be1996 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -76,8 +76,6 @@
 	android_net_TrafficStats.cpp \
 	android_net_wifi_Wifi.cpp \
 	android_nio_utils.cpp \
-	android_nfc_NdefMessage.cpp \
-	android_nfc_NdefRecord.cpp \
 	android_text_format_Time.cpp \
 	android_util_AssetManager.cpp \
 	android_util_Binder.cpp \
@@ -214,7 +212,6 @@
 	libmedia \
 	libwpa_client \
 	libjpeg \
-	libnfc_ndef \
 	libusbhost \
 	libharfbuzz \
 	libz \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 8db7b24..af37454 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -129,8 +129,6 @@
 extern int register_android_database_SQLiteStatement(JNIEnv* env);
 extern int register_android_debug_JNITest(JNIEnv* env);
 extern int register_android_nio_utils(JNIEnv* env);
-extern int register_android_nfc_NdefMessage(JNIEnv *env);
-extern int register_android_nfc_NdefRecord(JNIEnv *env);
 extern int register_android_text_format_Time(JNIEnv* env);
 extern int register_android_os_Debug(JNIEnv* env);
 extern int register_android_os_MessageQueue(JNIEnv* env);
@@ -1161,8 +1159,6 @@
     REG_JNI(register_android_net_NetworkUtils),
     REG_JNI(register_android_net_TrafficStats),
     REG_JNI(register_android_net_wifi_WifiManager),
-    REG_JNI(register_android_nfc_NdefMessage),
-    REG_JNI(register_android_nfc_NdefRecord),
     REG_JNI(register_android_os_MemoryFile),
     REG_JNI(register_com_android_internal_os_ZygoteInit),
     REG_JNI(register_android_hardware_Camera),
diff --git a/core/jni/android_nfc_NdefMessage.cpp b/core/jni/android_nfc_NdefMessage.cpp
deleted file mode 100644
index 41099cb..0000000
--- a/core/jni/android_nfc_NdefMessage.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdlib.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-
-#include "android_nfc.h"
-
-namespace android {
-
-static jint android_nfc_NdefMessage_parseNdefMessage(JNIEnv *e, jobject o,
-        jbyteArray array)
-{
-    uint16_t status;
-    uint32_t i;
-    jbyte *raw_msg;
-    jsize raw_msg_size;
-    uint32_t num_of_records = 0;
-    uint8_t **records = NULL;
-    uint8_t *is_chunked = NULL;
-    jint ret = -1;
-    phFriNfc_NdefRecord_t record;
-
-    jclass record_cls;
-    jobjectArray records_array;
-    jmethodID ctor;
-
-    jclass msg_cls;
-    jfieldID mrecords;
-
-    raw_msg_size = e->GetArrayLength(array);
-    raw_msg = e->GetByteArrayElements(array, NULL);
-    if (raw_msg == NULL)
-        return -1;
-
-    /* Get the number of records in the message so we can allocate buffers */
-    TRACE("phFriNfc_NdefRecord_GetRecords(NULL)");
-
-    status = phFriNfc_NdefRecord_GetRecords((uint8_t *)raw_msg,
-            (uint32_t)raw_msg_size, NULL, NULL, &num_of_records);
-
-    if (status) {
-        LOGE("phFriNfc_NdefRecord_GetRecords(NULL) returned 0x%04x", status);
-        goto end;
-    }
-    TRACE("phFriNfc_NdefRecord_GetRecords(NULL) returned 0x%04x, with %d records", status, num_of_records);
-
-    is_chunked = (uint8_t*)malloc(num_of_records);
-    if (is_chunked == NULL)
-        goto end;
-    records = (uint8_t**)malloc(num_of_records * sizeof(uint8_t *));
-    if (records == NULL)
-        goto end;
-
-    /* Now, actually retrieve records position in message */
-    TRACE("phFriNfc_NdefRecord_GetRecords()");
-
-    status = phFriNfc_NdefRecord_GetRecords((uint8_t *)raw_msg,
-            (uint32_t)raw_msg_size, records, is_chunked, &num_of_records);
-
-    if (status) {
-        LOGE("phFriNfc_NdefRecord_GetRecords() returned 0x%04x", status);
-        goto end;
-    }
-    TRACE("phFriNfc_NdefRecord_GetRecords() returned 0x%04x, with %d records", status, num_of_records);
-
-    /* Build NDEF records array */
-    record_cls = e->FindClass("android/nfc/NdefRecord");
-    records_array = e->NewObjectArray((jsize)num_of_records, record_cls,
-            NULL);
-    if (records_array == NULL)
-        goto end;
-
-    ctor = e->GetMethodID(record_cls, "<init>", "(S[B[B[BB)V");
-
-    for (i = 0; i < num_of_records; i++) {
-        jbyteArray type, id, payload;
-        jobject new_record;
-
-        TRACE("phFriNfc_NdefRecord_Parse()");
-
-        status = phFriNfc_NdefRecord_Parse(&record, records[i]);
-
-        if (status) {
-            LOGE("phFriNfc_NdefRecord_Parse() returned 0x%04x", status);
-            goto end;
-        }
-        TRACE("phFriNfc_NdefRecord_Parse() returned 0x%04x", status);
-
-        // We don't exactly know what *is* a valid length, but a simple
-        // sanity check is to make sure that the length of the header
-        // plus all fields does not exceed raw_msg_size. The min length
-        // of the header is 3 bytes: TNF, Type Length, Payload Length
-        // (ID length field is optional!)
-        uint64_t indicatedMsgLength = 3 + record.TypeLength + record.IdLength +
-                (uint64_t)record.PayloadLength;
-        if (indicatedMsgLength >
-                (uint64_t)raw_msg_size) {
-            LOGE("phFri_NdefRecord_Parse: invalid length field");
-            goto end;
-        }
-
-        type = e->NewByteArray(record.TypeLength);
-        if (type == NULL) {
-            LOGD("NFC_Set Record Type Error\n");
-            goto end;
-        }
-
-        id = e->NewByteArray(record.IdLength);
-        if(id == NULL) {
-            LOGD("NFC_Set Record ID Error\n");
-            goto end;
-        }
-
-        payload = e->NewByteArray(record.PayloadLength);
-        if(payload == NULL) {
-            LOGD("NFC_Set Record Payload Error\n");
-            goto end;
-        }
-
-        e->SetByteArrayRegion(type, 0, record.TypeLength,
-                (jbyte *)record.Type);
-        e->SetByteArrayRegion(id, 0, record.IdLength,
-                (jbyte *)record.Id);
-        e->SetByteArrayRegion(payload, 0, record.PayloadLength,
-                (jbyte *)record.PayloadData);
-
-        new_record = e->NewObject(record_cls, ctor,
-                (jshort)record.Tnf, type, id, payload, (jbyte)record.Flags);
-
-        e->SetObjectArrayElement(records_array, i, new_record);
-
-        /* Try not to clutter the Java stack too much */
-        e->DeleteLocalRef(new_record);
-        e->DeleteLocalRef(type);
-        e->DeleteLocalRef(id);
-        e->DeleteLocalRef(payload);
-    }
-
-    /* Store built array in our NDEFMessage instance */
-    msg_cls = e->GetObjectClass(o);
-    mrecords = e->GetFieldID(msg_cls, "mRecords", "[Landroid/nfc/NdefRecord;");
-
-    e->SetObjectField(o, mrecords, (jobject)records_array);
-
-    ret = 0;
-
-end:
-    if(is_chunked)
-        free(is_chunked);
-    if(records)
-        free(records);
-    e->ReleaseByteArrayElements(array, raw_msg, JNI_ABORT);
-
-    return ret;
-}
-
-static JNINativeMethod gMethods[] = {
-        {"parseNdefMessage", "([B)I", (void *)android_nfc_NdefMessage_parseNdefMessage},
-};
-
-int register_android_nfc_NdefMessage(JNIEnv *e)
-{
-    return jniRegisterNativeMethods(e, "android/nfc/NdefMessage", gMethods, NELEM(gMethods));
-}
-
-} // namespace android
diff --git a/core/jni/android_nfc_NdefRecord.cpp b/core/jni/android_nfc_NdefRecord.cpp
deleted file mode 100644
index 67907b6..0000000
--- a/core/jni/android_nfc_NdefRecord.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "NdefRecord"
-
-#include <stdlib.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-
-#include "android_nfc.h"
-
-#include <utils/Log.h>
-
-namespace android {
-
-static jbyteArray android_nfc_NdefRecord_generate(
-        JNIEnv *e, jobject o, jshort flags, jshort tnf, jbyteArray type,
-        jbyteArray id, jbyteArray payload)
-{
-    uint32_t status;
-    phFriNfc_NdefRecord_t record;
-    uint32_t buf_size;
-    uint32_t record_size;
-    uint8_t *buf = NULL;
-    jbyteArray result = NULL;
-
-    /* Prepare NDEF record structure */
-    record.Flags = (uint8_t)flags;
-    record.Tnf = (uint8_t)tnf;
-    record.TypeLength = (uint32_t)e->GetArrayLength(type);
-    record.Type = (uint8_t *)e->GetByteArrayElements(type, NULL);
-    record.IdLength = (uint32_t)e->GetArrayLength(id);
-    record.Id = (uint8_t *)e->GetByteArrayElements(id, NULL);
-    record.PayloadLength = (uint32_t)e->GetArrayLength(payload);
-    record.PayloadData = (uint8_t *)e->GetByteArrayElements(payload, NULL);
-
-    buf_size = record.PayloadLength + record.IdLength + record.TypeLength + 8;
-
-    buf = (uint8_t*)malloc(buf_size);
-    if (buf == NULL)
-        goto end;
-
-    TRACE("phFriNfc_NdefRecord_Generate()");
-
-    status = phFriNfc_NdefRecord_Generate(&record, buf, buf_size,
-            &record_size);
-
-    if (status) {
-        LOGE("phFriNfc_NdefRecord_Generate() returned 0x%04x", status);
-        goto end;
-    }
-    TRACE("phFriNfc_NdefRecord_Generate() returned 0x%04x", status);
-
-    result = e->NewByteArray(record_size);
-    if (result == NULL)
-        goto end;
-
-    e->SetByteArrayRegion(result, 0, record_size, (jbyte *)buf);
-
-end:
-    e->ReleaseByteArrayElements(type, (jbyte *)record.Type, JNI_ABORT);
-    e->ReleaseByteArrayElements(id, (jbyte *)record.Id, JNI_ABORT);
-    e->ReleaseByteArrayElements(payload, (jbyte *)record.PayloadData, JNI_ABORT);
-
-    if(buf)
-        free(buf);
-
-    return result;
-}
-
-static jint android_nfc_NdefRecord_parseNdefRecord(JNIEnv *e, jobject o,
-        jbyteArray array)
-{
-    uint16_t status;
-    jbyte *raw_record;
-    jsize raw_record_size;
-    jint ret = -1;
-    phFriNfc_NdefRecord_t record;
-
-    jfieldID mType, mId, mPayload, mTnf, mFlags;
-    jbyteArray type = NULL;
-    jbyteArray id = NULL;
-    jbyteArray payload = NULL;
-
-    jclass record_cls = e->GetObjectClass(o);
-
-    raw_record_size = e->GetArrayLength(array);
-    raw_record = e->GetByteArrayElements(array, NULL);
-    if (raw_record == NULL) {
-        goto clean_and_return;
-    }
-
-    TRACE("phFriNfc_NdefRecord_Parse()");
-    status = phFriNfc_NdefRecord_Parse(&record, (uint8_t *)raw_record);
-    if (status) {
-        LOGE("phFriNfc_NdefRecord_Parse() returned 0x%04x", status);
-        goto clean_and_return;
-    }
-    TRACE("phFriNfc_NdefRecord_Parse() returned 0x%04x", status);
-
-    /* Set TNF field */
-    mTnf = e->GetFieldID(record_cls, "mTnf", "S");
-    e->SetShortField(o, mTnf, record.Tnf);
-
-    /* Set type field */
-    mType = e->GetFieldID(record_cls, "mType", "[B");
-    type = e->NewByteArray(record.TypeLength);
-    if (type == NULL) {
-        goto clean_and_return;
-    }
-    e->SetByteArrayRegion(type, 0, record.TypeLength,
-            (jbyte *)record.Type);
-    e->SetObjectField(o, mType, type);
-
-    /* Set id field */
-    mId = e->GetFieldID(record_cls, "mId", "[B");
-    id = e->NewByteArray(record.IdLength);
-    if (id == NULL) {
-        goto clean_and_return;
-    }
-    e->SetByteArrayRegion(id, 0, record.IdLength,
-            (jbyte *)record.Id);
-    e->SetObjectField(o, mId, id);
-
-    /* Set payload field */
-    mPayload = e->GetFieldID(record_cls, "mPayload", "[B");
-    payload = e->NewByteArray(record.PayloadLength);
-    if (payload == NULL) {
-        goto clean_and_return;
-    }
-
-    e->SetByteArrayRegion(payload, 0, record.PayloadLength,
-            (jbyte *)record.PayloadData);
-    e->SetObjectField(o, mPayload, payload);
-
-    /* Set flags field */
-    mFlags = e->GetFieldID(record_cls, "mFlags", "B");
-    e->SetByteField(o, mFlags, record.Flags);
-
-    ret = 0;
-
-clean_and_return:
-    if (type != NULL) {
-        e->DeleteLocalRef(type);
-    }
-    if (id != NULL) {
-        e->DeleteLocalRef(id);
-    }
-    if (payload != NULL) {
-        e->DeleteLocalRef(payload);
-    }
-    if (raw_record != NULL) {
-        e->ReleaseByteArrayElements(array, raw_record, JNI_ABORT);
-    }
-
-    return ret;
-}
-
-static JNINativeMethod gMethods[] = {
-    {"generate", "(SS[B[B[B)[B", (void *)android_nfc_NdefRecord_generate},
-    {"parseNdefRecord", "([B)I", (void *)android_nfc_NdefRecord_parseNdefRecord},
-};
-
-int register_android_nfc_NdefRecord(JNIEnv *e)
-{
-    return jniRegisterNativeMethods(e, "android/nfc/NdefRecord", gMethods, NELEM(gMethods));
-}
-
-} // namespace android
diff --git a/docs/html/guide/topics/media/camera.jd b/docs/html/guide/topics/media/camera.jd
index b962f96..4e928b3 100644
--- a/docs/html/guide/topics/media/camera.jd
+++ b/docs/html/guide/topics/media/camera.jd
@@ -1037,7 +1037,7 @@
 }
 
 /** Create a File for saving an image or video */
-private static Uri getOutputMediaFile(int type){
+private static File getOutputMediaFile(int type){
     // To be safe, you should check that the SDCard is mounted
     // using Environment.getExternalStorageState() before doing this.
 
diff --git a/docs/html/guide/topics/sensors/index.jd b/docs/html/guide/topics/sensors/index.jd
index e00a5b1..75a1716 100644
--- a/docs/html/guide/topics/sensors/index.jd
+++ b/docs/html/guide/topics/sensors/index.jd
@@ -81,7 +81,7 @@
       Sensors</a></strong></dt>
     <dd>Learn how to use the sensors that provide orientation and compass data, such as the
       orientation sensor and the geomagnetic field sensor.</dd>
-  <dt><strong><a href="{@docRoot}guide/topics/sensors/environment.html">Environment
+  <dt><strong><a href="{@docRoot}guide/topics/sensors/sensors_environment.html">Environment
         Sensors</a></strong></dt>
     <dd>Learn how to use the sensors that provide environmental data, such as the light,
       humidity, pressure, temperature, and proximity sensors.</dd>
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 7efdc6c..f02d0f9 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -42,7 +42,7 @@
  * <p>spin_animation.xml file in res/drawable/ folder:</p>
  * <pre>&lt;!-- Animation frames are wheel0.png -- wheel5.png files inside the
  * res/drawable/ folder --&gt;
- * &lt;animation-list android:id=&quot;selected&quot; android:oneshot=&quot;false&quot;&gt;
+ * &lt;animation-list android:id=&quot;@+id/selected&quot; android:oneshot=&quot;false&quot;&gt;
  *    &lt;item android:drawable=&quot;@drawable/wheel0&quot; android:duration=&quot;50&quot; /&gt;
  *    &lt;item android:drawable=&quot;@drawable/wheel1&quot; android:duration=&quot;50&quot; /&gt;
  *    &lt;item android:drawable=&quot;@drawable/wheel2&quot; android:duration=&quot;50&quot; /&gt;
@@ -216,6 +216,8 @@
             unscheduleSelf(this);
         }
         if (animate) {
+            // Unscheduling may have clobbered this value; restore it to record that we're animating
+            mCurFrame = frame;
             scheduleSelf(this, SystemClock.uptimeMillis() + mAnimationState.mDurations[frame]);
         }
     }
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index b02ca38..108d36a 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -133,7 +133,8 @@
 int  LvmEffect_enable          (EffectContext *pContext);
 int  LvmEffect_disable         (EffectContext *pContext);
 void LvmEffect_free            (EffectContext *pContext);
-int  Effect_configure          (EffectContext *pContext, effect_config_t *pConfig);
+int  Effect_setConfig          (EffectContext *pContext, effect_config_t *pConfig);
+void Effect_getConfig          (EffectContext *pContext, effect_config_t *pConfig);
 int  BassBoost_setParameter    (EffectContext *pContext, void *pParam, void *pValue);
 int  BassBoost_getParameter    (EffectContext *pContext,
                                void           *pParam,
@@ -936,7 +937,7 @@
 }    /* end LvmEffect_free */
 
 //----------------------------------------------------------------------------
-// Effect_configure()
+// Effect_setConfig()
 //----------------------------------------------------------------------------
 // Purpose: Set input and output audio configuration.
 //
@@ -949,9 +950,9 @@
 //
 //----------------------------------------------------------------------------
 
-int Effect_configure(EffectContext *pContext, effect_config_t *pConfig){
+int Effect_setConfig(EffectContext *pContext, effect_config_t *pConfig){
     LVM_Fs_en   SampleRate;
-    //ALOGV("\tEffect_configure start");
+    //ALOGV("\tEffect_setConfig start");
 
     CHECK_ARG(pContext != NULL);
     CHECK_ARG(pConfig != NULL);
@@ -992,7 +993,7 @@
         pContext->pBundledContext->SamplesPerSecond = 48000*2; // 2 secs Stereo
         break;
     default:
-        ALOGV("\tEffect_Configure invalid sampling rate %d", pConfig->inputCfg.samplingRate);
+        ALOGV("\tEffect_setConfig invalid sampling rate %d", pConfig->inputCfg.samplingRate);
         return -EINVAL;
     }
 
@@ -1001,28 +1002,47 @@
         LVM_ControlParams_t     ActiveParams;
         LVM_ReturnStatus_en     LvmStatus = LVM_SUCCESS;
 
-        ALOGV("\tEffect_configure change sampling rate to %d", SampleRate);
+        ALOGV("\tEffect_setConfig change sampling rate to %d", SampleRate);
 
         /* Get the current settings */
         LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance,
                                          &ActiveParams);
 
-        LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "Effect_configure")
+        LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "Effect_setConfig")
         if(LvmStatus != LVM_SUCCESS) return -EINVAL;
 
         LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams);
 
-        LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "Effect_configure")
-        ALOGV("\tEffect_configure Succesfully called LVM_SetControlParameters\n");
+        LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "Effect_setConfig")
+        ALOGV("\tEffect_setConfig Succesfully called LVM_SetControlParameters\n");
         pContext->pBundledContext->SampleRate = SampleRate;
 
     }else{
-        //ALOGV("\tEffect_configure keep sampling rate at %d", SampleRate);
+        //ALOGV("\tEffect_setConfig keep sampling rate at %d", SampleRate);
     }
 
-    //ALOGV("\tEffect_configure End....");
+    //ALOGV("\tEffect_setConfig End....");
     return 0;
-}   /* end Effect_configure */
+}   /* end Effect_setConfig */
+
+//----------------------------------------------------------------------------
+// Effect_getConfig()
+//----------------------------------------------------------------------------
+// Purpose: Get input and output audio configuration.
+//
+// Inputs:
+//  pContext:   effect engine context
+//  pConfig:    pointer to effect_config_t structure holding input and output
+//      configuration parameters
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+void Effect_getConfig(EffectContext *pContext, effect_config_t *pConfig)
+{
+    memcpy(pConfig, &pContext->config, sizeof(effect_config_t));
+}   /* end Effect_getConfig */
 
 //----------------------------------------------------------------------------
 // BassGetStrength()
@@ -2778,23 +2798,34 @@
             }
             break;
 
-        case EFFECT_CMD_CONFIGURE:
-            //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_CONFIGURE start");
+        case EFFECT_CMD_SET_CONFIG:
+            //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_CONFIG start");
             if (pCmdData    == NULL||
                 cmdSize     != sizeof(effect_config_t)||
                 pReplyData  == NULL||
                 *replySize  != sizeof(int)){
                 ALOGV("\tLVM_ERROR : Effect_command cmdCode Case: "
-                        "EFFECT_CMD_CONFIGURE: ERROR");
+                        "EFFECT_CMD_SET_CONFIG: ERROR");
                 return -EINVAL;
             }
-            *(int *) pReplyData = android::Effect_configure(pContext, (effect_config_t *) pCmdData);
-            //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_CONFIGURE end");
+            *(int *) pReplyData = android::Effect_setConfig(pContext, (effect_config_t *) pCmdData);
+            //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_CONFIG end");
+            break;
+
+        case EFFECT_CMD_GET_CONFIG:
+            if (pReplyData == NULL ||
+                *replySize != sizeof(effect_config_t)) {
+                ALOGV("\tLVM_ERROR : Effect_command cmdCode Case: "
+                        "EFFECT_CMD_GET_CONFIG: ERROR");
+                return -EINVAL;
+            }
+
+            android::Effect_getConfig(pContext, (effect_config_t *)pReplyData);
             break;
 
         case EFFECT_CMD_RESET:
             //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_RESET start");
-            android::Effect_configure(pContext, &pContext->config);
+            android::Effect_setConfig(pContext, &pContext->config);
             //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_RESET end");
             break;
 
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 1825aab..09cd5cc 100755
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -175,7 +175,8 @@
 //--- local function prototypes
 int  Reverb_init            (ReverbContext *pContext);
 void Reverb_free            (ReverbContext *pContext);
-int  Reverb_configure       (ReverbContext *pContext, effect_config_t *pConfig);
+int  Reverb_setConfig       (ReverbContext *pContext, effect_config_t *pConfig);
+void Reverb_getConfig       (ReverbContext *pContext, effect_config_t *pConfig);
 int  Reverb_setParameter    (ReverbContext *pContext, void *pParam, void *pValue);
 int  Reverb_getParameter    (ReverbContext *pContext,
                              void          *pParam,
@@ -609,7 +610,7 @@
 }    /* end Reverb_free */
 
 //----------------------------------------------------------------------------
-// Reverb_configure()
+// Reverb_setConfig()
 //----------------------------------------------------------------------------
 // Purpose: Set input and output audio configuration.
 //
@@ -622,9 +623,9 @@
 //
 //----------------------------------------------------------------------------
 
-int Reverb_configure(ReverbContext *pContext, effect_config_t *pConfig){
+int Reverb_setConfig(ReverbContext *pContext, effect_config_t *pConfig){
     LVM_Fs_en   SampleRate;
-    //ALOGV("\tReverb_configure start");
+    //ALOGV("\tReverb_setConfig start");
 
     CHECK_ARG(pContext != NULL);
     CHECK_ARG(pConfig != NULL);
@@ -642,7 +643,7 @@
         return -EINVAL;
     }
 
-    //ALOGV("\tReverb_configure calling memcpy");
+    //ALOGV("\tReverb_setConfig calling memcpy");
     memcpy(&pContext->config, pConfig, sizeof(effect_config_t));
 
 
@@ -666,7 +667,7 @@
         SampleRate = LVM_FS_48000;
         break;
     default:
-        ALOGV("\rReverb_Configure invalid sampling rate %d", pConfig->inputCfg.samplingRate);
+        ALOGV("\rReverb_setConfig invalid sampling rate %d", pConfig->inputCfg.samplingRate);
         return -EINVAL;
     }
 
@@ -675,28 +676,46 @@
         LVREV_ControlParams_st    ActiveParams;
         LVREV_ReturnStatus_en     LvmStatus = LVREV_SUCCESS;
 
-        //ALOGV("\tReverb_configure change sampling rate to %d", SampleRate);
+        //ALOGV("\tReverb_setConfig change sampling rate to %d", SampleRate);
 
         /* Get the current settings */
         LvmStatus = LVREV_GetControlParameters(pContext->hInstance,
                                          &ActiveParams);
 
-        LVM_ERROR_CHECK(LvmStatus, "LVREV_GetControlParameters", "Reverb_configure")
+        LVM_ERROR_CHECK(LvmStatus, "LVREV_GetControlParameters", "Reverb_setConfig")
         if(LvmStatus != LVREV_SUCCESS) return -EINVAL;
 
         LvmStatus = LVREV_SetControlParameters(pContext->hInstance, &ActiveParams);
 
-        LVM_ERROR_CHECK(LvmStatus, "LVREV_SetControlParameters", "Reverb_configure")
-        //ALOGV("\tReverb_configure Succesfully called LVREV_SetControlParameters\n");
+        LVM_ERROR_CHECK(LvmStatus, "LVREV_SetControlParameters", "Reverb_setConfig")
+        //ALOGV("\tReverb_setConfig Succesfully called LVREV_SetControlParameters\n");
 
     }else{
-        //ALOGV("\tReverb_configure keep sampling rate at %d", SampleRate);
+        //ALOGV("\tReverb_setConfig keep sampling rate at %d", SampleRate);
     }
 
-    //ALOGV("\tReverb_configure End");
+    //ALOGV("\tReverb_setConfig End");
     return 0;
-}   /* end Reverb_configure */
+}   /* end Reverb_setConfig */
 
+//----------------------------------------------------------------------------
+// Reverb_getConfig()
+//----------------------------------------------------------------------------
+// Purpose: Get input and output audio configuration.
+//
+// Inputs:
+//  pContext:   effect engine context
+//  pConfig:    pointer to effect_config_t structure holding input and output
+//      configuration parameters
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+void Reverb_getConfig(ReverbContext *pContext, effect_config_t *pConfig)
+{
+    memcpy(pConfig, &pContext->config, sizeof(effect_config_t));
+}   /* end Reverb_getConfig */
 
 //----------------------------------------------------------------------------
 // Reverb_init()
@@ -1924,24 +1943,36 @@
             *(int *) pReplyData = 0;
             break;
 
-        case EFFECT_CMD_CONFIGURE:
+        case EFFECT_CMD_SET_CONFIG:
             //ALOGV("\tReverb_command cmdCode Case: "
-            //        "EFFECT_CMD_CONFIGURE start");
-            if (pCmdData    == NULL||
-                cmdSize     != sizeof(effect_config_t)||
-                pReplyData  == NULL||
-                *replySize  != sizeof(int)){
+            //        "EFFECT_CMD_SET_CONFIG start");
+            if (pCmdData == NULL ||
+                cmdSize != sizeof(effect_config_t) ||
+                pReplyData == NULL ||
+                *replySize != sizeof(int)) {
                 ALOGV("\tLVM_ERROR : Reverb_command cmdCode Case: "
-                        "EFFECT_CMD_CONFIGURE: ERROR");
+                        "EFFECT_CMD_SET_CONFIG: ERROR");
                 return -EINVAL;
             }
-            *(int *) pReplyData = Reverb_configure(pContext, (effect_config_t *) pCmdData);
+            *(int *) pReplyData = android::Reverb_setConfig(pContext,
+                                                            (effect_config_t *) pCmdData);
+            break;
+
+        case EFFECT_CMD_GET_CONFIG:
+            if (pReplyData == NULL ||
+                *replySize != sizeof(effect_config_t)) {
+                ALOGV("\tLVM_ERROR : Reverb_command cmdCode Case: "
+                        "EFFECT_CMD_GET_CONFIG: ERROR");
+                return -EINVAL;
+            }
+
+            android::Reverb_getConfig(pContext, (effect_config_t *)pReplyData);
             break;
 
         case EFFECT_CMD_RESET:
             //ALOGV("\tReverb_command cmdCode Case: "
             //        "EFFECT_CMD_RESET start");
-            Reverb_configure(pContext, &pContext->config);
+            Reverb_setConfig(pContext, &pContext->config);
             break;
 
         case EFFECT_CMD_GET_PARAM:{
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index b15614a..c99552b 100755
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -940,6 +940,19 @@
     return 0;
 }
 
+void Session_GetConfig(preproc_session_t *session, effect_config_t *config)
+{
+    memset(config, 0, sizeof(effect_config_t));
+    config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
+    config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    config->inputCfg.channels = session->inChannelCount == 1 ?
+                                    AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO;
+    config->outputCfg.channels = session->outChannelCount == 1 ?
+                                    AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO;
+    config->inputCfg.mask = config->outputCfg.mask =
+            (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
+}
+
 int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config)
 {
     if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
@@ -969,6 +982,17 @@
     return 0;
 }
 
+void Session_GetReverseConfig(preproc_session_t *session, effect_config_t *config)
+{
+    memset(config, 0, sizeof(effect_config_t));
+    config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
+    config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    config->inputCfg.channels = config->outputCfg.channels =
+            session->revChannelCount == 1 ? AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO;
+    config->inputCfg.mask = config->outputCfg.mask =
+            (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
+}
+
 void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled)
 {
     if (enabled) {
@@ -1250,13 +1274,13 @@
             *(int *)pReplyData = 0;
             break;
 
-        case EFFECT_CMD_CONFIGURE:
+        case EFFECT_CMD_SET_CONFIG:
             if (pCmdData    == NULL||
                 cmdSize     != sizeof(effect_config_t)||
                 pReplyData  == NULL||
                 *replySize  != sizeof(int)){
                 ALOGV("PreProcessingFx_Command cmdCode Case: "
-                        "EFFECT_CMD_CONFIGURE: ERROR");
+                        "EFFECT_CMD_SET_CONFIG: ERROR");
                 return -EINVAL;
             }
             *(int *)pReplyData = Session_SetConfig(effect->session, (effect_config_t *)pCmdData);
@@ -1266,13 +1290,24 @@
             *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
             break;
 
-        case EFFECT_CMD_CONFIGURE_REVERSE:
-            if (pCmdData    == NULL||
-                cmdSize     != sizeof(effect_config_t)||
-                pReplyData  == NULL||
-                *replySize  != sizeof(int)){
+        case EFFECT_CMD_GET_CONFIG:
+            if (pReplyData == NULL ||
+                *replySize != sizeof(effect_config_t)) {
+                ALOGV("\tLVM_ERROR : PreProcessingFx_Command cmdCode Case: "
+                        "EFFECT_CMD_GET_CONFIG: ERROR");
+                return -EINVAL;
+            }
+
+            Session_GetConfig(effect->session, (effect_config_t *)pCmdData);
+            break;
+
+        case EFFECT_CMD_SET_CONFIG_REVERSE:
+            if (pCmdData == NULL ||
+                cmdSize != sizeof(effect_config_t) ||
+                pReplyData == NULL ||
+                *replySize != sizeof(int)) {
                 ALOGV("PreProcessingFx_Command cmdCode Case: "
-                        "EFFECT_CMD_CONFIGURE_REVERSE: ERROR");
+                        "EFFECT_CMD_SET_CONFIG_REVERSE: ERROR");
                 return -EINVAL;
             }
             *(int *)pReplyData = Session_SetReverseConfig(effect->session,
@@ -1282,6 +1317,16 @@
             }
             break;
 
+        case EFFECT_CMD_GET_CONFIG_REVERSE:
+            if (pReplyData == NULL ||
+                *replySize != sizeof(effect_config_t)){
+                ALOGV("PreProcessingFx_Command cmdCode Case: "
+                        "EFFECT_CMD_GET_CONFIG_REVERSE: ERROR");
+                return -EINVAL;
+            }
+            Session_GetReverseConfig(effect->session, (effect_config_t *)pCmdData);
+            break;
+
         case EFFECT_CMD_RESET:
             if (effect->ops->reset) {
                 effect->ops->reset(effect);
diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp
index 79a296c..52fbf79 100644
--- a/media/libeffects/testlibs/EffectEqualizer.cpp
+++ b/media/libeffects/testlibs/EffectEqualizer.cpp
@@ -114,7 +114,7 @@
 //--- local function prototypes
 
 int Equalizer_init(EqualizerContext *pContext);
-int Equalizer_configure(EqualizerContext *pContext, effect_config_t *pConfig);
+int Equalizer_setConfig(EqualizerContext *pContext, effect_config_t *pConfig);
 int Equalizer_getParameter(AudioEqualizer * pEqualizer, int32_t *pParam, size_t *pValueSize, void *pValue);
 int Equalizer_setParameter(AudioEqualizer * pEqualizer, int32_t *pParam, void *pValue);
 
@@ -224,7 +224,7 @@
 }
 
 //----------------------------------------------------------------------------
-// Equalizer_configure()
+// Equalizer_setConfig()
 //----------------------------------------------------------------------------
 // Purpose: Set input and output audio configuration.
 //
@@ -237,9 +237,9 @@
 //
 //----------------------------------------------------------------------------
 
-int Equalizer_configure(EqualizerContext *pContext, effect_config_t *pConfig)
+int Equalizer_setConfig(EqualizerContext *pContext, effect_config_t *pConfig)
 {
-    ALOGV("Equalizer_configure start");
+    ALOGV("Equalizer_setConfig start");
 
     CHECK_ARG(pContext != NULL);
     CHECK_ARG(pConfig != NULL);
@@ -272,7 +272,26 @@
                         pConfig->outputCfg.accessMode);
 
     return 0;
-}   // end Equalizer_configure
+}   // end Equalizer_setConfig
+
+//----------------------------------------------------------------------------
+// Equalizer_getConfig()
+//----------------------------------------------------------------------------
+// Purpose: Get input and output audio configuration.
+//
+// Inputs:
+//  pContext:   effect engine context
+//  pConfig:    pointer to effect_config_t structure holding input and output
+//      configuration parameters
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+void Equalizer_getConfig(EqualizerContext *pContext, effect_config_t *pConfig)
+{
+    memcpy(pConfig, &pContext->config, sizeof(effect_config_t));
+}   // end Equalizer_getConfig
 
 
 //----------------------------------------------------------------------------
@@ -332,7 +351,7 @@
 
     pContext->pEqualizer->enable(true);
 
-    Equalizer_configure(pContext, &pContext->config);
+    Equalizer_setConfig(pContext, &pContext->config);
 
     return 0;
 }   // end Equalizer_init
@@ -643,16 +662,22 @@
         }
         *(int *) pReplyData = Equalizer_init(pContext);
         break;
-    case EFFECT_CMD_CONFIGURE:
+    case EFFECT_CMD_SET_CONFIG:
         if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
                 || pReplyData == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
-        *(int *) pReplyData = Equalizer_configure(pContext,
+        *(int *) pReplyData = Equalizer_setConfig(pContext,
                 (effect_config_t *) pCmdData);
         break;
+    case EFFECT_CMD_GET_CONFIG:
+        if (pReplyData == NULL || *replySize != sizeof(effect_config_t)) {
+            return -EINVAL;
+        }
+        Equalizer_getConfig(pContext, (effect_config_t *) pCmdData);
+        break;
     case EFFECT_CMD_RESET:
-        Equalizer_configure(pContext, &pContext->config);
+        Equalizer_setConfig(pContext, &pContext->config);
         break;
     case EFFECT_CMD_GET_PARAM: {
         if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
diff --git a/media/libeffects/testlibs/EffectReverb.c b/media/libeffects/testlibs/EffectReverb.c
index 1da8d32..419a41c 100644
--- a/media/libeffects/testlibs/EffectReverb.c
+++ b/media/libeffects/testlibs/EffectReverb.c
@@ -318,14 +318,20 @@
             pRvbModule->context.mState = REVERB_STATE_INITIALIZED;
         }
         break;
-    case EFFECT_CMD_CONFIGURE:
+    case EFFECT_CMD_SET_CONFIG:
         if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
                 || pReplyData == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
-        *(int *) pReplyData = Reverb_Configure(pRvbModule,
+        *(int *) pReplyData = Reverb_setConfig(pRvbModule,
                 (effect_config_t *)pCmdData, false);
         break;
+    case EFFECT_CMD_GET_CONFIG:
+        if (pReplyData == NULL || *replySize != sizeof(effect_config_t)) {
+            return -EINVAL;
+        }
+        Reverb_getConfig(pRvbModule, (effect_config_t *) pCmdData);
+        break;
     case EFFECT_CMD_RESET:
         Reverb_Reset(pReverb, false);
         break;
@@ -492,7 +498,7 @@
     pRvbModule->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
     pRvbModule->config.outputCfg.mask = EFFECT_CONFIG_ALL;
 
-    ret = Reverb_Configure(pRvbModule, &pRvbModule->config, true);
+    ret = Reverb_setConfig(pRvbModule, &pRvbModule->config, true);
     if (ret < 0) {
         ALOGV("Reverb_Init error %d on module %p", ret, pRvbModule);
     }
@@ -501,7 +507,7 @@
 }
 
 /*----------------------------------------------------------------------------
- * Reverb_Init()
+ * Reverb_setConfig()
  *----------------------------------------------------------------------------
  * Purpose:
  *  Set input and output audio configuration.
@@ -518,7 +524,7 @@
  *----------------------------------------------------------------------------
  */
 
-int Reverb_Configure(reverb_module_t *pRvbModule, effect_config_t *pConfig,
+int Reverb_setConfig(reverb_module_t *pRvbModule, effect_config_t *pConfig,
         bool init) {
     reverb_object_t *pReverb = &pRvbModule->context;
     int bufferSizeInSamples;
@@ -531,12 +537,12 @@
         || pConfig->outputCfg.channels != OUTPUT_CHANNELS
         || pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT
         || pConfig->outputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
-        ALOGV("Reverb_Configure invalid config");
+        ALOGV("Reverb_setConfig invalid config");
         return -EINVAL;
     }
     if ((pReverb->m_Aux && (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_MONO)) ||
         (!pReverb->m_Aux && (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO))) {
-        ALOGV("Reverb_Configure invalid config");
+        ALOGV("Reverb_setConfig invalid config");
         return -EINVAL;
     }
 
@@ -576,7 +582,7 @@
         pReverb->m_nCosWT_5KHz = 25997;
         break;
     default:
-        ALOGV("Reverb_Configure invalid sampling rate %d", pReverb->m_nSamplingRate);
+        ALOGV("Reverb_setConfig invalid sampling rate %d", pReverb->m_nSamplingRate);
         return -EINVAL;
     }
 
@@ -620,6 +626,28 @@
 }
 
 /*----------------------------------------------------------------------------
+ * Reverb_getConfig()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ *  Get input and output audio configuration.
+ *
+ * Inputs:
+ *  pRvbModule    - pointer to reverb effect module
+ *  pConfig       - pointer to effect_config_t structure containing input
+ *              and output audio parameters configuration
+ * Outputs:
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void Reverb_getConfig(reverb_module_t *pRvbModule, effect_config_t *pConfig)
+{
+    memcpy(pConfig, &pRvbModule->config, sizeof(effect_config_t));
+}
+
+/*----------------------------------------------------------------------------
  * Reverb_Reset()
  *----------------------------------------------------------------------------
  * Purpose:
@@ -844,7 +872,7 @@
             if (param == REVERB_PARAM_ROOM_HF_LEVEL) {
                 break;
             }
-            pValue32 = &pProperties->decayTime;
+            pValue32 = (int32_t *)&pProperties->decayTime;
             /* FALL THROUGH */
 
         case REVERB_PARAM_DECAY_TIME:
@@ -916,7 +944,7 @@
             if (param == REVERB_PARAM_REFLECTIONS_LEVEL) {
                 break;
             }
-            pValue32 = &pProperties->reflectionsDelay;
+            pValue32 = (int32_t *)&pProperties->reflectionsDelay;
             /* FALL THROUGH */
 
         case REVERB_PARAM_REFLECTIONS_DELAY:
@@ -940,7 +968,7 @@
             if (param == REVERB_PARAM_REVERB_LEVEL) {
                 break;
             }
-            pValue32 = &pProperties->reverbDelay;
+            pValue32 = (int32_t *)&pProperties->reverbDelay;
             /* FALL THROUGH */
 
         case REVERB_PARAM_REVERB_DELAY:
diff --git a/media/libeffects/testlibs/EffectReverb.h b/media/libeffects/testlibs/EffectReverb.h
index 8e2cc31..5137074 100644
--- a/media/libeffects/testlibs/EffectReverb.h
+++ b/media/libeffects/testlibs/EffectReverb.h
@@ -329,7 +329,8 @@
 */
 
 int Reverb_Init(reverb_module_t *pRvbModule, int aux, int preset);
-int Reverb_Configure(reverb_module_t *pRvbModule, effect_config_t *pConfig, bool init);
+int Reverb_setConfig(reverb_module_t *pRvbModule, effect_config_t *pConfig, bool init);
+void Reverb_getConfig(reverb_module_t *pRvbModule, effect_config_t *pConfig);
 void Reverb_Reset(reverb_object_t *pReverb, bool init);
 
 int Reverb_setParameter (reverb_object_t *pReverb, int32_t param, size_t size, void *pValue);
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index e9b8042..b2a7a35 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -78,7 +78,7 @@
 }
 
 //----------------------------------------------------------------------------
-// Visualizer_configure()
+// Visualizer_setConfig()
 //----------------------------------------------------------------------------
 // Purpose: Set input and output audio configuration.
 //
@@ -91,9 +91,9 @@
 //
 //----------------------------------------------------------------------------
 
-int Visualizer_configure(VisualizerContext *pContext, effect_config_t *pConfig)
+int Visualizer_setConfig(VisualizerContext *pContext, effect_config_t *pConfig)
 {
-    ALOGV("Visualizer_configure start");
+    ALOGV("Visualizer_setConfig start");
 
     if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
     if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
@@ -112,6 +112,26 @@
 
 
 //----------------------------------------------------------------------------
+// Visualizer_getConfig()
+//----------------------------------------------------------------------------
+// Purpose: Get input and output audio configuration.
+//
+// Inputs:
+//  pContext:   effect engine context
+//  pConfig:    pointer to effect_config_t structure holding input and output
+//      configuration parameters
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+void Visualizer_getConfig(VisualizerContext *pContext, effect_config_t *pConfig)
+{
+    memcpy(pConfig, &pContext->mConfig, sizeof(effect_config_t));
+}
+
+
+//----------------------------------------------------------------------------
 // Visualizer_init()
 //----------------------------------------------------------------------------
 // Purpose: Initialize engine with default configuration.
@@ -144,7 +164,7 @@
 
     pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX;
 
-    Visualizer_configure(pContext, &pContext->mConfig);
+    Visualizer_setConfig(pContext, &pContext->mConfig);
 
     return 0;
 }
@@ -337,14 +357,21 @@
         }
         *(int *) pReplyData = Visualizer_init(pContext);
         break;
-    case EFFECT_CMD_CONFIGURE:
+    case EFFECT_CMD_SET_CONFIG:
         if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
                 || pReplyData == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
-        *(int *) pReplyData = Visualizer_configure(pContext,
+        *(int *) pReplyData = Visualizer_setConfig(pContext,
                 (effect_config_t *) pCmdData);
         break;
+    case EFFECT_CMD_GET_CONFIG:
+        if (pReplyData == NULL ||
+            *replySize != sizeof(effect_config_t)) {
+            return -EINVAL;
+        }
+        Visualizer_getConfig(pContext, (effect_config_t *)pReplyData);
+        break;
     case EFFECT_CMD_RESET:
         Visualizer_reset(pContext);
         break;
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
index dbdfb98..f45556f 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
@@ -479,8 +479,9 @@
                 break;
 
             case NetworkLocked:
-                carrierText = makeCarierString(mPlmn,
-                        getContext().getText(R.string.lockscreen_network_locked_message));
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.lockscreen_network_locked_message),
+                        mPlmn);
                 carrierHelpTextId = R.string.lockscreen_instructions_when_pattern_disabled;
                 break;
 
@@ -489,10 +490,9 @@
                 // This depends on mPlmn containing the text "Emergency calls only" when the radio
                 // has some connectivity. Otherwise, it should be null or empty and just show
                 // "No SIM card"
-                carrierText = getContext().getText(R.string.lockscreen_missing_sim_message_short);
-                if (mLockPatternUtils.isEmergencyCallCapable()) {
-                    carrierText = makeCarierString(carrierText, mPlmn);
-                }
+                carrierText =  makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.lockscreen_missing_sim_message_short),
+                        mPlmn);
                 carrierHelpTextId = R.string.lockscreen_missing_sim_instructions_long;
                 break;
 
@@ -503,21 +503,24 @@
                 break;
 
             case SimMissingLocked:
-                carrierText = makeCarierString(mPlmn,
-                        getContext().getText(R.string.lockscreen_missing_sim_message_short));
+                carrierText =  makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.lockscreen_missing_sim_message_short),
+                        mPlmn);
                 carrierHelpTextId = R.string.lockscreen_missing_sim_instructions;
                 mEmergencyButtonEnabledBecauseSimLocked = true;
                 break;
 
             case SimLocked:
-                carrierText = makeCarierString(mPlmn,
-                        getContext().getText(R.string.lockscreen_sim_locked_message));
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.lockscreen_sim_locked_message),
+                        mPlmn);
                 mEmergencyButtonEnabledBecauseSimLocked = true;
                 break;
 
             case SimPukLocked:
-                carrierText = makeCarierString(mPlmn,
-                        getContext().getText(R.string.lockscreen_sim_puk_locked_message));
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.lockscreen_sim_puk_locked_message),
+                        mPlmn);
                 if (!mLockPatternUtils.isPukUnlockScreenEnable()) {
                     // This means we're showing the PUK unlock screen
                     mEmergencyButtonEnabledBecauseSimLocked = true;
@@ -530,6 +533,18 @@
         updateEmergencyCallButtonState(mPhoneState);
     }
 
+
+    /*
+     * Add emergencyCallMessage to carrier string only if phone supports emergency calls.
+     */
+    private CharSequence makeCarrierStringOnEmergencyCapable(
+            CharSequence simMessage, CharSequence emergencyCallMessage) {
+        if (mLockPatternUtils.isEmergencyCallCapable()) {
+            return makeCarierString(simMessage, emergencyCallMessage);
+        }
+        return simMessage;
+    }
+
     private View findViewById(int id) {
         return mContainer.findViewById(id);
     }
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 849898c..2090f1b 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -6375,7 +6375,7 @@
     status_t cmdStatus;
     uint32_t size = sizeof(int);
     status_t status = (*mEffectInterface)->command(mEffectInterface,
-                                                   EFFECT_CMD_CONFIGURE,
+                                                   EFFECT_CMD_SET_CONFIG,
                                                    sizeof(effect_config_t),
                                                    &mConfig,
                                                    &size,
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index f5fdee7..89f7b65 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -1017,6 +1017,7 @@
     }
 }
 
+#if 0
 // 2 tracks is also a common case
 // NEVER used in current implementation of process__validate()
 // only use if the 2 tracks have the same output buffer
@@ -1114,6 +1115,7 @@
         delete [] buff;
     }
 }
+#endif
 
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 39af103..70464fce 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -114,11 +114,6 @@
         NEEDS_AUX_ENABLED      = 0x00010000,
     };
 
-    static inline int32_t applyVolume(int32_t in, int32_t v) {
-        return in * v;
-    }
-
-
     struct state_t;
     struct track_t;
 
@@ -198,7 +193,9 @@
     static void process__genericNoResampling(state_t* state);
     static void process__genericResampling(state_t* state);
     static void process__OneTrack16BitsStereoNoResampling(state_t* state);
+#if 0
     static void process__TwoTracks16BitsStereoNoResampling(state_t* state);
+#endif
 };
 
 // ----------------------------------------------------------------------------