Merge change I143ea844 into eclair

* changes:
  Add BMW and Audi to Auto Pairing black list.
diff --git a/api/current.xml b/api/current.xml
index 32d0f1e..d6af516 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -35279,6 +35279,17 @@
  visibility="public"
 >
 </field>
+<field name="ACTION_LOCALE_CHANGED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.LOCALE_CHANGED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ACTION_MAIN"
  type="java.lang.String"
  transient="false"
@@ -36125,6 +36136,17 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_CHANGED_COMPONENT_NAME_LIST"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.extra.changed_component_name_list&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="EXTRA_DATA_REMOVED"
  type="java.lang.String"
  transient="false"
diff --git a/core/java/android/content/AbstractSyncableContentProvider.java b/core/java/android/content/AbstractSyncableContentProvider.java
index fbe3548..3716274 100644
--- a/core/java/android/content/AbstractSyncableContentProvider.java
+++ b/core/java/android/content/AbstractSyncableContentProvider.java
@@ -135,8 +135,10 @@
         public void onCreate(SQLiteDatabase db) {
             bootstrapDatabase(db);
             mSyncState.createDatabase(db);
-            ContentResolver.requestSync(null /* all accounts */,
+            if (!isTemporary()) {
+		ContentResolver.requestSync(null /* all accounts */,
                     mContentUri.getAuthority(), new Bundle());
+	    }
         }
 
         @Override
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index b785dbf..398f211 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1275,12 +1275,15 @@
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
     /**
-     * Broadcast Action: An existing application package has been changed (e.g. a component has been
-     * enabled or disabled.  The data contains the name of the package.
+     * Broadcast Action: An existing application package has been changed (e.g.
+     * a component has been enabled or disabled).  The data contains the name of
+     * the package.
      * <ul>
      * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
-     * <li> {@link #EXTRA_CHANGED_COMPONENT_NAME} containing the class name of the changed component.
-     * <li> {@link #EXTRA_DONT_KILL_APP} containing boolean field to override the default action of restarting the application.
+     * <li> {@link #EXTRA_CHANGED_COMPONENT_NAME_LIST} containing the class name
+     * of the changed components.
+     * <li> {@link #EXTRA_DONT_KILL_APP} containing boolean field to override the
+     * default action of restarting the application.
      * </ul>
      * 
      * <p class="note">This is a protected intent that can only be sent
@@ -1344,6 +1347,12 @@
      * can not be restarted will need to watch for this action and handle it
      * appropriately.
      * 
+     * <p class="note">
+     * You can <em>not</em> receive this through components declared
+     * in manifests, only by explicitly registering for it with
+     * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
+     * Context.registerReceiver()}.
+     * 
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      *
@@ -1352,6 +1361,14 @@
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
     /**
+     * Broadcast Action: The current device's locale has changed.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_LOCALE_CHANGED = "android.intent.action.LOCALE_CHANGED";
+    /**
      * Broadcast Action:  This is a <em>sticky broadcast</em> containing the
      * charging state, level, and other information about the battery.
      * See {@link android.os.BatteryManager} for documentation on the
@@ -2087,14 +2104,20 @@
             "android.intent.extra.remote_intent_token";
 
     /**
-     * Used as an int extra field in {@link android.content.Intent#ACTION_PACKAGE_CHANGED}
-     * intent to supply the name of the component that changed.
-     *
+     * @Deprecated See {@link #EXTRA_CHANGED_COMPONENT_NAME_LIST}; this field
+     * will contain only the first name in the list.
      */
     public static final String EXTRA_CHANGED_COMPONENT_NAME =
             "android.intent.extra.changed_component_name";
 
     /**
+     * This field is part of {@link android.content.Intent#ACTION_PACKAGE_CHANGED}
+     * and contains a string array of all of the components that have changed.
+     */
+    public static final String EXTRA_CHANGED_COMPONENT_NAME_LIST =
+            "android.intent.extra.changed_component_name_list";
+
+    /**
      * @hide
      * Magic extra system code can use when binding, to give a label for
      * who it is that has bound to a service.  This is an integer giving
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 87da55f..b94bb51 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -309,15 +309,22 @@
 
     public void dump(Printer pw, String prefix) {
         super.dumpFront(pw, prefix);
-        pw.println(prefix + "permission=" + permission);
+        if (permission != null) {
+            pw.println(prefix + "permission=" + permission);
+        }
         pw.println(prefix + "taskAffinity=" + taskAffinity
                 + " targetActivity=" + targetActivity);
-        pw.println(prefix + "launchMode=" + launchMode
-                + " flags=0x" + Integer.toHexString(flags)
-                + " theme=0x" + Integer.toHexString(theme));
-        pw.println(prefix + "screenOrientation=" + screenOrientation
-                + " configChanges=0x" + Integer.toHexString(configChanges)
-                + " softInputMode=0x" + Integer.toHexString(softInputMode));
+        if (launchMode != 0 || flags != 0 || theme != 0) {
+            pw.println(prefix + "launchMode=" + launchMode
+                    + " flags=0x" + Integer.toHexString(flags)
+                    + " theme=0x" + Integer.toHexString(theme));
+        }
+        if (screenOrientation != SCREEN_ORIENTATION_UNSPECIFIED
+                || configChanges != 0 || softInputMode != 0) {
+            pw.println(prefix + "screenOrientation=" + screenOrientation
+                    + " configChanges=0x" + Integer.toHexString(configChanges)
+                    + " softInputMode=0x" + Integer.toHexString(softInputMode));
+        }
         super.dumpBack(pw, prefix);
     }
     
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 7a65af8..1800c30 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -270,21 +270,31 @@
 
     public void dump(Printer pw, String prefix) {
         super.dumpFront(pw, prefix);
-        pw.println(prefix + "className=" + className);
-        pw.println(prefix + "permission=" + permission
-                + " uid=" + uid);
-        pw.println(prefix + "taskAffinity=" + taskAffinity);
-        pw.println(prefix + "theme=0x" + Integer.toHexString(theme));
+        if (className != null) {
+            pw.println(prefix + "className=" + className);
+        }
+        if (permission != null) {
+            pw.println(prefix + "permission=" + permission);
+        }
+        pw.println(prefix + "uid=" + uid + " taskAffinity=" + taskAffinity);
+        if (theme != 0) {
+            pw.println(prefix + "theme=0x" + Integer.toHexString(theme));
+        }
         pw.println(prefix + "flags=0x" + Integer.toHexString(flags)
                 + " processName=" + processName);
         pw.println(prefix + "sourceDir=" + sourceDir);
         pw.println(prefix + "publicSourceDir=" + publicSourceDir);
-        pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles);
         pw.println(prefix + "dataDir=" + dataDir);
-        pw.println(prefix + "targetSdkVersion=" + targetSdkVersion);
-        pw.println(prefix + "enabled=" + enabled);
-        pw.println(prefix + "manageSpaceActivityName="+manageSpaceActivityName);
-        pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes));
+        if (sharedLibraryFiles != null) {
+            pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles);
+        }
+        pw.println(prefix + "enabled=" + enabled + " targetSdkVersion=" + targetSdkVersion);
+        if (manageSpaceActivityName != null) {
+            pw.println(prefix + "manageSpaceActivityName="+manageSpaceActivityName);
+        }
+        if (descriptionRes != 0) {
+            pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes));
+        }
         super.dumpBack(pw, prefix);
     }
     
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 46e7ca43..8043dae 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -141,11 +141,15 @@
     }
     
     protected void dumpFront(Printer pw, String prefix) {
-        pw.println(prefix + "name=" + name);
+        if (name != null) {
+            pw.println(prefix + "name=" + name);
+        }
         pw.println(prefix + "packageName=" + packageName);
-        pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes)
-                + " nonLocalizedLabel=" + nonLocalizedLabel
-                + " icon=0x" + Integer.toHexString(icon));
+        if (labelRes != 0 || nonLocalizedLabel != null || icon != 0) {
+            pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes)
+                    + " nonLocalizedLabel=" + nonLocalizedLabel
+                    + " icon=0x" + Integer.toHexString(icon));
+        }
     }
     
     protected void dumpBack(Printer pw, String prefix) {
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 7904401..c3b0f1c 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -29,6 +29,7 @@
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.RemoteException;
+import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.text.TextUtils;
 import android.util.Pair;
 import android.view.View;
@@ -37,8 +38,59 @@
 import java.io.InputStream;
 
 /**
- * The contract between the contacts provider and applications. Contains definitions
- * for the supported URIs and columns. These APIs supersede {@link Contacts}.
+ * <p>
+ * The contract between the contacts provider and applications. Contains
+ * definitions for the supported URIs and columns. These APIs supersede
+ * {@link Contacts}.
+ * </p>
+ * <h3>Overview</h3>
+ * <p>
+ * ContactsContract defines an extensible database of contact-related
+ * information. Contact information is stored in a three-tier data model:
+ * </p>
+ * <blockquote>
+ * <p>
+ * The {@link Data} table contains all kinds of personal data: phone numbers,
+ * email addresses etc. The list of data kinds that can be stored in this table
+ * is open-ended. There is a predefined set of common kinds, but any application
+ * can add its own data kinds.
+ * </p>
+ * <p>
+ * A row in the {@link RawContacts} table represents a set of Data describing a
+ * person and associated with a single account.
+ * </p>
+ * <p>
+ * A row in the {@link Contacts} table represents an aggregate of one or more
+ * RawContacts presumably describing the same person.
+ * </p>
+ * </blockquote>
+ * <p>
+ * Other tables include:
+ * </p>
+ * <blockquote>
+ * <p>
+ * {@link Groups}, which contains information about raw contact groups - the
+ * current API does not support the notion of groups spanning multiple accounts.
+ * </p>
+ * <p>
+ * {@link StatusUpdates}, which contains social status updates including IM
+ * availability.
+ * </p>
+ * <p>
+ * {@link AggregationExceptions}, which is used for manual aggregation and
+ * disaggregation of raw contacts
+ * </p>
+ * <p>
+ * {@link Settings}, which contains visibility and sync settings for accounts
+ * and groups.
+ * </p>
+ * <p>
+ * {@link SyncState}, which contains free-form data maintained on behalf of sync
+ * adapters
+ * </p>
+ * <p>
+ * {@link PhoneLookup}, which is used for quick caller-ID lookup</id>
+ * </blockquote>
  */
 @SuppressWarnings("unused")
 public final class ContactsContract {
@@ -128,6 +180,9 @@
      * Generic columns for use by sync adapters. The specific functions of
      * these columns are private to the sync adapter. Other clients of the API
      * should not attempt to either read or write this column.
+     *
+     * @see RawContacts
+     * @see Groups
      */
     protected interface BaseSyncColumns {
 
@@ -144,6 +199,9 @@
     /**
      * Columns that appear when each row of a table belongs to a specific
      * account, including sync information that an account may need.
+     *
+     * @see RawContacts
+     * @see Groups
      */
     protected interface SyncColumns extends BaseSyncColumns {
         /**
@@ -181,6 +239,13 @@
         public static final String DIRTY = "dirty";
     }
 
+    /**
+     * @see Contacts
+     * @see RawContacts
+     * @see ContactsContract.Data
+     * @see PhoneLookup
+     * @see ContactsContract.Contacts.AggregationSuggestions
+     */
     protected interface ContactOptionsColumns {
         /**
          * The number of times a contact has been contacted
@@ -214,6 +279,12 @@
         public static final String SEND_TO_VOICEMAIL = "send_to_voicemail";
     }
 
+    /**
+     * @see Contacts
+     * @see ContactsContract.Data
+     * @see PhoneLookup
+     * @see ContactsContract.Contacts.AggregationSuggestions
+     */
     protected interface ContactsColumns {
         /**
          * The display name for the contact.
@@ -247,6 +318,9 @@
         public static final String LOOKUP_KEY = "lookup";
     }
 
+    /**
+     * @see Contacts
+     */
     protected interface ContactStatusColumns {
         /**
          * Contact presence status. See {@link StatusUpdates} for individual status
@@ -270,7 +344,7 @@
 
         /**
          * The package containing resources for this status: label and icon.
-         * <p>Type: NUMBER</p>
+         * <p>Type: TEXT</p>
          */
         public static final String CONTACT_STATUS_RES_PACKAGE = "contact_status_res_package";
 
@@ -291,8 +365,194 @@
     }
 
     /**
-     * Constants for the contacts table, which contains a record per group
+     * Constants for the contacts table, which contains a record per aggregate
      * of raw contacts representing the same person.
+     * <h3>Operations</h3>
+     * <dl>
+     * <dt><b>Insert</b></dt>
+     * <dd>A Contact cannot be created explicitly. When a raw contact is
+     * inserted, the provider will first try to find a Contact representing the
+     * same person. If one is found, the raw contact's
+     * {@link RawContacts#CONTACT_ID} column gets the _ID of the aggregate
+     * Contact. If no match is found, the provider automatically inserts a new
+     * Contact and puts its _ID into the {@link RawContacts#CONTACT_ID} column
+     * of the newly inserted raw contact.</dd>
+     * <dt><b>Update</b></dt>
+     * <dd>Only certain columns of Contact are modifiable:
+     * {@link #TIMES_CONTACTED}, {@link #LAST_TIME_CONTACTED}, {@link #STARRED},
+     * {@link #CUSTOM_RINGTONE}, {@link #SEND_TO_VOICEMAIL}. Changing any of
+     * these columns on the Contact also changes them on all constituent raw
+     * contacts.</dd>
+     * <dt><b>Delete</b></dt>
+     * <dd>Be careful with deleting Contacts! Deleting an aggregate contact
+     * deletes all constituent raw contacts. The corresponding sync adapters
+     * will notice the deletions of their respective raw contacts and remove
+     * them from their back end storage.</dd>
+     * <dt><b>Query</b></dt>
+     * <dd>
+     * <ul>
+     * <li>If you need to read an individual contact, consider using
+     * {@link #CONTENT_LOOKUP_URI} instead of {@link #CONTENT_URI}.</li>
+     * <li>If you need to look up a contact by the phone number, use
+     * {@link PhoneLookup#CONTENT_FILTER_URI PhoneLookup.CONTENT_FILTER_URI},
+     * which is optimized for this purpose.</li>
+     * <li>If you need to look up a contact by partial name, e.g. to produce
+     * filter-as-you-type suggestions, use the {@link #CONTENT_FILTER_URI} URI.
+     * <li>If you need to look up a contact by some data element like email
+     * address, nickname, etc, use a query against the {@link ContactsContract.Data} table.
+     * The result will contain contact ID, name etc.
+     * </ul>
+     * </dd>
+     * </dl>
+     * <h2>Columns</h2>
+     * <table class="jd-sumtable">
+     * <tr>
+     * <th colspan='4'>Contacts</th>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #_ID}</td>
+     * <td>read-only</td>
+     * <td>Row ID. Consider using {@link #LOOKUP_KEY} instead.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #LOOKUP_KEY}</td>
+     * <td>read-only</td>
+     * <td>An opaque value that contains hints on how to find the contact if its
+     * row id changed as a result of a sync or aggregation.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #DISPLAY_NAME}</td>
+     * <td>read-only</td>
+     * <td>The display name for the contact. During aggregation display name is
+     * computed from display names of constituent raw contacts using a
+     * heuristic: a longer name or a name with more diacritic marks or more
+     * upper case characters is chosen.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #PHOTO_ID}</td>
+     * <td>read-only</td>
+     * <td>Reference to the row in the {@link ContactsContract.Data} table holding the photo.
+     * That row has the mime type
+     * {@link CommonDataKinds.Photo#CONTENT_ITEM_TYPE}. The value of this field
+     * is computed automatically based on the
+     * {@link CommonDataKinds.Photo#IS_SUPER_PRIMARY} field of the data rows of
+     * that mime type.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #IN_VISIBLE_GROUP}</td>
+     * <td>read-only</td>
+     * <td>An indicator of whether this contact is supposed to be visible in the
+     * UI. "1" if the contact has at least one raw contact that belongs to a
+     * visible group; "0" otherwise.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #HAS_PHONE_NUMBER}</td>
+     * <td>read-only</td>
+     * <td>An indicator of whether this contact has at least one phone number.
+     * "1" if there is at least one phone number, "0" otherwise.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #TIMES_CONTACTED}</td>
+     * <td>read/write</td>
+     * <td>The number of times the contact has been contacted. See
+     * {@link #markAsContacted}. When raw contacts are aggregated, this field is
+     * computed automatically as the maximum number of times contacted among all
+     * constituent raw contacts. Setting this field automatically changes the
+     * corresponding field on all constituent raw contacts.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #LAST_TIME_CONTACTED}</td>
+     * <td>read/write</td>
+     * <td>The timestamp of the last time the contact was contacted. See
+     * {@link #markAsContacted}. Setting this field also automatically
+     * increments {@link #TIMES_CONTACTED}. When raw contacts are aggregated,
+     * this field is computed automatically as the latest time contacted of all
+     * constituent raw contacts. Setting this field automatically changes the
+     * corresponding field on all constituent raw contacts.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #STARRED}</td>
+     * <td>read/write</td>
+     * <td>An indicator for favorite contacts: '1' if favorite, '0' otherwise.
+     * When raw contacts are aggregated, this field is automatically computed:
+     * if any constituent raw contacts are starred, then this field is set to
+     * '1'. Setting this field automatically changes the corresponding field on
+     * all constituent raw contacts.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #CUSTOM_RINGTONE}</td>
+     * <td>read/write</td>
+     * <td>A custom ringtone associated with a contact. Typically this is the
+     * URI returned by an activity launched with the
+     * {@link android.media.RingtoneManager#ACTION_RINGTONE_PICKER} intent.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #SEND_TO_VOICEMAIL}</td>
+     * <td>read/write</td>
+     * <td>An indicator of whether calls from this contact should be forwarded
+     * directly to voice mail ('1') or not ('0'). When raw contacts are
+     * aggregated, this field is automatically computed: if <i>all</i>
+     * constituent raw contacts have SEND_TO_VOICEMAIL=1, then this field is set
+     * to '1'. Setting this field automatically changes the corresponding field
+     * on all constituent raw contacts.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #CONTACT_PRESENCE}</td>
+     * <td>read-only</td>
+     * <td>Contact IM presence status. See {@link StatusUpdates} for individual
+     * status definitions. Automatically computed as the highest presence of all
+     * constituent raw contacts. The provider may choose not to store this value
+     * in persistent storage. The expectation is that presence status will be
+     * updated on a regular basic.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #CONTACT_STATUS}</td>
+     * <td>read-only</td>
+     * <td>Contact's latest status update. Automatically computed as the latest
+     * of all constituent raw contacts' status updates.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #CONTACT_STATUS_TIMESTAMP}</td>
+     * <td>read-only</td>
+     * <td>The absolute time in milliseconds when the latest status was
+     * inserted/updated.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #CONTACT_STATUS_RES_PACKAGE}</td>
+     * <td>read-only</td>
+     * <td> The package containing resources for this status: label and icon.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #CONTACT_STATUS_LABEL}</td>
+     * <td>read-only</td>
+     * <td>The resource ID of the label describing the source of contact status,
+     * e.g. "Google Talk". This resource is scoped by the
+     * {@link #CONTACT_STATUS_RES_PACKAGE}.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #CONTACT_STATUS_ICON}</td>
+     * <td>read-only</td>
+     * <td>The resource ID of the icon for the source of contact status. This
+     * resource is scoped by the {@link #CONTACT_STATUS_RES_PACKAGE}.</td>
+     * </tr>
+     * </table>
      */
     public static class Contacts implements BaseColumns, ContactsColumns,
             ContactOptionsColumns, ContactStatusColumns {
@@ -365,7 +625,7 @@
 
         /**
          * Build a {@link #CONTENT_LOOKUP_URI} lookup {@link Uri} using the
-         * given {@link android.provider.ContactsContract.Contacts#_ID} and {@link #LOOKUP_KEY}.
+         * given {@link ContactsContract.Contacts#_ID} and {@link #LOOKUP_KEY}.
          */
         public static Uri getLookupUri(long contactId, String lookupKey) {
             return ContentUris.withAppendedId(Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI,
@@ -423,7 +683,7 @@
 
         /**
          * The content:// style URI for this table joined with useful data from
-         * {@link Data}, filtered to include only starred contacts
+         * {@link ContactsContract.Data}, filtered to include only starred contacts
          * and the most frequently contacted contacts.
          */
         public static final Uri CONTENT_STREQUENT_URI = Uri.withAppendedPath(
@@ -461,7 +721,7 @@
 
         /**
          * A sub-directory of a single contact that contains all of the constituent raw contact
-         * {@link Data} rows.
+         * {@link ContactsContract.Data} rows.
          */
         public static final class Data implements BaseColumns, DataColumns {
             /**
@@ -476,10 +736,33 @@
         }
 
         /**
-         * A sub-directory of a single contact aggregate that contains all aggregation suggestions
-         * (other contacts).  The aggregation suggestions are computed based on approximate
-         * data matches with this contact.
+         * <p>
+         * A <i>read-only</i> sub-directory of a single contact aggregate that
+         * contains all aggregation suggestions (other contacts). The
+         * aggregation suggestions are computed based on approximate data
+         * matches with this contact.
+         * </p>
+         * <p>
+         * <i>Note: this query may be expensive! If you need to use it in bulk,
+         * make sure the user experience is acceptable when the query runs for a
+         * long time.</i>
+         * <p>
+         * Usage example:
+         *
+         * <pre>
+         * Uri uri = Contacts.CONTENT_URI.buildUpon()
+         *          .appendEncodedPath(String.valueOf(contactId))
+         *          .appendPath(Contacts.AggregationSuggestions.CONTENT_DIRECTORY)
+         *          .appendQueryParameter(&quot;limit&quot;, &quot;3&quot;)
+         *          .build()
+         * Cursor cursor = getContentResolver().query(suggestionsUri,
+         *          new String[] {Contacts.DISPLAY_NAME, Contacts._ID, Contacts.LOOKUP_KEY},
+         *          null, null, null);
+         * </pre>
+         *
+         * </p>
          */
+        // TODO: add ContactOptionsColumns, ContactStatusColumns
         public static final class AggregationSuggestions implements BaseColumns, ContactsColumns {
             /**
              * No public constructor since this is a utility class
@@ -495,8 +778,40 @@
         }
 
         /**
-         * A sub-directory of a single contact that contains the contact's primary photo.
+         * A <i>read-only</i> sub-directory of a single contact that contains
+         * the contact's primary photo.
+         * <p>
+         * Usage example:
+         *
+         * <pre>
+         * public InputStream openPhoto(long contactId) {
+         *     Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
+         *     Uri photoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.CONTENT_DIRECTORY);
+         *     Cursor cursor = getContentResolver().query(photoUri,
+         *          new String[] {Contacts.Photo.PHOTO}, null, null, null);
+         *     if (cursor == null) {
+         *         return null;
+         *     }
+         *     try {
+         *         if (cursor.moveToFirst()) {
+         *             byte[] data = cursor.getBlob(0);
+         *             if (data != null) {
+         *                 return new ByteArrayInputStream(data);
+         *             }
+         *         }
+         *     } finally {
+         *         cursor.close();
+         *     }
+         *     return null;
+         * }
+         * </pre>
+         *
+         * </p>
+         * <p>You should also consider using the convenience method
+         * {@link ContactsContract.Contacts#openContactPhotoInputStream(ContentResolver, Uri)}
+         * </p>
          */
+        // TODO: change DataColumns to DataColumnsWithJoins
         public static final class Photo implements BaseColumns, DataColumns {
             /**
              * no public constructor since this is a utility class
@@ -507,6 +822,15 @@
              * The directory twig for this sub-table
              */
             public static final String CONTENT_DIRECTORY = "photo";
+
+            /**
+             * Thumbnail photo of the raw contact. This is the raw bytes of an image
+             * that could be inflated using {@link android.graphics.BitmapFactory}.
+             * <p>
+             * Type: BLOB
+             * @hide TODO: Unhide in a separate CL
+             */
+            public static final String PHOTO = DATA15;
         }
 
         /**
@@ -542,7 +866,7 @@
 
     protected interface RawContactsColumns {
         /**
-         * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} that this
+         * A reference to the {@link ContactsContract.Contacts#_ID} that this
          * data belongs to.
          * <P>Type: INTEGER</P>
          */
@@ -580,6 +904,315 @@
      * Constants for the raw contacts table, which contains the base contact
      * information per sync source. Sync adapters and contact management apps
      * are the primary consumers of this API.
+     * <h3>Operations</h3>
+     * <dl>
+     * <dt><b>Insert</b></dt>
+     * <dd>There are two mechanisms that can be used to insert a raw contact: incremental and
+     * batch. The incremental method is more traditional but less efficient.  It should be used
+     * only if the constituent data rows are unavailable at the time the raw contact is created:
+     * <pre>
+     * ContentValues values = new ContentValues();
+     * values.put(RawContacts.ACCOUNT_TYPE, accountType);
+     * values.put(RawContacts.ACCOUNT_NAME, accountName);
+     * Uri rawContactUri = getContentResolver().insert(RawContacts.CONTENT_URI, values);
+     * long rawContactId = ContentUris.parseId(rawContactUri);
+     * </pre>
+     * <p>
+     * Once data rows are available, insert those.  For example, here's how you would insert
+     * a name:
+     *
+     * <pre>
+     * values.clear();
+     * values.put(Data.RAW_CONTACT_ID, rawContactId);
+     * values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+     * values.put(StructuredName.DISPLAY_NAME, &quot;Mike Sullivan&quot;);
+     * getContentResolver().insert(Data.CONTENT_URI, values);
+     * </pre>
+     * </p>
+     * <p>
+     * The batch method is by far preferred.  It inserts the raw contact and its
+     * constituent data rows in a single database transaction
+     * and causes at most one aggregation pass.
+     * <pre>
+     * ArrayList&lt;ContentProviderOperation&gt; ops = Lists.newArrayList();
+     * int rawContactInsertIndex = ops.size();
+     * ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
+     *          .withValue(RawContacts.ACCOUNT_TYPE, accountType)
+     *          .withValue(RawContacts.ACCOUNT_NAME, accountName)
+     *          .build());
+     *
+     * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
+     *          .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
+     *          .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
+     *          .withValue(StructuredName.DISPLAY_NAME, &quot;Mike Sullivan&quot;)
+     *          .build());
+     *
+     * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
+     * </pre>
+     * </p>
+     * <p>
+     * Please note the use of back reference in the construction of the
+     * {@link ContentProviderOperation}. It allows an operation to use the result of
+     * a previous operation by referring to it by its index in the batch.
+     * </p>
+     * <dt><b>Update</b></dt>
+     * <dd><p>Just as with insert, the update can be done incrementally or as a batch, the
+     * batch mode being the preferred method.</p></dd>
+     * <dt><b>Delete</b></dt>
+     * <dd><p>When a raw contact is deleted, all of its Data rows as well as StatusUpdates,
+     * AggregationExceptions, PhoneLookup rows are deleted automatically. When all raw
+     * contacts in a Contact are deleted, the Contact itself is also deleted automatically.
+     * </p>
+     * <p>
+     * The invocation of {@code resolver.delete(...)}, does not physically delete
+     * a raw contacts row. It sets the {@link #DELETED} flag on the raw contact and
+     * removes the raw contact from its aggregate contact.
+     * The sync adapter then deletes the raw contact from the server and
+     * finalizes phone-side deletion by calling {@code resolver.delete(...)}
+     * again and passing the {@link #CALLER_IS_SYNCADAPTER} query parameter.<p>
+     * <p>Some sync adapters are read-only, meaning that they only sync server-side
+     * changes to the phone, but not the reverse.  If one of those raw contacts
+     * is marked for deletion, it will remain on the phone.  However it will be
+     * effectively invisible, because it will not be part of any aggregate contact.
+     * </dd>
+     * <dt><b>Query</b></dt>
+     * <dd>
+     * <p>
+     * Finding all raw contacts in a Contact is easy:
+     * <pre>
+     * Cursor c = getContentResolver().query(RawContacts.CONTENT_URI,
+     *          new String[]{RawContacts._ID},
+     *          RawContacts.CONTACT_ID + "=?",
+     *          new String[]{String.valueOf(contactId)}, null);
+     * </pre>
+     * </p>
+     * <p>
+     * There are two ways to find raw contacts within a specific account,
+     * you can either put the account name and type in the selection or pass them as query
+     * parameters.  The latter approach is preferable, especially when you can reuse the
+     * URI:
+     * <pre>
+     * Uri rawContactUri = RawContacts.URI.buildUpon()
+     *          .appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName)
+     *          .appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType)
+     *          .build();
+     * Cursor c1 = getContentResolver().query(rawContactUri,
+     *          RawContacts.STARRED + "&lt;&gt;0", null, null, null);
+     * ...
+     * Cursor c2 = getContentResolver().query(rawContactUri,
+     *          RawContacts.DELETED + "&lt;&gt;0", null, null, null);
+     * </pre>
+     * </p>
+     * <p>The best way to read a raw contact along with all the data associated with it is
+     * by using the {@link Entity} directory. If the raw contact has data rows,
+     * the Entity cursor will contain a row for each data row.  If the raw contact has no
+     * data rows, the cursor will still contain one row with the raw contact-level information.
+     * <pre>
+     * Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
+     * Uri entityUri = Uri.withAppendedPath(rawContactUri, Entity.CONTENT_DIRECTORY);
+     * Cursor c = getContentResolver().query(entityUri,
+     *          new String[]{RawContacts.SOURCE_ID, Entity.DATA_ID, Entity.MIMETYPE, Entity.DATA1},
+     *          null, null, null);
+     * try {
+     *     while (c.moveToNext()) {
+     *         String sourceId = c.getString(0);
+     *         if (!c.isNull(1)) {
+     *             String mimeType = c.getString(2);
+     *             String data = c.getString(3);
+     *             ...
+     *         }
+     *     }
+     * } finally {
+     *     c.close();
+     * }
+     * </pre>
+     * </p>
+     * </dd>
+     * </dl>
+     * <h3>Aggregation</h3>
+     * <p>
+     * As soon as a raw contact is inserted or whenever its constituent data
+     * changes, the provider will check if the raw contact matches other
+     * existing raw contacts and if so will aggregate it with those. From the
+     * data standpoint, aggregation is reflected in the change of the
+     * {@link #CONTACT_ID} field, which is the reference to the aggregate contact.
+     * </p>
+     * <p>
+     * See also {@link AggregationExceptions} for a mechanism to control
+     * aggregation programmatically.
+     * </p>
+     * <h2>Columns</h2>
+     * <table class="jd-sumtable">
+     * <tr>
+     * <th colspan='4'>RawContacts</th>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #_ID}</td>
+     * <td>read-only</td>
+     * <td>Row ID. Sync adapter should try to preserve row IDs during updates. In other words,
+     * it would be a really bad idea to delete and reinsert a raw contact. A sync adapter should
+     * always do an update instead.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #CONTACT_ID}</td>
+     * <td>read-only</td>
+     * <td>A reference to the {@link ContactsContract.Contacts#_ID} that this raw contact belongs
+     * to. Raw contacts are linked to contacts by the aggregation process, which can be controlled
+     * by the {@link #AGGREGATION_MODE} field and {@link AggregationExceptions}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #AGGREGATION_MODE}</td>
+     * <td>read/write</td>
+     * <td>A mechanism that allows programmatic control of the aggregation process. The allowed
+     * values are {@link #AGGREGATION_MODE_DEFAULT}, {@link #AGGREGATION_MODE_DISABLED}
+     * and {@link #AGGREGATION_MODE_SUSPENDED}. See also {@link AggregationExceptions}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #DELETED}</td>
+     * <td>read/write</td>
+     * <td>The "deleted" flag: "0" by default, "1" if the row has been marked
+     * for deletion. When {@link android.content.ContentResolver#delete} is
+     * called on a raw contact, it is marked for deletion and removed from its
+     * aggregate contact. The sync adaptor deletes the raw contact on the server and
+     * then calls ContactResolver.delete once more, this time passing the
+     * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to finalize
+     * the data removal.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #TIMES_CONTACTED}</td>
+     * <td>read/write</td>
+     * <td>The number of times the contact has been contacted. To have an effect
+     * on the corresponding value of the aggregate contact, this field
+     * should be set at the time the raw contact is inserted.
+     * See {@link ContactsContract.Contacts#markAsContacted}.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #LAST_TIME_CONTACTED}</td>
+     * <td>read/write</td>
+     * <td>The timestamp of the last time the contact was contacted. To have an effect
+     * on the corresponding value of the aggregate contact, this field
+     * should be set at the time the raw contact is inserted.
+     * See {@link ContactsContract.Contacts#markAsContacted}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #STARRED}</td>
+     * <td>read/write</td>
+     * <td>An indicator for favorite contacts: '1' if favorite, '0' otherwise.
+     * Changing this field immediately effects the corresponding aggregate contact:
+     * if any raw contacts in that aggregate contact are starred, then the contact
+     * itself is marked as starred.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #CUSTOM_RINGTONE}</td>
+     * <td>read/write</td>
+     * <td>A custom ringtone associated with a raw contact. Typically this is the
+     * URI returned by an activity launched with the
+     * {@link android.media.RingtoneManager#ACTION_RINGTONE_PICKER} intent.
+     * To have an effect on the corresponding value of the aggregate contact, this field
+     * should be set at the time the raw contact is inserted. To set a custom
+     * ringtone on a contact, use the field {@link ContactsContract.Contacts#CUSTOM_RINGTONE}
+     * instead.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #SEND_TO_VOICEMAIL}</td>
+     * <td>read/write</td>
+     * <td>An indicator of whether calls from this raw contact should be forwarded
+     * directly to voice mail ('1') or not ('0'). To have an effect
+     * on the corresponding value of the aggregate contact, this field
+     * should be set at the time the raw contact is inserted.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #ACCOUNT_NAME}</td>
+     * <td>read/write-once</td>
+     * <td>The name of the account instance to which this row belongs, which when paired with
+     * {@link #ACCOUNT_TYPE} identifies a specific account. It should be set at the time
+     * the raw contact is inserted and never changed afterwards.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #ACCOUNT_TYPE}</td>
+     * <td>read/write-once</td>
+     * <td>The type of account to which this row belongs, which when paired with
+     * {@link #ACCOUNT_NAME} identifies a specific account. It should be set at the time
+     * the raw contact is inserted and never changed afterwards.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #SOURCE_ID}</td>
+     * <td>read/write</td>
+     * <td>String that uniquely identifies this row to its source account.
+     * Typically it is set at the time the raw contact is inserted and never
+     * changed afterwards. The one notable exception is a new raw contact: it
+     * will have an account name and type, but no source id. This should
+     * indicated to the sync adapter that a new contact needs to be created
+     * server-side and its ID stored in the corresponding SOURCE_ID field on
+     * the phone.
+     * </td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #VERSION}</td>
+     * <td>read-only</td>
+     * <td>Version number that is updated whenever this row or its related data
+     * changes. This field can be used for optimistic locking of a raw contact.
+     * </td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #DIRTY}</td>
+     * <td>read/write</td>
+     * <td>Flag indicating that {@link #VERSION} has changed, and this row needs
+     * to be synchronized by its owning account.  The value is set to "1" automatically
+     * whenever the raw contact changes, unless the URI has the
+     * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter specified.
+     * The sync adapter should always supply this query parameter to prevent
+     * unnecessary synchronization: user changes some data on the server,
+     * the sync adapter updates the contact on the phone (without the
+     * CALLER_IS_SYNCADAPTER flag) flag, which sets the DIRTY flag,
+     * which triggers a sync to bring the changes to the server.
+     * </td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #SYNC1}</td>
+     * <td>read/write</td>
+     * <td>Generic column for use by sync adapters. Content provider
+     * stores this information on behalf of the sync adapter but does not
+     * interpret it in any way.
+     * </td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #SYNC2}</td>
+     * <td>read/write</td>
+     * <td>Generic column for use by sync adapters.
+     * </td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #SYNC3}</td>
+     * <td>read/write</td>
+     * <td>Generic column for use by sync adapters.
+     * </td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #SYNC4}</td>
+     * <td>read/write</td>
+     * <td>Generic column for use by sync adapters.
+     * </td>
+     * </tr>
+     * </table>
      */
     public static final class RawContacts implements BaseColumns, RawContactsColumns,
             ContactOptionsColumns, SyncColumns  {
@@ -613,6 +1246,7 @@
 
         /**
          * Aggregation mode: aggregate at the time the raw contact is inserted/updated.
+         * TODO: deprecate. Aggregation is now synchronous, this value is a no-op
          */
         public static final int AGGREGATION_MODE_IMMEDIATE = 1;
 
@@ -658,8 +1292,9 @@
         }
 
         /**
-         * A sub-directory of a single raw contact that contains all of their {@link Data} rows.
-         * To access this directory append {@link Data#CONTENT_DIRECTORY} to the contact URI.
+         * A sub-directory of a single raw contact that contains all of their
+         * {@link ContactsContract.Data} rows. To access this directory
+         * append {@link Data#CONTENT_DIRECTORY} to the contact URI.
          */
         public static final class Data implements BaseColumns, DataColumns {
             /**
@@ -675,8 +1310,27 @@
         }
 
         /**
-         * A sub-directory of a single raw contact that contains all of their {@link Data} rows.
-         * To access this directory append {@link Entity#CONTENT_DIRECTORY} to the contact URI.
+         * <p>
+         * A sub-directory of a single raw contact that contains all of their
+         * {@link ContactsContract.Data} rows. To access this directory append
+         * {@link Entity#CONTENT_DIRECTORY} to the contact URI. See
+         * {@link RawContactsEntity} for a stand-alone table containing the same
+         * data.
+         * </p>
+         * <p>
+         * The Entity directory is similar to the {@link RawContacts.Data}
+         * directory but with two important differences:
+         * <ul>
+         * <li>Entity has different ID fields: {@link #_ID} for the raw contact
+         * and {@link #DATA_ID} for the data rows.</li>
+         * <li>Entity always contains at least one row, even if there are no
+         * actual data rows. In this case the {@link #DATA_ID} field will be
+         * null.</li>
+         * </ul>
+         * Using Entity should preferred to using two separate queries:
+         * RawContacts followed by Data. The reason is that Entity reads all
+         * data for a raw contact in one transaction, so there is no possibility
+         * of the data changing between the two queries.
          */
         public static final class Entity implements BaseColumns, DataColumns {
             /**
@@ -699,6 +1353,12 @@
         }
     }
 
+    /**
+     * Social status update columns.
+     *
+     * @see StatusUpdates
+     * @see ContactsContract.Data
+     */
     protected interface StatusColumns extends Im.CommonPresenceColumns {
         /**
          * Contact's latest presence level.
@@ -739,6 +1399,11 @@
         public static final String STATUS_ICON = "status_icon";
     }
 
+    /**
+     * Columns in the Data table.
+     *
+     * @see ContactsContract.Data
+     */
     protected interface DataColumns {
         /**
          * The package name to use when creating {@link Resources} objects for
@@ -824,7 +1489,9 @@
     }
 
     /**
-     * Combines all columns returned by {@link Data} table queries.
+     * Combines all columns returned by {@link ContactsContract.Data} table queries.
+     *
+     * @see ContactsContract.Data
      */
     protected interface DataColumnsWithJoins extends BaseColumns, DataColumns, StatusColumns,
         RawContactsColumns, ContactsColumns, ContactOptionsColumns, ContactStatusColumns {
@@ -832,10 +1499,468 @@
     }
 
     /**
-     * Constants for the data table, which contains data points tied to a raw contact.
-     * For example, a phone number or email address. Each row in this table contains a type
-     * definition and some generic columns. Each data type can define the meaning for each of
-     * the generic columns.
+     * <p>
+     * Constants for the data table, which contains data points tied to a raw
+     * contact. For example, a phone number or email address.
+     * </p>
+     * <h3>Data kinds</h3>
+     * <p>
+     * Data is a generic table that can hold all kinds of data. Sync adapters
+     * and applications can introduce their own data kinds. The kind of data
+     * stored in a particular row is determined by the mime type in the row.
+     * Fields from {@link #DATA1} through {@link #DATA15} are generic columns
+     * whose specific use is determined by the kind of data stored in the row.
+     * For example, if the data kind is
+     * {@link CommonDataKinds.Phone Phone.CONTENT_ITEM_TYPE}, then DATA1 stores the
+     * phone number, but if the data kind is
+     * {@link CommonDataKinds.Email Email.CONTENT_ITEM_TYPE}, then DATA1 stores the
+     * email address.
+     * </p>
+     * <p>
+     * ContactsContract defines a small number of common data kinds, e.g.
+     * {@link CommonDataKinds.Phone}, {@link CommonDataKinds.Email} etc. As a
+     * convenience, these classes define data kind specific aliases for DATA1 etc.
+     * For example, {@link CommonDataKinds.Phone Phone.NUMBER} is the same as
+     * {@link ContactsContract.Data Data.DATA1}.
+     * </p>
+     * <p>
+     * {@link #DATA1} is an indexed column and should be used for the data element that is
+     * expected to be most frequently used in query selections. For example, in the
+     * case of a row representing email addresses {@link #DATA1} should probably
+     * be used for the email address itself, while {@link #DATA2} etc can be
+     * used for auxiliary information like type of email address.
+     * <p>
+     * <p>
+     * By convention, {@link #DATA15} is used for storing BLOBs (binary data).
+     * </p>
+     * <p>
+     * Typically you should refrain from introducing new kinds of data for 3rd
+     * party account types. For example, if you add a data row for
+     * "favorite song" to a raw contact owned by a Google account, it will not
+     * get synced to the server, because the Google sync adapter does not know
+     * how to handle this data kind. Thus new data kinds are typically
+     * introduced along with new account types, i.e. new sync adapters.
+     * </p>
+     * <h3>Batch operations</h3>
+     * <p>
+     * Data rows can be inserted/updated/deleted using the traditional
+     * {@link ContentResolver#insert}, {@link ContentResolver#update} and
+     * {@link ContentResolver#delete} methods, however the newer mechanism based
+     * on a batch of {@link ContentProviderOperation} will prove to be a better
+     * choice in almost all cases. All operations in a batch are executed in a
+     * single transaction, which ensures that the phone-side and server-side
+     * state of a raw contact are always consistent. Also, the batch-based
+     * approach is far more efficient: not only are the database operations
+     * faster when executed in a single transaction, but also sending a batch of
+     * commands to the content provider saves a lot of time on context switching
+     * between your process and the process in which the content provider runs.
+     * </p>
+     * <p>
+     * The flip side of using batched operations is that a large batch may lock
+     * up the database for a long time preventing other applications from
+     * accessing data and potentially causing ANRs ("Application Not Responding"
+     * dialogs.)
+     * </p>
+     * <p>
+     * To avoid such lockups of the database, make sure to insert "yield points"
+     * in the batch. A yield point indicates to the content provider that before
+     * executing the next operation it can commit the changes that have already
+     * been made, yield to other requests, open another transaction and continue
+     * processing operations. A yield point will not automatically commit the
+     * transaction, but only if there is another request waiting on the
+     * database. Normally a sync adapter should insert a yield point at the
+     * beginning of each raw contact operation sequence in the batch. See
+     * {@link ContentProviderOperation.Builder#withYieldAllowed(boolean)}.
+     * </p>
+     * <h3>Operations</h3>
+     * <dl>
+     * <dt><b>Insert</b></dt>
+     * <dd>
+     * <p>
+     * An individual data row can be inserted using the traditional
+     * {@link ContentResolver#insert(Uri, ContentValues)} method. Multiple rows
+     * should always be inserted as a batch.
+     * </p>
+     * <p>
+     * An example of a traditional insert:
+     * <pre>
+     * ContentValues values = new ContentValues();
+     * values.put(Data.RAW_CONTACT_ID, rawContactId);
+     * values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+     * values.put(Phone.NUMBER, "1-800-GOOG-411");
+     * values.put(Phone.TYPE, Phone.TYPE_CUSTOM);
+     * values.put(Phone.LABEL, "free directory assistance");
+     * Uri dataUri = getContentResolver().insert(Data.CONTENT_URI, values);
+     * </pre>
+     * <p>
+     * The same done using ContentProviderOperations:
+     * <pre>
+     * ArrayList&lt;ContentProviderOperation&gt; ops = Lists.newArrayList();
+     * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
+     *          .withValue(Data.RAW_CONTACT_ID, rawContactId)
+     *          .withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
+     *          .withValue(Phone.NUMBER, "1-800-GOOG-411")
+     *          .withValue(Phone.TYPE, Phone.TYPE_CUSTOM)
+     *          .withValue(Phone.LABEL, "free directory assistance")
+     *          .build());
+     * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
+     * </pre>
+     * </p>
+     * <dt><b>Update</b></dt>
+     * <dd>
+     * <p>
+     * Just as with insert, update can be done incrementally or as a batch,
+     * the batch mode being the preferred method:
+     * <pre>
+     * ArrayList&lt;ContentProviderOperation&gt; ops = Lists.newArrayList();
+     * ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)
+     *          .withSelection(Data._ID + "=?", new String[]{String.valueOf(dataId)})
+     *          .withValue(Email.DATA, "somebody@android.com")
+     *          .build());
+     * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
+     * </pre>
+     * </p>
+     * </dd>
+     * <dt><b>Delete</b></dt>
+     * <dd>
+     * <p>
+     * Just as with insert and update, deletion can be done either using the
+     * {@link ContentResolver#delete} method or using a ContentProviderOperation:
+     * <pre>
+     * ArrayList&lt;ContentProviderOperation&gt; ops = Lists.newArrayList();
+     * ops.add(ContentProviderOperation.newDelete(Data.CONTENT_URI)
+     *          .withSelection(Data._ID + "=?", new String[]{String.valueOf(dataId)})
+     *          .build());
+     * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
+     * </pre>
+     * </p>
+     * </dd>
+     * <dt><b>Query</b></dt>
+     * <dd>
+     * <p>
+     * <dl>
+     * <dt>Finding all Data of a given type for a given contact</dt>
+     * <dd>
+     * <pre>
+     * Cursor c = getContentResolver().query(Data.CONTENT_URI,
+     *          new String[] {Data._ID, Phone.NUMBER, Phone.TYPE, Phone.LABEL},
+     *          Data.CONTACT_ID + &quot;=?&quot; + " AND "
+     *                  + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'",
+     *          new String[] {String.valueOf(contactId)}, null);
+     * </pre>
+     * </p>
+     * <p>
+     * </dd>
+     * <dt>Finding all Data of a given type for a given raw contact</dt>
+     * <dd>
+     * <pre>
+     * Cursor c = getContentResolver().query(Data.CONTENT_URI,
+     *          new String[] {Data._ID, Phone.NUMBER, Phone.TYPE, Phone.LABEL},
+     *          Data.RAW_CONTACT_ID + &quot;=?&quot; + " AND "
+     *                  + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'",
+     *          new String[] {String.valueOf(rawContactId)}, null);
+     * </pre>
+     * </dd>
+     * <dt>Finding all Data for a given raw contact</dt>
+     * <dd>
+     * Most sync adapters will want to read all data rows for a raw contact
+     * along with the raw contact itself.  For that you should use the
+     * {@link RawContactsEntity}. See also {@link RawContacts}.
+     * </dd>
+     * </dl>
+     * </p>
+     * </dd>
+     * </dl>
+     * <h2>Columns</h2>
+     * <table class="jd-sumtable">
+     * <tr>
+     * <th colspan='4'>Data</th>
+     * </tr>
+     * <tr>
+     * <td style="width: 7em;">long</td>
+     * <td style="width: 20em;">{@link #_ID}</td>
+     * <td style="width: 5em;">read-only</td>
+     * <td>Row ID. Sync adapter should try to preserve row IDs during updates. In other words,
+     * it would be a bad idea to delete and reinsert a data rows. A sync adapter should
+     * always do an update instead.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #MIMETYPE}</td>
+     * <td>read/write-once</td>
+     * <td>
+     * <p>The MIME type of the item represented by this row. Examples of common
+     * MIME types are:
+     * <ul>
+     * <li>{@link CommonDataKinds.StructuredName StructuredName.CONTENT_ITEM_TYPE}</li>
+     * <li>{@link CommonDataKinds.Phone Phone.CONTENT_ITEM_TYPE}</li>
+     * <li>{@link CommonDataKinds.Email Email.CONTENT_ITEM_TYPE}</li>
+     * <li>{@link CommonDataKinds.Photo Photo.CONTENT_ITEM_TYPE}</li>
+     * <li>{@link CommonDataKinds.Organization Organization.CONTENT_ITEM_TYPE}</li>
+     * <li>{@link CommonDataKinds.Im Im.CONTENT_ITEM_TYPE}</li>
+     * <li>{@link CommonDataKinds.Nickname Nickname.CONTENT_ITEM_TYPE}</li>
+     * <li>{@link CommonDataKinds.Note Note.CONTENT_ITEM_TYPE}</li>
+     * <li>{@link CommonDataKinds.StructuredPostal StructuredPostal.CONTENT_ITEM_TYPE}</li>
+     * <li>{@link CommonDataKinds.GroupMembership GroupMembership.CONTENT_ITEM_TYPE}</li>
+     * <li>{@link CommonDataKinds.Website Website.CONTENT_ITEM_TYPE}</li>
+     * <li>{@link CommonDataKinds.Event Event.CONTENT_ITEM_TYPE}</li>
+     * <li>{@link CommonDataKinds.Relation Relation.CONTENT_ITEM_TYPE}</li>
+     * </ul>
+     * </p>
+     * </td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #RAW_CONTACT_ID}</td>
+     * <td>read/write-once</td>
+     * <td>A reference to the {@link RawContacts#_ID} that this data belongs to.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #CONTACT_ID}</td>
+     * <td>read-only</td>
+     * <td>A reference to the {@link ContactsContract.Contacts#_ID} that this data row belongs
+     * to. It is obtained through a join with RawContacts.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #IS_PRIMARY}</td>
+     * <td>read/write</td>
+     * <td>Whether this is the primary entry of its kind for the raw contact it belongs to.
+     * "1" if true, "0" if false.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #IS_SUPER_PRIMARY}</td>
+     * <td>read/write</td>
+     * <td>Whether this is the primary entry of its kind for the aggregate
+     * contact it belongs to. Any data record that is "super primary" must
+     * also be "primary".</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #DATA_VERSION}</td>
+     * <td>read-only</td>
+     * <td>The version of this data record. Whenever the data row changes
+     * the version goes up. This value is monotonically increasing.</td>
+     * </tr>
+     * <tr>
+     * <td>Any type</td>
+     * <td>
+     * {@link #DATA1}<br>
+     * {@link #DATA2}<br>
+     * {@link #DATA3}<br>
+     * {@link #DATA4}<br>
+     * {@link #DATA5}<br>
+     * {@link #DATA6}<br>
+     * {@link #DATA7}<br>
+     * {@link #DATA8}<br>
+     * {@link #DATA9}<br>
+     * {@link #DATA10}<br>
+     * {@link #DATA11}<br>
+     * {@link #DATA12}<br>
+     * {@link #DATA13}<br>
+     * {@link #DATA14}<br>
+     * {@link #DATA15}
+     * </td>
+     * <td>read/write</td>
+     * <td>Generic data columns, the meaning is {@link #MIMETYPE} specific.</td>
+     * </tr>
+     * <tr>
+     * <td>Any type</td>
+     * <td>
+     * {@link #SYNC1}<br>
+     * {@link #SYNC2}<br>
+     * {@link #SYNC3}<br>
+     * {@link #SYNC4}
+     * </td>
+     * <td>read/write</td>
+     * <td>Generic columns for use by sync adapters. For example, a Photo row
+     * may store the image URL in SYNC1, a status (not loaded, loading, loaded, error)
+     * in SYNC2, server-side version number in SYNC3 and error code in SYNC4.</td>
+     * </tr>
+     * </table>
+     *
+     * <table class="jd-sumtable">
+     * <tr>
+     * <th colspan='4'>Join with {@link StatusUpdates}</th>
+     * </tr>
+     * <tr>
+     * <td style="width: 7em;">int</td>
+     * <td style="width: 20em;">{@link #PRESENCE}</td>
+     * <td style="width: 5em;">read-only</td>
+     * <td>IM presence status linked to this data row. Compare with
+     * {@link #CONTACT_PRESENCE}, which contains the contact's presence across
+     * all IM rows. See {@link StatusUpdates} for individual status definitions.
+     * The provider may choose not to store this value
+     * in persistent storage. The expectation is that presence status will be
+     * updated on a regular basic.
+     * </td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #STATUS}</td>
+     * <td>read-only</td>
+     * <td>Latest status update linked with this data row.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #STATUS_TIMESTAMP}</td>
+     * <td>read-only</td>
+     * <td>The absolute time in milliseconds when the latest status was
+     * inserted/updated for this data row.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #STATUS_RES_PACKAGE}</td>
+     * <td>read-only</td>
+     * <td>The package containing resources for this status: label and icon.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #STATUS_LABEL}</td>
+     * <td>read-only</td>
+     * <td>The resource ID of the label describing the source of status update linked
+     * to this data row. This resource is scoped by the {@link #STATUS_RES_PACKAGE}.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #STATUS_ICON}</td>
+     * <td>read-only</td>
+     * <td>The resource ID of the icon for the source of the status update linked
+     * to this data row. This resource is scoped by the {@link #STATUS_RES_PACKAGE}.</td>
+     * </tr>
+     * </table>
+     *
+     * <p>
+     * Columns from the associated raw contact are also available through an
+     * implicit join.
+     * </p>
+     *
+     * <table class="jd-sumtable">
+     * <tr>
+     * <th colspan='4'>Join with {@link RawContacts}</th>
+     * </tr>
+     * <tr>
+     * <td style="width: 7em;">int</td>
+     * <td style="width: 20em;">{@link #AGGREGATION_MODE}</td>
+     * <td style="width: 5em;">read-only</td>
+     * <td>See {@link RawContacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #DELETED}</td>
+     * <td>read-only</td>
+     * <td>See {@link RawContacts}.</td>
+     * </tr>
+     * </table>
+     *
+     * <p>
+     * Columns from the associated aggregated contact are also available through an
+     * implicit join.
+     * </p>
+     *
+     * <table class="jd-sumtable">
+     * <tr>
+     * <th colspan='4'>Join with {@link Contacts}</th>
+     * </tr>
+     * <tr>
+     * <td style="width: 7em;">String</td>
+     * <td style="width: 20em;">{@link #LOOKUP_KEY}</td>
+     * <td style="width: 5em;">read-only</td>
+     * <td>See {@link ContactsContract.Contacts}</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #DISPLAY_NAME}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #PHOTO_ID}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #IN_VISIBLE_GROUP}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #HAS_PHONE_NUMBER}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #TIMES_CONTACTED}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #LAST_TIME_CONTACTED}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #STARRED}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #CUSTOM_RINGTONE}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #SEND_TO_VOICEMAIL}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #CONTACT_PRESENCE}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #CONTACT_STATUS}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #CONTACT_STATUS_TIMESTAMP}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #CONTACT_STATUS_RES_PACKAGE}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #CONTACT_STATUS_LABEL}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #CONTACT_STATUS_ICON}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * </table>
      */
     public final static class Data implements DataColumnsWithJoins {
         /**
@@ -859,7 +1984,7 @@
          *
          * This flag is useful (currently) only for vCard exporter in Contacts app, which
          * needs to exclude "un-exportable" data from available data to export, while
-         * Contacts app itself has priviledge to access all data including "un-expotable"
+         * Contacts app itself has priviledge to access all data including "un-exportable"
          * ones and providers return all of them regardless of the callers' intention.
          * <P>Type: INTEGER</p>
          *
@@ -872,7 +1997,7 @@
         /**
          * Build a {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}
          * style {@link Uri} for the parent {@link android.provider.ContactsContract.Contacts}
-         * entry of the given {@link Data} entry.
+         * entry of the given {@link ContactsContract.Data} entry.
          */
         public static Uri getContactLookupUri(ContentResolver resolver, Uri dataUri) {
             final Cursor cursor = resolver.query(dataUri, new String[] {
@@ -894,8 +2019,141 @@
     }
 
     /**
-     * Constants for the raw contacts entities table, which can be though of as an outer join
-     * of the raw_contacts table with the data table.
+     * <p>
+     * Constants for the raw contacts entities table, which can be though of as
+     * an outer join of the raw_contacts table with the data table.  It is a strictly
+     * read-only table.
+     * </p>
+     * <p>
+     * If a raw contact has data rows, the RawContactsEntity cursor will contain
+     * a one row for each data row. If the raw contact has no data rows, the
+     * cursor will still contain one row with the raw contact-level information
+     * and nulls for data columns.
+     *
+     * <pre>
+     * Uri entityUri = ContentUris.withAppendedId(RawContactsEntity.CONTENT_URI, rawContactId);
+     * Cursor c = getContentResolver().query(entityUri,
+     *          new String[]{
+     *              RawContactsEntity.SOURCE_ID,
+     *              RawContactsEntity.DATA_ID,
+     *              RawContactsEntity.MIMETYPE,
+     *              RawContactsEntity.DATA1
+     *          }, null, null, null);
+     * try {
+     *     while (c.moveToNext()) {
+     *         String sourceId = c.getString(0);
+     *         if (!c.isNull(1)) {
+     *             String mimeType = c.getString(2);
+     *             String data = c.getString(3);
+     *             ...
+     *         }
+     *     }
+     * } finally {
+     *     c.close();
+     * }
+     * </pre>
+     *
+     * <h3>Columns</h3>
+     * RawContactsEntity has a combination of RawContact and Data columns.
+     *
+     * <table class="jd-sumtable">
+     * <tr>
+     * <th colspan='4'>RawContacts</th>
+     * </tr>
+     * <tr>
+     * <td style="width: 7em;">long</td>
+     * <td style="width: 20em;">{@link #_ID}</td>
+     * <td style="width: 5em;">read-only</td>
+     * <td>Raw contact row ID. See {@link RawContacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #CONTACT_ID}</td>
+     * <td>read-only</td>
+     * <td>See {@link RawContacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #AGGREGATION_MODE}</td>
+     * <td>read-only</td>
+     * <td>See {@link RawContacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #DELETED}</td>
+     * <td>read-only</td>
+     * <td>See {@link RawContacts}.</td>
+     * </tr>
+     * </table>
+     *
+     * <table class="jd-sumtable">
+     * <tr>
+     * <th colspan='4'>Data</th>
+     * </tr>
+     * <tr>
+     * <td style="width: 7em;">long</td>
+     * <td style="width: 20em;">{@link #DATA_ID}</td>
+     * <td style="width: 5em;">read-only</td>
+     * <td>Data row ID. It will be null if the raw contact has no data rows.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #MIMETYPE}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Data}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #IS_PRIMARY}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Data}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #IS_SUPER_PRIMARY}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Data}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #DATA_VERSION}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Data}.</td>
+     * </tr>
+     * <tr>
+     * <td>Any type</td>
+     * <td>
+     * {@link #DATA1}<br>
+     * {@link #DATA2}<br>
+     * {@link #DATA3}<br>
+     * {@link #DATA4}<br>
+     * {@link #DATA5}<br>
+     * {@link #DATA6}<br>
+     * {@link #DATA7}<br>
+     * {@link #DATA8}<br>
+     * {@link #DATA9}<br>
+     * {@link #DATA10}<br>
+     * {@link #DATA11}<br>
+     * {@link #DATA12}<br>
+     * {@link #DATA13}<br>
+     * {@link #DATA14}<br>
+     * {@link #DATA15}
+     * </td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Data}.</td>
+     * </tr>
+     * <tr>
+     * <td>Any type</td>
+     * <td>
+     * {@link #SYNC1}<br>
+     * {@link #SYNC2}<br>
+     * {@link #SYNC3}<br>
+     * {@link #SYNC4}
+     * </td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Data}.</td>
+     * </tr>
+     * </table>
      */
     public final static class RawContactsEntity
             implements BaseColumns, DataColumns, RawContactsColumns {
@@ -938,6 +2196,9 @@
         public static final String DATA_ID = "data_id";
     }
 
+    /**
+     * @see PhoneLookup
+     */
     protected interface PhoneLookupColumns {
         /**
          * The phone number as the user entered it.
@@ -961,7 +2222,112 @@
     /**
      * A table that represents the result of looking up a phone number, for
      * example for caller ID. To perform a lookup you must append the number you
-     * want to find to {@link #CONTENT_FILTER_URI}.
+     * want to find to {@link #CONTENT_FILTER_URI}.  This query is highly
+     * optimized.
+     * <pre>
+     * Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
+     * resolver.query(uri, new String[]{PhoneLookup.DISPLAY_NAME,...
+     * </pre>
+     *
+     * <h3>Columns</h3>
+     *
+     * <table class="jd-sumtable">
+     * <tr>
+     * <th colspan='4'>PhoneLookup</th>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #_ID}</td>
+     * <td>read-only</td>
+     * <td>Data row ID.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #NUMBER}</td>
+     * <td>read-only</td>
+     * <td>Phone number.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #TYPE}</td>
+     * <td>read-only</td>
+     * <td>Phone number type. See {@link CommonDataKinds.Phone}.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #LABEL}</td>
+     * <td>read-only</td>
+     * <td>Custom label for the phone number. See {@link CommonDataKinds.Phone}.</td>
+     * </tr>
+     * </table>
+     * <p>
+     * Columns from the Contacts table are also available through a join.
+     * </p>
+     * <table class="jd-sumtable">
+     * <tr>
+     * <th colspan='4'>Join with {@link Contacts}</th>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #LOOKUP_KEY}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #DISPLAY_NAME}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #PHOTO_ID}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #IN_VISIBLE_GROUP}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #HAS_PHONE_NUMBER}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #TIMES_CONTACTED}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #LAST_TIME_CONTACTED}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #STARRED}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #CUSTOM_RINGTONE}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #SEND_TO_VOICEMAIL}</td>
+     * <td>read-only</td>
+     * <td>See {@link ContactsContract.Contacts}.</td>
+     * </tr>
+     * </table>
      */
     public static final class PhoneLookup implements BaseColumns, PhoneLookupColumns,
             ContactsColumns, ContactOptionsColumns {
@@ -973,10 +2339,9 @@
         /**
          * The content:// style URI for this table. Append the phone number you want to lookup
          * to this URI and query it to perform a lookup. For example:
-         *
-         * {@code
-         * Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_URI, phoneNumber);
-         * }
+         * <pre>
+         * Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_URI, Uri.encode(phoneNumber));
+         * </pre>
          */
         public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(AUTHORITY_URI,
                 "phone_lookup");
@@ -985,6 +2350,8 @@
     /**
      * Additional data mixed in with {@link StatusColumns} to link
      * back to specific {@link ContactsContract.Data#_ID} entries.
+     *
+     * @see StatusUpdates
      */
     protected interface PresenceColumns {
 
@@ -995,6 +2362,7 @@
         public static final String DATA_ID = "presence_data_id";
 
         /**
+         * See {@link CommonDataKinds.Im} for a list of defined protocol constants.
          * <p>Type: NUMBER</p>
          */
         public static final String PROTOCOL = "protocol";
@@ -1024,11 +2392,132 @@
     }
 
     /**
-     * A status update is linked to a {@link Data} row and captures the user's latest status
-     * update via the corresponding source, e.g. "Having lunch" via "Google Talk".
+     * <p>
+     * A status update is linked to a {@link ContactsContract.Data} row and captures
+     * the user's latest status update via the corresponding source, e.g.
+     * "Having lunch" via "Google Talk".
+     * </p>
+     * <p>
+     * There are two ways a status update can be inserted: by explicitly linking
+     * it to a Data row using {@link #DATA_ID} or indirectly linking it to a data row
+     * using a combination of {@link #PROTOCOL} (or {@link #CUSTOM_PROTOCOL}) and
+     * {@link #IM_HANDLE}.  There is no difference between insert and update, you can use
+     * either.
+     * </p>
+     * <p>
+     * You cannot use {@link ContentResolver#update} to change a status, but
+     * {@link ContentResolver#insert} will replace the latests status if it already
+     * exists.
+     * </p>
+     * <p>
+     * Use {@link ContentResolver#bulkInsert(Uri, ContentValues[])} to insert/update statuses
+     * for multiple contacts at once.
+     * </p>
+     *
+     * <h3>Columns</h3>
+     * <table class="jd-sumtable">
+     * <tr>
+     * <th colspan='4'>StatusUpdates</th>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #DATA_ID}</td>
+     * <td>read/write</td>
+     * <td>Reference to the {@link Data#_ID} entry that owns this presence. If this
+     * field is <i>not</i> specified, the provider will attempt to find a data row
+     * that matches the {@link #PROTOCOL} (or {@link #CUSTOM_PROTOCOL}) and
+     * {@link #IM_HANDLE} columns.
+     * </td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #PROTOCOL}</td>
+     * <td>read/write</td>
+     * <td>See {@link CommonDataKinds.Im} for a list of defined protocol constants.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #CUSTOM_PROTOCOL}</td>
+     * <td>read/write</td>
+     * <td>Name of the custom protocol.  Should be supplied along with the {@link #PROTOCOL} value
+     * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}.  Should be null or
+     * omitted if {@link #PROTOCOL} value is not
+     * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #IM_HANDLE}</td>
+     * <td>read/write</td>
+     * <td> The IM handle the presence item is for. The handle is scoped to
+     * {@link #PROTOCOL}.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #IM_ACCOUNT}</td>
+     * <td>read/write</td>
+     * <td>The IM account for the local user that the presence data came from.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #PRESENCE}</td>
+     * <td>read/write</td>
+     * <td>Contact IM presence status. The allowed values are:
+     * <p>
+     * <ul>
+     * <li>{@link #OFFLINE}</li>
+     * <li>{@link #INVISIBLE}</li>
+     * <li>{@link #AWAY}</li>
+     * <li>{@link #IDLE}</li>
+     * <li>{@link #DO_NOT_DISTURB}</li>
+     * <li>{@link #AVAILABLE}</li>
+     * </ul>
+     * </p>
+     * <p>
+     * Since presence status is inherently volatile, the content provider
+     * may choose not to store this field in long-term storage.
+     * </p>
+     * </td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #STATUS}</td>
+     * <td>read/write</td>
+     * <td>Contact's latest status update, e.g. "having toast for breakfast"</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #STATUS_TIMESTAMP}</td>
+     * <td>read/write</td>
+     * <td>The absolute time in milliseconds when the status was
+     * entered by the user. If this value is not provided, the provider will follow
+     * this logic: if there was no prior status update, the value will be left as null.
+     * If there was a prior status update, the provider will default this field
+     * to the current time.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #STATUS_RES_PACKAGE}</td>
+     * <td>read/write</td>
+     * <td> The package containing resources for this status: label and icon.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #STATUS_LABEL}</td>
+     * <td>read/write</td>
+     * <td>The resource ID of the label describing the source of contact status,
+     * e.g. "Google Talk". This resource is scoped by the
+     * {@link #STATUS_RES_PACKAGE}.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #STATUS_ICON}</td>
+     * <td>read/write</td>
+     * <td>The resource ID of the icon for the source of contact status. This
+     * resource is scoped by the {@link #STATUS_RES_PACKAGE}.</td>
+     * </tr>
+     * </table>
      */
-    // TODO make final as soon as Presence is removed
-    public static /*final*/ class StatusUpdates implements StatusColumns, PresenceColumns {
+    public static class StatusUpdates implements StatusColumns, PresenceColumns {
 
         /**
          * This utility class cannot be instantiated
@@ -1088,13 +2577,17 @@
         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/status-update";
     }
 
+    /**
+     * @deprecated This old name was never meant to be made public. Do not use.
+     */
     @Deprecated
     public static final class Presence extends StatusUpdates {
 
     }
 
     /**
-     * Container for definitions of common data types stored in the {@link Data} table.
+     * Container for definitions of common data types stored in the {@link ContactsContract.Data}
+     * table.
      */
     public static final class CommonDataKinds {
         /**
@@ -1144,7 +2637,69 @@
         }
 
         /**
-         * Parts of the name.
+         * A data kind representing the contact's proper name. You can use all
+         * columns defined for {@link ContactsContract.Data} as well as the following aliases.
+         *
+         * <h2>Column aliases</h2>
+         * <table class="jd-sumtable">
+         * <tr>
+         * <th>Type</th><th>Alias</th><th colspan='2'>Data column</th>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #DISPLAY_NAME}</td>
+         * <td>{@link #DATA1}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #GIVEN_NAME}</td>
+         * <td>{@link #DATA2}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #FAMILY_NAME}</td>
+         * <td>{@link #DATA3}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #PREFIX}</td>
+         * <td>{@link #DATA4}</td>
+         * <td>Common prefixes in English names are "Mr", "Ms", "Dr" etc.</td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #MIDDLE_NAME}</td>
+         * <td>{@link #DATA5}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #SUFFIX}</td>
+         * <td>{@link #DATA6}</td>
+         * <td>Common suffixes in English names are "Sr", "Jr", "III" etc.</td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #PHONETIC_GIVEN_NAME}</td>
+         * <td>{@link #DATA7}</td>
+         * <td>Used for phonetic spelling of the name, e.g. Pinyin, Katakana, Hiragana</td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #PHONETIC_MIDDLE_NAME}</td>
+         * <td>{@link #DATA8}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #PHONETIC_FAMILY_NAME}</td>
+         * <td>{@link #DATA9}</td>
+         * <td></td>
+         * </tr>
+         * </table>
          */
         public static final class StructuredName implements DataColumnsWithJoins {
             /**
@@ -1213,7 +2768,68 @@
         }
 
         /**
-         * A nickname.
+         * <p>A data kind representing the contact's nickname. For example, for
+         * Bob Parr ("Mr. Incredible"):
+         * <pre>
+         * ArrayList&lt;ContentProviderOperation&gt; ops = Lists.newArrayList();
+         * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
+         *          .withValue(Data.RAW_CONTACT_ID, rawContactId)
+         *          .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
+         *          .withValue(StructuredName.DISPLAY_NAME, &quot;Bob Parr&quot;)
+         *          .build());
+         *
+         * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
+         *          .withValue(Data.RAW_CONTACT_ID, rawContactId)
+         *          .withValue(Data.MIMETYPE, Nickname.CONTENT_ITEM_TYPE)
+         *          .withValue(Nickname.NAME, "Mr. Incredible")
+         *          .withValue(Nickname.TYPE, Nickname.TYPE_CUSTOM)
+         *          .withValue(Nickname.LABEL, "Superhero")
+         *          .build());
+         *
+         * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
+         * </pre>
+         * </p>
+         * <p>
+         * You can use all columns defined for {@link ContactsContract.Data} as well as the
+         * following aliases.
+         * </p>
+         *
+         * <h2>Column aliases</h2>
+         * <table class="jd-sumtable">
+         * <tr>
+         * <th>Type</th><th>Alias</th><th colspan='2'>Data column</th>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #NAME}</td>
+         * <td>{@link #DATA1}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>int</td>
+         * <td>{@link #TYPE}</td>
+         * <td>{@link #DATA2}</td>
+         * <td>
+         * Allowed values are:
+         * <p>
+         * <ul>
+         * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
+         * <li>{@link #TYPE_DEFAULT}</li>
+         * <li>{@link #TYPE_OTHER_NAME}</li>
+         * <li>{@link #TYPE_MAINDEN_NAME}</li>
+         * <li>{@link #TYPE_SHORT_NAME}</li>
+         * <li>{@link #TYPE_INITIALS}</li>
+         * </ul>
+         * </p>
+         * </td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #LABEL}</td>
+         * <td>{@link #DATA3}</td>
+         * <td></td>
+         * </tr>
+         * </table>
          */
         public static final class Nickname implements DataColumnsWithJoins, CommonColumns {
             /**
@@ -1237,7 +2853,64 @@
         }
 
         /**
-         * Common data definition for telephone numbers.
+         * <p>
+         * A data kind representing a telephone number.
+         * </p>
+         * <p>
+         * You can use all columns defined for {@link ContactsContract.Data} as
+         * well as the following aliases.
+         * </p>
+         * <h2>Column aliases</h2>
+         * <table class="jd-sumtable">
+         * <tr>
+         * <th>Type</th>
+         * <th>Alias</th><th colspan='2'>Data column</th>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #NUMBER}</td>
+         * <td>{@link #DATA1}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>int</td>
+         * <td>{@link #TYPE}</td>
+         * <td>{@link #DATA2}</td>
+         * <td>Allowed values are:
+         * <p>
+         * <ul>
+         * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
+         * <li>{@link #TYPE_HOME}</li>
+         * <li>{@link #TYPE_MOBILE}</li>
+         * <li>{@link #TYPE_WORK}</li>
+         * <li>{@link #TYPE_FAX_WORK}</li>
+         * <li>{@link #TYPE_FAX_HOME}</li>
+         * <li>{@link #TYPE_PAGER}</li>
+         * <li>{@link #TYPE_OTHER}</li>
+         * <li>{@link #TYPE_CALLBACK}</li>
+         * <li>{@link #TYPE_CAR}</li>
+         * <li>{@link #TYPE_COMPANY_MAIN}</li>
+         * <li>{@link #TYPE_ISDN}</li>
+         * <li>{@link #TYPE_MAIN}</li>
+         * <li>{@link #TYPE_OTHER_FAX}</li>
+         * <li>{@link #TYPE_RADIO}</li>
+         * <li>{@link #TYPE_TELEX}</li>
+         * <li>{@link #TYPE_TTY_TDD}</li>
+         * <li>{@link #TYPE_WORK_MOBILE}</li>
+         * <li>{@link #TYPE_WORK_PAGER}</li>
+         * <li>{@link #TYPE_ASSISTANT}</li>
+         * <li>{@link #TYPE_MMS}</li>
+         * </ul>
+         * </p>
+         * </td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #LABEL}</td>
+         * <td>{@link #DATA3}</td>
+         * <td></td>
+         * </tr>
+         * </table>
          */
         public static final class Phone implements DataColumnsWithJoins, CommonColumns {
             /**
@@ -1365,7 +3038,48 @@
         }
 
         /**
-         * Common data definition for email addresses.
+         * <p>
+         * A data kind representing an email address.
+         * </p>
+         * <p>
+         * You can use all columns defined for {@link ContactsContract.Data} as
+         * well as the following aliases.
+         * </p>
+         * <h2>Column aliases</h2>
+         * <table class="jd-sumtable">
+         * <tr>
+         * <th>Type</th>
+         * <th>Alias</th><th colspan='2'>Data column</th>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #DATA}</td>
+         * <td>{@link #DATA1}</td>
+         * <td>Email address itself.</td>
+         * </tr>
+         * <tr>
+         * <td>int</td>
+         * <td>{@link #TYPE}</td>
+         * <td>{@link #DATA2}</td>
+         * <td>Allowed values are:
+         * <p>
+         * <ul>
+         * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
+         * <li>{@link #TYPE_HOME}</li>
+         * <li>{@link #TYPE_WORK}</li>
+         * <li>{@link #TYPE_OTHER}</li>
+         * <li>{@link #TYPE_MOBILE}</li>
+         * </ul>
+         * </p>
+         * </td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #LABEL}</td>
+         * <td>{@link #DATA3}</td>
+         * <td></td>
+         * </tr>
+         * </table>
          */
         public static final class Email implements DataColumnsWithJoins, CommonColumns {
             /**
@@ -1390,22 +3104,50 @@
                     "emails");
 
             /**
+             * <p>
              * The content:// style URL for looking up data rows by email address. The
              * lookup argument, an email address, should be passed as an additional path segment
              * after this URI.
+             * </p>
+             * <p>Example:
+             * <pre>
+             * Uri uri = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(email));
+             * Cursor c = getContentResolver().query(uri,
+             *          new String[]{Email.CONTACT_ID, Email.DISPLAY_NAME, Email.DATA},
+             *          null, null, null);
+             * </pre>
+             * </p>
              */
             public static final Uri CONTENT_LOOKUP_URI = Uri.withAppendedPath(CONTENT_URI,
                     "lookup");
 
             /**
+             * <p>
              * The content:// style URL for email lookup using a filter. The filter returns
              * records of MIME type {@link #CONTENT_ITEM_TYPE}. The filter is applied
              * to display names as well as email addresses. The filter argument should be passed
              * as an additional path segment after this URI.
+             * </p>
+             * <p>The query in the following example will return "Robert Parr (bob@incredibles.com)"
+             * as well as "Bob Parr (incredible@android.com)".
+             * <pre>
+             * Uri uri = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode("bob"));
+             * Cursor c = getContentResolver().query(uri,
+             *          new String[]{Email.DISPLAY_NAME, Email.DATA},
+             *          null, null, null);
+             * </pre>
+             * </p>
              */
             public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(CONTENT_URI,
                     "filter");
 
+            /**
+             * The email address.
+             * <P>Type: TEXT</P>
+             * @hide TODO: Unhide in a separate CL
+             */
+            public static final String ADDRESS = DATA1;
+
             public static final int TYPE_HOME = 1;
             public static final int TYPE_WORK = 2;
             public static final int TYPE_OTHER = 3;
@@ -1448,7 +3190,89 @@
         }
 
         /**
-         * Common data definition for postal addresses.
+         * <p>
+         * A data kind representing a postal addresses.
+         * </p>
+         * <p>
+         * You can use all columns defined for {@link ContactsContract.Data} as
+         * well as the following aliases.
+         * </p>
+         * <h2>Column aliases</h2>
+         * <table class="jd-sumtable">
+         * <tr>
+         * <th>Type</th>
+         * <th>Alias</th><th colspan='2'>Data column</th>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #FORMATTED_ADDRESS}</td>
+         * <td>{@link #DATA1}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>int</td>
+         * <td>{@link #TYPE}</td>
+         * <td>{@link #DATA2}</td>
+         * <td>Allowed values are:
+         * <p>
+         * <ul>
+         * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
+         * <li>{@link #TYPE_HOME}</li>
+         * <li>{@link #TYPE_WORK}</li>
+         * <li>{@link #TYPE_OTHER}</li>
+         * </ul>
+         * </p>
+         * </td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #LABEL}</td>
+         * <td>{@link #DATA3}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #STREET}</td>
+         * <td>{@link #DATA4}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #POBOX}</td>
+         * <td>{@link #DATA5}</td>
+         * <td>Post Office Box number</td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #NEIGHBORHOOD}</td>
+         * <td>{@link #DATA6}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #CITY}</td>
+         * <td>{@link #DATA7}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #REGION}</td>
+         * <td>{@link #DATA8}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #POSTCODE}</td>
+         * <td>{@link #DATA9}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #COUNTRY}</td>
+         * <td>{@link #DATA10}</td>
+         * <td></td>
+         * </tr>
+         * </table>
          */
         public static final class StructuredPostal implements DataColumnsWithJoins, CommonColumns {
             /**
@@ -1573,7 +3397,76 @@
         }
 
         /**
-         * Common data definition for IM addresses.
+         * <p>
+         * A data kind representing an IM address
+         * </p>
+         * <p>
+         * You can use all columns defined for {@link ContactsContract.Data} as
+         * well as the following aliases.
+         * </p>
+         * <h2>Column aliases</h2>
+         * <table class="jd-sumtable">
+         * <tr>
+         * <th>Type</th>
+         * <th>Alias</th><th colspan='2'>Data column</th>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #DATA}</td>
+         * <td>{@link #DATA1}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>int</td>
+         * <td>{@link #TYPE}</td>
+         * <td>{@link #DATA2}</td>
+         * <td>Allowed values are:
+         * <p>
+         * <ul>
+         * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
+         * <li>{@link #TYPE_HOME}</li>
+         * <li>{@link #TYPE_WORK}</li>
+         * <li>{@link #TYPE_OTHER}</li>
+         * </ul>
+         * </p>
+         * </td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #LABEL}</td>
+         * <td>{@link #DATA3}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #PROTOCOL}</td>
+         * <td>{@link #DATA5}</td>
+         * <td>
+         * <p>
+         * Allowed values:
+         * <ul>
+         * <li>{@link #PROTOCOL_CUSTOM}. Also provide the actual protocol name
+         * as {@link #CUSTOM_PROTOCOL}.</li>
+         * <li>{@link #PROTOCOL_AIM}</li>
+         * <li>{@link #PROTOCOL_MSN}</li>
+         * <li>{@link #PROTOCOL_YAHOO}</li>
+         * <li>{@link #PROTOCOL_SKYPE}</li>
+         * <li>{@link #PROTOCOL_QQ}</li>
+         * <li>{@link #PROTOCOL_GOOGLE_TALK}</li>
+         * <li>{@link #PROTOCOL_ICQ}</li>
+         * <li>{@link #PROTOCOL_JABBER}</li>
+         * <li>{@link #PROTOCOL_NETMEETING}</li>
+         * </ul>
+         * </p>
+         * </td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #CUSTOM_PROTOCOL}</td>
+         * <td>{@link #DATA6}</td>
+         * <td></td>
+         * </tr>
+         * </table>
          */
         public static final class Im implements DataColumnsWithJoins, CommonColumns {
             /**
@@ -1676,7 +3569,82 @@
         }
 
         /**
-         * Common data definition for organizations.
+         * <p>
+         * A data kind representing an organization.
+         * </p>
+         * <p>
+         * You can use all columns defined for {@link ContactsContract.Data} as
+         * well as the following aliases.
+         * </p>
+         * <h2>Column aliases</h2>
+         * <table class="jd-sumtable">
+         * <tr>
+         * <th>Type</th>
+         * <th>Alias</th><th colspan='2'>Data column</th>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #COMPANY}</td>
+         * <td>{@link #DATA1}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>int</td>
+         * <td>{@link #TYPE}</td>
+         * <td>{@link #DATA2}</td>
+         * <td>Allowed values are:
+         * <p>
+         * <ul>
+         * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
+         * <li>{@link #TYPE_WORK}</li>
+         * <li>{@link #TYPE_OTHER}</li>
+         * </ul>
+         * </p>
+         * </td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #LABEL}</td>
+         * <td>{@link #DATA3}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #TITLE}</td>
+         * <td>{@link #DATA4}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #DEPARTMENT}</td>
+         * <td>{@link #DATA5}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #JOB_DESCRIPTION}</td>
+         * <td>{@link #DATA6}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #SYMBOL}</td>
+         * <td>{@link #DATA7}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #PHONETIC_NAME}</td>
+         * <td>{@link #DATA8}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #OFFICE_LOCATION}</td>
+         * <td>{@link #DATA9}</td>
+         * <td></td>
+         * </tr>
+         * </table>
          */
         public static final class Organization implements DataColumnsWithJoins, CommonColumns {
             /**
@@ -1761,7 +3729,58 @@
         }
 
         /**
-         * Common data definition for relations.
+         * <p>
+         * A data kind representing a relation.
+         * </p>
+         * <p>
+         * You can use all columns defined for {@link ContactsContract.Data} as
+         * well as the following aliases.
+         * </p>
+         * <h2>Column aliases</h2>
+         * <table class="jd-sumtable">
+         * <tr>
+         * <th>Type</th>
+         * <th>Alias</th><th colspan='2'>Data column</th>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #NAME}</td>
+         * <td>{@link #DATA1}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>int</td>
+         * <td>{@link #TYPE}</td>
+         * <td>{@link #DATA2}</td>
+         * <td>Allowed values are:
+         * <p>
+         * <ul>
+         * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
+         * <li>{@link #TYPE_ASSISTANT}</li>
+         * <li>{@link #TYPE_BROTHER}</li>
+         * <li>{@link #TYPE_CHILD}</li>
+         * <li>{@link #TYPE_DOMESTIC_PARTNER}</li>
+         * <li>{@link #TYPE_FATHER}</li>
+         * <li>{@link #TYPE_FRIEND}</li>
+         * <li>{@link #TYPE_MANAGER}</li>
+         * <li>{@link #TYPE_MOTHER}</li>
+         * <li>{@link #TYPE_PARENT}</li>
+         * <li>{@link #TYPE_PARTNER}</li>
+         * <li>{@link #TYPE_REFERRED_BY}</li>
+         * <li>{@link #TYPE_RELATIVE}</li>
+         * <li>{@link #TYPE_SISTER}</li>
+         * <li>{@link #TYPE_SPOUSE}</li>
+         * </ul>
+         * </p>
+         * </td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #LABEL}</td>
+         * <td>{@link #DATA3}</td>
+         * <td></td>
+         * </tr>
+         * </table>
          */
         public static final class Relation implements DataColumnsWithJoins, CommonColumns {
             /**
@@ -1795,7 +3814,47 @@
         }
 
         /**
-         * Common data definition for events.
+         * <p>
+         * A data kind representing an event.
+         * </p>
+         * <p>
+         * You can use all columns defined for {@link ContactsContract.Data} as
+         * well as the following aliases.
+         * </p>
+         * <h2>Column aliases</h2>
+         * <table class="jd-sumtable">
+         * <tr>
+         * <th>Type</th>
+         * <th>Alias</th><th colspan='2'>Data column</th>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #START_DATE}</td>
+         * <td>{@link #DATA1}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>int</td>
+         * <td>{@link #TYPE}</td>
+         * <td>{@link #DATA2}</td>
+         * <td>Allowed values are:
+         * <p>
+         * <ul>
+         * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
+         * <li>{@link #TYPE_ANNIVERSARY}</li>
+         * <li>{@link #TYPE_OTHER}</li>
+         * <li>{@link #TYPE_BIRTHDAY}</li>
+         * </ul>
+         * </p>
+         * </td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #LABEL}</td>
+         * <td>{@link #DATA3}</td>
+         * <td></td>
+         * </tr>
+         * </table>
          */
         public static final class Event implements DataColumnsWithJoins, CommonColumns {
             /**
@@ -1835,7 +3894,33 @@
         }
 
         /**
-         * Photo of the contact.
+         * <p>
+         * A data kind representing an photo for the contact.
+         * </p>
+         * <p>
+         * Some sync adapters will choose to download photos in a separate
+         * pass. A common pattern is to use columns {@link ContactsContract.Data#SYNC1}
+         * through {@link ContactsContract.Data#SYNC4} to store temporary
+         * data, e.g. the image URL or ID, state of download, server-side version
+         * of the image.  It is allowed for the {@link #PHOTO} to be null.
+         * </p>
+         * <p>
+         * You can use all columns defined for {@link ContactsContract.Data} as
+         * well as the following aliases.
+         * </p>
+         * <h2>Column aliases</h2>
+         * <table class="jd-sumtable">
+         * <tr>
+         * <th>Type</th>
+         * <th>Alias</th><th colspan='2'>Data column</th>
+         * </tr>
+         * <tr>
+         * <td>BLOB</td>
+         * <td>{@link #PHOTO}</td>
+         * <td>{@link #DATA15}</td>
+         * <td>By convention, binary data is stored in DATA15.</td>
+         * </tr>
+         * </table>
          */
         public static final class Photo implements DataColumnsWithJoins {
             /**
@@ -1856,7 +3941,26 @@
         }
 
         /**
+         * <p>
          * Notes about the contact.
+         * </p>
+         * <p>
+         * You can use all columns defined for {@link ContactsContract.Data} as
+         * well as the following aliases.
+         * </p>
+         * <h2>Column aliases</h2>
+         * <table class="jd-sumtable">
+         * <tr>
+         * <th>Type</th>
+         * <th>Alias</th><th colspan='2'>Data column</th>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #NOTE}</td>
+         * <td>{@link #DATA1}</td>
+         * <td></td>
+         * </tr>
+         * </table>
          */
         public static final class Note implements DataColumnsWithJoins {
             /**
@@ -1875,7 +3979,43 @@
         }
 
         /**
+         * <p>
          * Group Membership.
+         * </p>
+         * <p>
+         * You can use all columns defined for {@link ContactsContract.Data} as
+         * well as the following aliases.
+         * </p>
+         * <h2>Column aliases</h2>
+         * <table class="jd-sumtable">
+         * <tr>
+         * <th>Type</th>
+         * <th>Alias</th><th colspan='2'>Data column</th>
+         * </tr>
+         * <tr>
+         * <td>long</td>
+         * <td>{@link #GROUP_ROW_ID}</td>
+         * <td>{@link #DATA1}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #GROUP_SOURCE_ID}</td>
+         * <td>none</td>
+         * <td>
+         * <p>
+         * The sourceid of the group that this group membership refers to.
+         * Exactly one of this or {@link #GROUP_ROW_ID} must be set when
+         * inserting a row.
+         * </p>
+         * <p>
+         * If this field is specified, the provider will first try to
+         * look up a group with this {@link Groups Groups.SOURCE_ID}.  If such a group
+         * is found, it will use the corresponding row id.  If the group is not
+         * found, it will create one.
+         * </td>
+         * </tr>
+         * </table>
          */
         public static final class GroupMembership implements DataColumnsWithJoins {
             /**
@@ -1903,7 +4043,51 @@
         }
 
         /**
-         * Website related to the contact.
+         * <p>
+         * A data kind representing a website related to the contact.
+         * </p>
+         * <p>
+         * You can use all columns defined for {@link ContactsContract.Data} as
+         * well as the following aliases.
+         * </p>
+         * <h2>Column aliases</h2>
+         * <table class="jd-sumtable">
+         * <tr>
+         * <th>Type</th>
+         * <th>Alias</th><th colspan='2'>Data column</th>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #URL}</td>
+         * <td>{@link #DATA1}</td>
+         * <td></td>
+         * </tr>
+         * <tr>
+         * <td>int</td>
+         * <td>{@link #TYPE}</td>
+         * <td>{@link #DATA2}</td>
+         * <td>Allowed values are:
+         * <p>
+         * <ul>
+         * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
+         * <li>{@link #TYPE_HOMEPAGE}</li>
+         * <li>{@link #TYPE_BLOG}</li>
+         * <li>{@link #TYPE_PROFILE}</li>
+         * <li>{@link #TYPE_HOME}</li>
+         * <li>{@link #TYPE_WORK}</li>
+         * <li>{@link #TYPE_FTP}</li>
+         * <li>{@link #TYPE_OTHER}</li>
+         * </ul>
+         * </p>
+         * </td>
+         * </tr>
+         * <tr>
+         * <td>String</td>
+         * <td>{@link #LABEL}</td>
+         * <td>{@link #DATA3}</td>
+         * <td></td>
+         * </tr>
+         * </table>
          */
         public static final class Website implements DataColumnsWithJoins, CommonColumns {
             /**
@@ -1930,6 +4114,9 @@
         }
     }
 
+    /**
+     * @see Groups
+     */
     protected interface GroupsColumns {
         /**
          * The display title of this group.
@@ -2000,11 +4187,11 @@
         /**
          * The "deleted" flag: "0" by default, "1" if the row has been marked
          * for deletion. When {@link android.content.ContentResolver#delete} is
-         * called on a raw contact, it is marked for deletion and removed from its
-         * aggregate contact. The sync adaptor deletes the raw contact on the server and
-         * then calls ContactResolver.delete once more, this time setting the the
-         * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to finalize
-         * the data removal.
+         * called on a group, it is marked for deletion. The sync adaptor
+         * deletes the group on the server and then calls ContactResolver.delete
+         * once more, this time setting the the
+         * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to
+         * finalize the data removal.
          * <P>Type: INTEGER</P>
          */
         public static final String DELETED = "deleted";
@@ -2019,7 +4206,82 @@
     }
 
     /**
-     * Constants for the groups table.
+     * Constants for the groups table. Only per-account groups are supported.
+     * <h2>Columns</h2>
+     * <table class="jd-sumtable">
+     * <tr>
+     * <th colspan='4'>Groups</th>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #_ID}</td>
+     * <td>read-only</td>
+     * <td>Row ID. Sync adapter should try to preserve row IDs during updates.
+     * In other words, it would be a really bad idea to delete and reinsert a
+     * group. A sync adapter should always do an update instead.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #TITLE}</td>
+     * <td>read/write</td>
+     * <td>The display title of this group.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #NOTES}</td>
+     * <td>read/write</td>
+     * <td>Notes about the group.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #SYSTEM_ID}</td>
+     * <td>read/write</td>
+     * <td>The ID of this group if it is a System Group, i.e. a group that has a
+     * special meaning to the sync adapter, null otherwise.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #SUMMARY_COUNT}</td>
+     * <td>read-only</td>
+     * <td>The total number of {@link Contacts} that have
+     * {@link CommonDataKinds.GroupMembership} in this group. Read-only value
+     * that is only present when querying {@link Groups#CONTENT_SUMMARY_URI}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #SUMMARY_WITH_PHONES}</td>
+     * <td>read-only</td>
+     * <td>The total number of {@link Contacts} that have both
+     * {@link CommonDataKinds.GroupMembership} in this group, and also have
+     * phone numbers. Read-only value that is only present when querying
+     * {@link Groups#CONTENT_SUMMARY_URI}.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #GROUP_VISIBLE}</td>
+     * <td>read-only</td>
+     * <td>Flag indicating if the contacts belonging to this group should be
+     * visible in any user interface. Allowed values: 0 and 1.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #DELETED}</td>
+     * <td>read/write</td>
+     * <td>The "deleted" flag: "0" by default, "1" if the row has been marked
+     * for deletion. When {@link android.content.ContentResolver#delete} is
+     * called on a group, it is marked for deletion. The sync adaptor deletes
+     * the group on the server and then calls ContactResolver.delete once more,
+     * this time setting the the {@link ContactsContract#CALLER_IS_SYNCADAPTER}
+     * query parameter to finalize the data removal.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #SHOULD_SYNC}</td>
+     * <td>read/write</td>
+     * <td>Whether this group should be synced if the SYNC_EVERYTHING settings
+     * is false for this group's account.</td>
+     * </tr>
+     * </table>
      */
     public static final class Groups implements BaseColumns, GroupsColumns, SyncColumns {
         /**
@@ -2035,7 +4297,7 @@
 
         /**
          * The content:// style URI for this table joined with details data from
-         * {@link Data}.
+         * {@link ContactsContract.Data}.
          */
         public static final Uri CONTENT_SUMMARY_URI = Uri.withAppendedPath(AUTHORITY_URI,
                 "groups_summary");
@@ -2052,9 +4314,39 @@
     }
 
     /**
+     * <p>
      * Constants for the contact aggregation exceptions table, which contains
-     * aggregation rules overriding those used by automatic aggregation.  This type only
-     * supports query and update. Neither insert nor delete are supported.
+     * aggregation rules overriding those used by automatic aggregation. This
+     * type only supports query and update. Neither insert nor delete are
+     * supported.
+     * </p>
+     * <h2>Columns</h2>
+     * <table class="jd-sumtable">
+     * <tr>
+     * <th colspan='4'>AggregationExceptions</th>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #TYPE}</td>
+     * <td>read/write</td>
+     * <td>The type of exception: {@link #TYPE_KEEP_TOGETHER},
+     * {@link #TYPE_KEEP_SEPARATE} or {@link #TYPE_AUTOMATIC}.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #RAW_CONTACT_ID1}</td>
+     * <td>read/write</td>
+     * <td>A reference to the {@link RawContacts#_ID} of the raw contact that
+     * the rule applies to.</td>
+     * </tr>
+     * <tr>
+     * <td>long</td>
+     * <td>{@link #RAW_CONTACT_ID2}</td>
+     * <td>read/write</td>
+     * <td>A reference to the other {@link RawContacts#_ID} of the raw contact
+     * that the rule applies to.</td>
+     * </tr>
+     * </table>
      */
     public static final class AggregationExceptions implements BaseColumns {
         /**
@@ -2117,6 +4409,9 @@
         public static final String RAW_CONTACT_ID2 = "raw_contact_id2";
     }
 
+    /**
+     * @see Settings
+     */
     protected interface SettingsColumns {
         /**
          * The name of the account instance to which this row belongs.
@@ -2172,8 +4467,68 @@
     }
 
     /**
-     * Contacts-specific settings for various {@link Account}.
+     * <p>
+     * Contacts-specific settings for various {@link Account}'s.
+     * </p>
+     * <h2>Columns</h2>
+     * <table class="jd-sumtable">
+     * <tr>
+     * <th colspan='4'>Settings</th>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #ACCOUNT_NAME}</td>
+     * <td>read/write-once</td>
+     * <td>The name of the account instance to which this row belongs.</td>
+     * </tr>
+     * <tr>
+     * <td>String</td>
+     * <td>{@link #ACCOUNT_TYPE}</td>
+     * <td>read/write-once</td>
+     * <td>The type of account to which this row belongs, which when paired with
+     * {@link #ACCOUNT_NAME} identifies a specific account.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #SHOULD_SYNC}</td>
+     * <td>read/write</td>
+     * <td>Depending on the mode defined by the sync-adapter, this flag controls
+     * the top-level sync behavior for this data source.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #UNGROUPED_VISIBLE}</td>
+     * <td>read/write</td>
+     * <td>Flag indicating if contacts without any
+     * {@link CommonDataKinds.GroupMembership} entries should be visible in any
+     * user interface.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #ANY_UNSYNCED}</td>
+     * <td>read-only</td>
+     * <td>Read-only flag indicating if this {@link #SHOULD_SYNC} or any
+     * {@link Groups#SHOULD_SYNC} under this account have been marked as
+     * unsynced.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #UNGROUPED_COUNT}</td>
+     * <td>read-only</td>
+     * <td>Read-only count of {@link Contacts} from a specific source that have
+     * no {@link CommonDataKinds.GroupMembership} entries.</td>
+     * </tr>
+     * <tr>
+     * <td>int</td>
+     * <td>{@link #UNGROUPED_WITH_PHONES}</td>
+     * <td>read-only</td>
+     * <td>Read-only count of {@link Contacts} from a specific source that have
+     * no {@link CommonDataKinds.GroupMembership} entries, and also have phone
+     * numbers.</td>
+     * </tr>
+     * </table>
      */
+
     public static final class Settings implements SettingsColumns {
         /**
          * This utility class cannot be instantiated
@@ -2252,8 +4607,8 @@
         /**
          * Trigger a dialog that lists the various methods of interacting with
          * the requested {@link Contacts} entry. This may be based on available
-         * {@link Data} rows under that contact, and may also include social
-         * status and presence details.
+         * {@link ContactsContract.Data} rows under that contact, and may also
+         * include social status and presence details.
          *
          * @param context The parent {@link Context} that may be used as the
          *            parent for this dialog.
@@ -2291,8 +4646,8 @@
         /**
          * Trigger a dialog that lists the various methods of interacting with
          * the requested {@link Contacts} entry. This may be based on available
-         * {@link Data} rows under that contact, and may also include social
-         * status and presence details.
+         * {@link ContactsContract.Data} rows under that contact, and may also
+         * include social status and presence details.
          *
          * @param context The parent {@link Context} that may be used as the
          *            parent for this dialog.
@@ -2593,7 +4948,7 @@
             /**
              * The extra field for the contact phone number type.
              * <P>Type: Either an integer value from
-             * {@link android.provider.Contacts.PhonesColumns PhonesColumns},
+             * {@link CommonDataKinds.Phone},
              *  or a string specifying a custom label.</P>
              */
             public static final String PHONE_TYPE = "phone_type";
@@ -2613,7 +4968,7 @@
             /**
              * The extra field for an optional second contact phone number type.
              * <P>Type: Either an integer value from
-             * {@link android.provider.Contacts.PhonesColumns PhonesColumns},
+             * {@link CommonDataKinds.Phone},
              *  or a string specifying a custom label.</P>
              */
             public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";
@@ -2627,7 +4982,7 @@
             /**
              * The extra field for an optional third contact phone number type.
              * <P>Type: Either an integer value from
-             * {@link android.provider.Contacts.PhonesColumns PhonesColumns},
+             * {@link CommonDataKinds.Phone},
              *  or a string specifying a custom label.</P>
              */
             public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
@@ -2641,7 +4996,7 @@
             /**
              * The extra field for the contact email type.
              * <P>Type: Either an integer value from
-             * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+             * {@link CommonDataKinds.Email}
              *  or a string specifying a custom label.</P>
              */
             public static final String EMAIL_TYPE = "email_type";
@@ -2661,7 +5016,7 @@
             /**
              * The extra field for an optional second contact email type.
              * <P>Type: Either an integer value from
-             * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+             * {@link CommonDataKinds.Email}
              *  or a string specifying a custom label.</P>
              */
             public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";
@@ -2675,7 +5030,7 @@
             /**
              * The extra field for an optional third contact email type.
              * <P>Type: Either an integer value from
-             * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+             * {@link CommonDataKinds.Email}
              *  or a string specifying a custom label.</P>
              */
             public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
@@ -2689,7 +5044,7 @@
             /**
              * The extra field for the contact postal address type.
              * <P>Type: Either an integer value from
-             * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+             * {@link CommonDataKinds.StructuredPostal}
              *  or a string specifying a custom label.</P>
              */
             public static final String POSTAL_TYPE = "postal_type";
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 142dffb..691fa77 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -500,7 +500,7 @@
     private boolean mMinZoomScaleFixed = true;
 
     // initial scale in percent. 0 means using default.
-    private int mInitialScale = 0;
+    private int mInitialScaleInPercent = 0;
 
     // while in the zoom overview mode, the page's width is fully fit to the
     // current window. The page is alive, in another words, you can click to
@@ -1525,7 +1525,7 @@
         }
         nativeClearCursor(); // start next trackball movement from page edge
         if (bottom) {
-            return pinScrollTo(mScrollX, mContentHeight, true, 0);
+            return pinScrollTo(mScrollX, computeVerticalScrollRange(), true, 0);
         }
         // Page down.
         int h = getHeight();
@@ -1595,7 +1595,7 @@
      * @param scaleInPercent The initial scale in percent.
      */
     public void setInitialScale(int scaleInPercent) {
-        mInitialScale = scaleInPercent;
+        mInitialScaleInPercent = scaleInPercent;
     }
 
     /**
@@ -2730,7 +2730,7 @@
     */
     @Deprecated
     public static synchronized PluginList getPluginList() {
-        return null;
+        return new PluginList();
     }
 
    /**
@@ -3615,6 +3615,13 @@
             mMinZoomScale = Math.min(1.0f, (float) getViewWidth()
                     / (mDrawHistory ? mHistoryPicture.getWidth()
                             : mZoomOverviewWidth));
+            if (mInitialScaleInPercent > 0) {
+                // limit the minZoomScale to the initialScale if it is set
+                float initialScale = mInitialScaleInPercent / 100.0f;
+                if (mMinZoomScale > initialScale) {
+                    mMinZoomScale = initialScale;
+                }
+            }
         }
 
         // we always force, in case our height changed, in which case we still
@@ -4297,7 +4304,7 @@
 
     private int computeMaxScrollY() {
         int maxContentH = computeVerticalScrollRange() + getTitleHeight();
-        return Math.max(maxContentH - getHeight(), getTitleHeight());
+        return Math.max(maxContentH - getViewHeightWithTitle(), getTitleHeight());
     }
 
     public void flingScroll(int vx, int vy) {
@@ -4967,7 +4974,9 @@
                     WebViewCore.RestoreState restoreState = draw.mRestoreState;
                     if (restoreState != null) {
                         mInZoomOverview = false;
-                        mLastScale = restoreState.mTextWrapScale;
+                        mLastScale = mInitialScaleInPercent > 0
+                                ? mInitialScaleInPercent / 100.0f
+                                        : restoreState.mTextWrapScale;
                         if (restoreState.mMinScale == 0) {
                             if (restoreState.mMobileSite) {
                                 if (draw.mMinPrefWidth >
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index d86b674..e4cc609 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1328,7 +1328,7 @@
                     getKeyDispatcherState().startTracking(event, this);
                     return true;
                 } else if (event.getAction() == KeyEvent.ACTION_UP
-                        && event.isTracking() && !event.isCanceled()) {
+                        && getKeyDispatcherState().isTracking(event) && !event.isCanceled()) {
                     dismiss();
                     return true;
                 }
diff --git a/core/java/com/android/internal/widget/SlidingTab.java b/core/java/com/android/internal/widget/SlidingTab.java
new file mode 100644
index 0000000..dfd4f40
--- /dev/null
+++ b/core/java/com/android/internal/widget/SlidingTab.java
@@ -0,0 +1,631 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Vibrator;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.ImageView.ScaleType;
+import com.android.internal.R;
+
+/**
+ * A special widget containing two Sliders and a threshold for each.  Moving either slider beyond
+ * the threshold will cause the registered OnTriggerListener.onTrigger() to be called with
+ * {@link OnTriggerListener#LEFT_HANDLE} or {@link OnTriggerListener#RIGHT_HANDLE} to be called.
+ *
+ */
+public class SlidingTab extends ViewGroup {
+    private static final int ANIMATION_DURATION = 250; // animation transition duration (in ms)
+    private static final String LOG_TAG = "SlidingTab";
+    private static final boolean DBG = false;
+    private static final int HORIZONTAL = 0; // as defined in attrs.xml
+    private static final int VERTICAL = 1;
+    private static final int MSG_ANIMATE = 100;
+
+    // TODO: Make these configurable
+    private static final float TARGET_ZONE = 2.0f / 3.0f;
+    private static final long VIBRATE_SHORT = 30;
+    private static final long VIBRATE_LONG = 40;
+
+    private OnTriggerListener mOnTriggerListener;
+    private int mGrabbedState = OnTriggerListener.NO_HANDLE;
+    private boolean mTriggered = false;
+    private Vibrator mVibrator;
+    private float mDensity; // used to scale dimensions for bitmaps.
+
+    private final SlidingTabHandler mHandler = new SlidingTabHandler();
+
+    /**
+     * Either {@link #HORIZONTAL} or {@link #VERTICAL}.
+     */
+    private int mOrientation;
+
+    private Slider mLeftSlider;
+    private Slider mRightSlider;
+    private Slider mCurrentSlider;
+    private boolean mTracking;
+    private float mTargetZone;
+    private Slider mOtherSlider;
+    private boolean mAnimating;
+
+    /**
+     * Interface definition for a callback to be invoked when a tab is triggered
+     * by moving it beyond a target zone.
+     */
+    public interface OnTriggerListener {
+        /**
+         * The interface was triggered because the user let go of the handle without reaching the
+         * target zone.
+         */
+        public static final int NO_HANDLE = 0;
+
+        /**
+         * The interface was triggered because the user grabbed the left handle and moved it past
+         * the target zone.
+         */
+        public static final int LEFT_HANDLE = 1;
+
+        /**
+         * The interface was triggered because the user grabbed the right handle and moved it past
+         * the target zone.
+         */
+        public static final int RIGHT_HANDLE = 2;
+
+        /**
+         * Called when the user moves a handle beyond the target zone.
+         *
+         * @param v The view that was triggered.
+         * @param whichHandle  Which "dial handle" the user grabbed,
+         *        either {@link #LEFT_HANDLE}, {@link #RIGHT_HANDLE}.
+         */
+        void onTrigger(View v, int whichHandle);
+
+        /**
+         * Called when the "grabbed state" changes (i.e. when the user either grabs or releases
+         * one of the handles.)
+         *
+         * @param v the view that was triggered
+         * @param grabbedState the new state: {@link #NO_HANDLE}, {@link #LEFT_HANDLE},
+         * or {@link #RIGHT_HANDLE}.
+         */
+        void onGrabbedStateChange(View v, int grabbedState);
+    }
+
+    /**
+     * Simple container class for all things pertinent to a slider.  
+     * A slider consists of 3 Views:
+     * 
+     * {@link #tab} is the tab shown on the screen in the default state.
+     * {@link #text} is the view revealed as the user slides the tab out.
+     * {@link #target} is the target the user must drag the slider past to trigger the slider.
+     *
+     */
+    private static class Slider {
+        /**
+         * Tab alignment - determines which side the tab should be drawn on
+         */
+        public static final int ALIGN_LEFT = 0;
+        public static final int ALIGN_RIGHT = 1;
+        public static final int ALIGN_TOP = 2;
+        public static final int ALIGN_BOTTOM = 3;
+
+        /**
+         * States for the view.
+         */
+        private static final int STATE_NORMAL = 0;
+        private static final int STATE_PRESSED = 1;
+        private static final int STATE_ACTIVE = 2;
+
+        private final ImageView tab;
+        private final TextView text;
+        private final ImageView target;
+
+        /**
+         * Constructor
+         * 
+         * @param parent the container view of this one
+         * @param tabId drawable for the tab
+         * @param barId drawable for the bar
+         * @param targetId drawable for the target
+         */
+        Slider(ViewGroup parent, int tabId, int barId, int targetId) {
+            // Create tab
+            tab = new ImageView(parent.getContext());
+            tab.setBackgroundResource(tabId);
+            tab.setScaleType(ScaleType.CENTER);
+            tab.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                    LayoutParams.WRAP_CONTENT));
+
+            // Create hint TextView
+            text = new TextView(parent.getContext());
+            text.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                    LayoutParams.FILL_PARENT));
+            text.setBackgroundResource(barId);
+            text.setTextAppearance(parent.getContext(), R.style.TextAppearance_SlidingTabNormal);
+            // hint.setSingleLine();  // Hmm.. this causes the text to disappear off-screen
+
+            // Create target
+            target = new ImageView(parent.getContext());
+            target.setImageResource(targetId);
+            target.setScaleType(ScaleType.CENTER);
+            target.setLayoutParams(
+                    new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+            target.setVisibility(View.INVISIBLE);
+
+            parent.addView(target); // this needs to be first - relies on painter's algorithm
+            parent.addView(tab);
+            parent.addView(text);
+        }
+
+        void setIcon(int iconId) {
+            tab.setImageResource(iconId);
+        }
+        
+        void setTabBackgroundResource(int tabId) {
+            tab.setBackgroundResource(tabId);
+        }
+        
+        void setBarBackgroundResource(int barId) {
+            text.setBackgroundResource(barId);
+        }
+        
+        void setHintText(int resId) {
+            // TODO: Text should be blank if widget is vertical
+            text.setText(resId); 
+        }
+
+        void hide() {
+            // TODO: Animate off the screen
+            text.setVisibility(View.INVISIBLE);
+            tab.setVisibility(View.INVISIBLE);
+            target.setVisibility(View.INVISIBLE);
+        }
+
+        void setState(int state) {
+            text.setPressed(state == STATE_PRESSED);
+            tab.setPressed(state == STATE_PRESSED);
+            if (state == STATE_ACTIVE) {
+                final int[] activeState = new int[] {com.android.internal.R.attr.state_active};
+                if (text.getBackground().isStateful()) {
+                    text.getBackground().setState(activeState);
+                }
+                if (tab.getBackground().isStateful()) {
+                    tab.getBackground().setState(activeState);
+                }
+                text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabActive);
+            } else {
+                text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabNormal);
+            }
+        }
+
+        void showTarget() {
+            target.setVisibility(View.VISIBLE);
+        }
+
+        void reset() {
+            setState(STATE_NORMAL);
+            text.setVisibility(View.VISIBLE);
+            text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabNormal);
+            tab.setVisibility(View.VISIBLE);
+            target.setVisibility(View.INVISIBLE);
+        }
+
+        void setTarget(int targetId) {
+            target.setImageResource(targetId);
+        }
+
+        /**
+         * Layout the given widgets within the parent.
+         *
+         * @param l the parent's left border
+         * @param t the parent's top border
+         * @param r the parent's right border
+         * @param b the parent's bottom border
+         * @param alignment which side to align the widget to
+         */
+        void layout(int l, int t, int r, int b, int alignment) {
+            final Drawable tabBackground = tab.getBackground();
+            final int handleWidth = tabBackground.getIntrinsicWidth();
+            final int handleHeight = tabBackground.getIntrinsicHeight();
+            final Drawable targetDrawable = target.getDrawable();
+            final int targetWidth = targetDrawable.getIntrinsicWidth();
+            final int targetHeight = targetDrawable.getIntrinsicHeight();
+            final int parentWidth = r - l;
+            final int parentHeight = b - t;
+
+            final int leftTarget = (int) (TARGET_ZONE * parentWidth) - targetWidth + handleWidth / 2;
+            final int rightTarget = (int) ((1.0f - TARGET_ZONE) * parentWidth) - handleWidth / 2;
+            final int left = (parentWidth - handleWidth) / 2;
+            final int right = left + handleWidth;
+
+            if (alignment == ALIGN_LEFT || alignment == ALIGN_RIGHT) {
+                // horizontal
+                final int targetTop = (parentHeight - targetHeight) / 2;
+                final int targetBottom = targetTop + targetHeight;
+                final int top = (parentHeight - handleHeight) / 2;
+                final int bottom = (parentHeight + handleHeight) / 2;
+                if (alignment == ALIGN_LEFT) {
+                    tab.layout(0, top, handleWidth, bottom);
+                    text.layout(0 - parentWidth, top, 0, bottom);
+                    text.setGravity(Gravity.RIGHT);
+                    target.layout(leftTarget, targetTop, leftTarget + targetWidth, targetBottom);
+                } else {
+                    tab.layout(parentWidth - handleWidth, top, parentWidth, bottom);
+                    text.layout(parentWidth, top, parentWidth + parentWidth, bottom);
+                    target.layout(rightTarget, targetTop, rightTarget + targetWidth, targetBottom);
+                    text.setGravity(Gravity.TOP);
+                }
+            } else {
+                // vertical
+                final int targetLeft = (parentWidth - targetWidth) / 2;
+                final int targetRight = (parentWidth + targetWidth) / 2;
+                final int top = (int) (TARGET_ZONE * parentHeight) + handleHeight / 2 - targetHeight;
+                final int bottom = (int) ((1.0f - TARGET_ZONE) * parentHeight) - handleHeight / 2;
+                if (alignment == ALIGN_TOP) {
+                    tab.layout(left, 0, right, handleHeight);
+                    text.layout(left, 0 - parentHeight, right, 0);
+                    target.layout(targetLeft, top, targetRight, top + targetHeight);
+                } else {
+                    tab.layout(left, parentHeight - handleHeight, right, parentHeight);
+                    text.layout(left, parentHeight, right, parentHeight + parentHeight);
+                    target.layout(targetLeft, bottom, targetRight, bottom + targetHeight);
+                }
+            }
+        }
+
+        public int getTabWidth() {
+            return tab.getDrawable().getIntrinsicWidth();
+        }
+
+        public int getTabHeight() {
+            return tab.getDrawable().getIntrinsicHeight();
+        }
+    }
+
+    public SlidingTab(Context context) {
+        this(context, null);
+    }
+
+    /**
+     * Constructor used when this widget is created from a layout file.
+     */
+    public SlidingTab(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlidingTab);
+        mOrientation = a.getInt(R.styleable.SlidingTab_orientation, HORIZONTAL);
+        a.recycle();
+
+        Resources r = getResources();
+        mDensity = r.getDisplayMetrics().density;
+        if (DBG) log("- Density: " + mDensity);
+
+        mLeftSlider = new Slider(this, 
+                R.drawable.jog_tab_left_generic, 
+                R.drawable.jog_tab_bar_left_generic,
+                R.drawable.jog_tab_target_gray);
+        mRightSlider = new Slider(this, 
+                R.drawable.jog_tab_right_generic, 
+                R.drawable.jog_tab_bar_right_generic,
+                R.drawable.jog_tab_target_gray);
+
+        // setBackgroundColor(0x80808080);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
+        int widthSpecSize =  MeasureSpec.getSize(widthMeasureSpec);
+
+        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
+        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
+
+        if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
+            throw new RuntimeException(LOG_TAG + " cannot have UNSPECIFIED dimensions");
+        }
+
+        final float density = mDensity;
+        final int leftTabWidth = (int) (density * mLeftSlider.getTabWidth() + 0.5f);
+        final int rightTabWidth = (int) (density * mRightSlider.getTabWidth() + 0.5f);
+        final int leftTabHeight = (int) (density * mLeftSlider.getTabHeight() + 0.5f);
+        final int rightTabHeight = (int) (density * mRightSlider.getTabHeight() + 0.5f);
+        final int width;
+        final int height;
+        if (isHorizontal()) {
+            width = Math.max(widthSpecSize, leftTabWidth + rightTabWidth);
+            height = Math.max(leftTabHeight, rightTabHeight);
+        } else {
+            width = Math.max(leftTabWidth, rightTabHeight);
+            height = Math.max(heightSpecSize, leftTabHeight + rightTabHeight);
+        }
+        setMeasuredDimension(width, height);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        final int action = event.getAction();
+        final float x = event.getX();
+        final float y = event.getY();
+
+        final Rect frame = new Rect();
+
+        if (mAnimating) {
+            return false;
+        }
+
+        View leftHandle = mLeftSlider.tab;
+        leftHandle.getHitRect(frame);
+        boolean leftHit = frame.contains((int) x, (int) y);
+
+        View rightHandle = mRightSlider.tab;
+        rightHandle.getHitRect(frame);
+        boolean rightHit = frame.contains((int)x, (int) y);
+
+        if (!mTracking && !(leftHit || rightHit)) {
+            return false;
+        }
+
+        switch (action) {
+            case MotionEvent.ACTION_DOWN: {
+                mTracking = true;
+                mTriggered = false;
+                vibrate(VIBRATE_SHORT);
+                if (leftHit) {
+                    mCurrentSlider = mLeftSlider;
+                    mOtherSlider = mRightSlider;
+                    mTargetZone = isHorizontal() ? TARGET_ZONE : 1.0f - TARGET_ZONE;
+                    setGrabbedState(OnTriggerListener.LEFT_HANDLE);
+                } else {
+                    mCurrentSlider = mRightSlider;
+                    mOtherSlider = mLeftSlider;
+                    mTargetZone = isHorizontal() ? 1.0f - TARGET_ZONE : TARGET_ZONE;
+                    setGrabbedState(OnTriggerListener.RIGHT_HANDLE);
+                }
+                mCurrentSlider.setState(Slider.STATE_PRESSED);
+                mCurrentSlider.showTarget();
+                mOtherSlider.hide();
+                break;
+            }
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mTracking) {
+            final int action = event.getAction();
+            final float x = event.getX();
+            final float y = event.getY();
+            final View handle = mCurrentSlider.tab;
+            switch (action) {
+                case MotionEvent.ACTION_MOVE:
+                    moveHandle(x, y);
+                    float position = isHorizontal() ? x : y;
+                    float target = mTargetZone * (isHorizontal() ? getWidth() : getHeight());
+                    boolean targetZoneReached;
+                    if (isHorizontal()) {
+                        targetZoneReached = mCurrentSlider == mLeftSlider ?
+                                position > target : position < target;
+                    } else {
+                        targetZoneReached = mCurrentSlider == mLeftSlider ?
+                                position < target : position > target;
+                    }
+                    if (!mTriggered && targetZoneReached) {
+                        mTriggered = true;
+                        mTracking = false;
+                        mCurrentSlider.setState(Slider.STATE_ACTIVE);
+                        dispatchTriggerEvent(mCurrentSlider == mLeftSlider ?
+                            OnTriggerListener.LEFT_HANDLE : OnTriggerListener.RIGHT_HANDLE);
+
+                        // TODO: This is a place holder for the real animation. It just holds
+                        // the screen for the duration of the animation for now.
+                        mAnimating = true;
+                        mHandler.postDelayed(new Runnable() {
+                            public void run() {
+                                resetView();
+                                mAnimating = false;
+                            }
+                        }, ANIMATION_DURATION);
+                    }
+
+                    if (isHorizontal() && (y <= handle.getBottom() && y >= handle.getTop()) ||
+                            !isHorizontal() && (x >= handle.getLeft() && x <= handle.getRight()) ) {
+                        break;
+                    }
+                    // Intentionally fall through - we're outside tracking rectangle
+
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_CANCEL:
+                    mTracking = false;
+                    mTriggered = false;
+                    resetView();
+                    setGrabbedState(OnTriggerListener.NO_HANDLE);
+                    break;
+            }
+        }
+
+        return mTracking || super.onTouchEvent(event);
+    }
+
+    private boolean isHorizontal() {
+        return mOrientation == HORIZONTAL;
+    }
+
+    private void resetView() {
+        mLeftSlider.reset();
+        mRightSlider.reset();
+        onLayout(true, getLeft(), getTop(), getLeft() + getWidth(), getTop() + getHeight());
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        if (!changed) return;
+
+        // Center the widgets in the view
+        mLeftSlider.layout(l, t, r, b, isHorizontal() ? Slider.ALIGN_LEFT : Slider.ALIGN_BOTTOM);
+        mRightSlider.layout(l, t, r, b, isHorizontal() ? Slider.ALIGN_RIGHT : Slider.ALIGN_TOP);
+
+        invalidate(); // TODO: be more conservative about what we're invalidating
+    }
+
+    private void moveHandle(float x, float y) {
+        final View handle = mCurrentSlider.tab;
+        final View content = mCurrentSlider.text;
+        if (isHorizontal()) {
+            int deltaX = (int) x - handle.getLeft() - (handle.getWidth() / 2);
+            handle.offsetLeftAndRight(deltaX);
+            content.offsetLeftAndRight(deltaX);
+        } else {
+            int deltaY = (int) y - handle.getTop() - (handle.getHeight() / 2);
+            handle.offsetTopAndBottom(deltaY);
+            content.offsetTopAndBottom(deltaY);
+        }
+        invalidate(); // TODO: be more conservative about what we're invalidating
+    }
+
+    /**
+     * Sets the left handle icon to a given resource.
+     *
+     * The resource should refer to a Drawable object, or use 0 to remove
+     * the icon.
+     *
+     * @param iconId the resource ID of the icon drawable
+     * @param targetId the resource of the target drawable
+     * @param barId the resource of the bar drawable (stateful)
+     * @param tabId the resource of the 
+     */
+    public void setLeftTabResources(int iconId, int targetId, int barId, int tabId) {
+        mLeftSlider.setIcon(iconId);
+        mLeftSlider.setTarget(targetId); 
+        mLeftSlider.setBarBackgroundResource(barId);
+        mLeftSlider.setTabBackgroundResource(tabId);
+    }
+
+    /**
+     * Sets the left handle hint text to a given resource string.
+     *
+     * @param resId
+     */
+    public void setLeftHintText(int resId) {
+        mLeftSlider.setHintText(resId);
+    }
+
+    /**
+     * Sets the right handle icon to a given resource.
+     *
+     * The resource should refer to a Drawable object, or use 0 to remove
+     * the icon.
+     *
+     * @param iconId the resource ID of the icon drawable
+     * @param targetId the resource of the target drawable
+     * @param barId the resource of the bar drawable (stateful)
+     * @param tabId the resource of the 
+     */
+    public void setRightTabResources(int iconId, int targetId, int barId, int tabId) {
+        mRightSlider.setIcon(iconId);
+        mRightSlider.setTarget(targetId); 
+        mRightSlider.setBarBackgroundResource(barId);
+        mRightSlider.setTabBackgroundResource(tabId);
+    }
+
+    /**
+     * Sets the left handle hint text to a given resource string.
+     *
+     * @param resId
+     */
+    public void setRightHintText(int resId) {
+        mRightSlider.setHintText(resId);
+    }
+
+    /**
+     * Triggers haptic feedback.
+     */
+    private synchronized void vibrate(long duration) {
+        if (mVibrator == null) {
+            mVibrator = (android.os.Vibrator)
+                    getContext().getSystemService(Context.VIBRATOR_SERVICE);
+        }
+        mVibrator.vibrate(duration);
+    }
+
+    /**
+     * Registers a callback to be invoked when the user triggers an event.
+     *
+     * @param listener the OnDialTriggerListener to attach to this view
+     */
+    public void setOnTriggerListener(OnTriggerListener listener) {
+        mOnTriggerListener = listener;
+    }
+
+    /**
+     * Dispatches a trigger event to listener. Ignored if a listener is not set.
+     * @param whichHandle the handle that triggered the event.
+     */
+    private void dispatchTriggerEvent(int whichHandle) {
+        vibrate(VIBRATE_LONG);
+        if (mOnTriggerListener != null) {
+            mOnTriggerListener.onTrigger(this, whichHandle);
+        }
+    }
+
+    /**
+     * Sets the current grabbed state, and dispatches a grabbed state change
+     * event to our listener.
+     */
+    private void setGrabbedState(int newState) {
+        if (newState != mGrabbedState) {
+            mGrabbedState = newState;
+            if (mOnTriggerListener != null) {
+                mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState);
+            }
+        }
+    }
+
+    private class SlidingTabHandler extends Handler {
+        public void handleMessage(Message m) {
+            switch (m.what) {
+                case MSG_ANIMATE:
+                    doAnimation();
+                    break;
+            }
+        }
+    }
+
+    private void doAnimation() {
+        if (mAnimating) {
+
+        }
+    }
+
+    private void log(String msg) {
+        Log.d(LOG_TAG, msg);
+    }
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7d6f158..1c3cf3c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -41,6 +41,7 @@
     <protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
     <protected-broadcast android:name="android.intent.action.UID_REMOVED" />
     <protected-broadcast android:name="android.intent.action.CONFIGURATION_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.LOCALE_CHANGED" />
     <protected-broadcast android:name="android.intent.action.BATTERY_CHANGED" />
     <protected-broadcast android:name="android.intent.action.BATTERY_LOW" />
     <protected-broadcast android:name="android.intent.action.BATTERY_OKAY" />
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_confirm_gray.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_gray.9.png
new file mode 100644
index 0000000..92db44f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_gray.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_confirm_green.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_green.9.png
new file mode 100644
index 0000000..0bed1a0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_confirm_red.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_red.9.png
new file mode 100644
index 0000000..81fbe5a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_red.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_confirm_yellow.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_yellow.9.png
new file mode 100644
index 0000000..d9c33fb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_yellow.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_normal.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_normal.9.png
new file mode 100644
index 0000000..1cf7f1c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_pressed.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_pressed.9.png
new file mode 100644
index 0000000..c7b367e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_gray.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_gray.png
new file mode 100644
index 0000000..3499208
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_gray.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_green.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_green.png
new file mode 100644
index 0000000..91eaec8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_green.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_red.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_red.png
new file mode 100644
index 0000000..8818b9e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_red.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_yellow.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_yellow.png
new file mode 100644
index 0000000..e5bc5f6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_yellow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_left_normal.png b/core/res/res/drawable-hdpi/jog_tab_left_normal.png
new file mode 100644
index 0000000..5326c7c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_left_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_left_pressed.png b/core/res/res/drawable-hdpi/jog_tab_left_pressed.png
new file mode 100644
index 0000000..7b906df
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_left_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_gray.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_gray.png
new file mode 100644
index 0000000..ea8c315
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_gray.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_green.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_green.png
new file mode 100644
index 0000000..aa0ceb9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_green.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_red.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_red.png
new file mode 100644
index 0000000..d772fb6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_red.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_yellow.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_yellow.png
new file mode 100644
index 0000000..3cfeb67
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_yellow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_right_normal.png b/core/res/res/drawable-hdpi/jog_tab_right_normal.png
new file mode 100644
index 0000000..da7726b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_right_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_right_pressed.png b/core/res/res/drawable-hdpi/jog_tab_right_pressed.png
new file mode 100644
index 0000000..450a325
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_right_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_target_gray.png b/core/res/res/drawable-hdpi/jog_tab_target_gray.png
new file mode 100644
index 0000000..e7ef129
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_target_gray.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_target_green.png b/core/res/res/drawable-hdpi/jog_tab_target_green.png
new file mode 100644
index 0000000..17f6b10
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_target_green.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_target_red.png b/core/res/res/drawable-hdpi/jog_tab_target_red.png
new file mode 100644
index 0000000..8db20bb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_target_red.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_target_yellow.png b/core/res/res/drawable-hdpi/jog_tab_target_yellow.png
new file mode 100644
index 0000000..15045b0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_target_yellow.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/btn_lock_normal.9.png b/core/res/res/drawable-land-hdpi/btn_lock_normal.9.png
new file mode 100644
index 0000000..f1dac62
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/btn_lock_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/ic_jog_dial_sound_off.png b/core/res/res/drawable-land-hdpi/ic_jog_dial_sound_off.png
new file mode 100755
index 0000000..d73db48
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/ic_jog_dial_sound_off.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/ic_jog_dial_sound_on.png b/core/res/res/drawable-land-hdpi/ic_jog_dial_sound_on.png
new file mode 100755
index 0000000..90da6e3
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/ic_jog_dial_sound_on.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/ic_jog_dial_unlock.png b/core/res/res/drawable-land-hdpi/ic_jog_dial_unlock.png
new file mode 100755
index 0000000..a9af1af
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/ic_jog_dial_unlock.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_gray.9.png b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_gray.9.png
new file mode 100644
index 0000000..c0f7706
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_gray.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_green.9.png b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_green.9.png
new file mode 100644
index 0000000..0f2ce13
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_red.9.png b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_red.9.png
new file mode 100644
index 0000000..a34eb7d
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_red.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_yellow.9.png b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_yellow.9.png
new file mode 100644
index 0000000..e143356
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_yellow.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_bar_normal.9.png b/core/res/res/drawable-land-hdpi/jog_tab_bar_normal.9.png
new file mode 100644
index 0000000..b5837f7
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_bar_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_bar_pressed.9.png b/core/res/res/drawable-land-hdpi/jog_tab_bar_pressed.9.png
new file mode 100644
index 0000000..79ad83d
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_bar_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_gray.png b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_gray.png
new file mode 100644
index 0000000..9c63b22
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_gray.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_green.png b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_green.png
new file mode 100644
index 0000000..4f9877c
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_green.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_red.png b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_red.png
new file mode 100644
index 0000000..bdce97d
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_red.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_yellow.png b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_yellow.png
new file mode 100644
index 0000000..327fc2c
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_yellow.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_left_normal.png b/core/res/res/drawable-land-hdpi/jog_tab_left_normal.png
new file mode 100644
index 0000000..e69d91c
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_left_normal.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_left_pressed.png b/core/res/res/drawable-land-hdpi/jog_tab_left_pressed.png
new file mode 100644
index 0000000..b6153d8
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_left_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_gray.png b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_gray.png
new file mode 100644
index 0000000..6e3e00b
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_gray.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_green.png b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_green.png
new file mode 100644
index 0000000..dae9efc
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_green.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_red.png b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_red.png
new file mode 100644
index 0000000..9de3158
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_red.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_yellow.png b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_yellow.png
new file mode 100644
index 0000000..8c9f180
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_yellow.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_right_normal.png b/core/res/res/drawable-land-hdpi/jog_tab_right_normal.png
new file mode 100644
index 0000000..0c4faf2
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_right_normal.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_right_pressed.png b/core/res/res/drawable-land-hdpi/jog_tab_right_pressed.png
new file mode 100644
index 0000000..4ec7b56
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_right_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_target_gray.png b/core/res/res/drawable-land-hdpi/jog_tab_target_gray.png
new file mode 100644
index 0000000..4150007
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_target_gray.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_target_green.png b/core/res/res/drawable-land-hdpi/jog_tab_target_green.png
new file mode 100644
index 0000000..ef18b6c
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_target_green.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_target_red.png b/core/res/res/drawable-land-hdpi/jog_tab_target_red.png
new file mode 100644
index 0000000..5dfaa5f
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_target_red.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_target_yellow.png b/core/res/res/drawable-land-hdpi/jog_tab_target_yellow.png
new file mode 100644
index 0000000..d0509fa
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_target_yellow.png
Binary files differ
diff --git a/core/res/res/drawable/jog_tab_bar_left_answer.xml b/core/res/res/drawable/jog_tab_bar_left_answer.xml
new file mode 100644
index 0000000..b1d7c31
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_bar_left_answer.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_bar_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_bar_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_bar_confirm_green" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_bar_left_generic.xml b/core/res/res/drawable/jog_tab_bar_left_generic.xml
new file mode 100644
index 0000000..de1a42f
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_bar_left_generic.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_bar_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_bar_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_bar_confirm_gray" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_bar_left_unlock.xml b/core/res/res/drawable/jog_tab_bar_left_unlock.xml
new file mode 100644
index 0000000..b1d7c31
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_bar_left_unlock.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_bar_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_bar_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_bar_confirm_green" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_bar_right_decline.xml b/core/res/res/drawable/jog_tab_bar_right_decline.xml
new file mode 100644
index 0000000..ae82aba
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_bar_right_decline.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_bar_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_bar_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_bar_confirm_red" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_bar_right_generic.xml b/core/res/res/drawable/jog_tab_bar_right_generic.xml
new file mode 100644
index 0000000..de1a42f
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_bar_right_generic.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_bar_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_bar_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_bar_confirm_gray" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_bar_right_sound_off.xml b/core/res/res/drawable/jog_tab_bar_right_sound_off.xml
new file mode 100644
index 0000000..de1a42f
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_bar_right_sound_off.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_bar_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_bar_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_bar_confirm_gray" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_bar_right_sound_on.xml b/core/res/res/drawable/jog_tab_bar_right_sound_on.xml
new file mode 100644
index 0000000..febe32a
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_bar_right_sound_on.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_bar_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_bar_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_bar_confirm_yellow" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_left_answer.xml b/core/res/res/drawable/jog_tab_left_answer.xml
new file mode 100644
index 0000000..18ec7fa
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_left_answer.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_left_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_left_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_left_confirm_green" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_left_generic.xml b/core/res/res/drawable/jog_tab_left_generic.xml
new file mode 100644
index 0000000..ed6d98b
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_left_generic.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_left_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_left_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_left_confirm_gray" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_left_unlock.xml b/core/res/res/drawable/jog_tab_left_unlock.xml
new file mode 100644
index 0000000..18ec7fa
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_left_unlock.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_left_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_left_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_left_confirm_green" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_right_decline.xml b/core/res/res/drawable/jog_tab_right_decline.xml
new file mode 100644
index 0000000..a3bca5e
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_right_decline.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_right_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_right_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_right_confirm_red" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_right_generic.xml b/core/res/res/drawable/jog_tab_right_generic.xml
new file mode 100644
index 0000000..e173f2a
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_right_generic.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_right_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_right_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_right_confirm_gray" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_right_sound_off.xml b/core/res/res/drawable/jog_tab_right_sound_off.xml
new file mode 100644
index 0000000..e173f2a
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_right_sound_off.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_right_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_right_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_right_confirm_gray" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_right_sound_on.xml b/core/res/res/drawable/jog_tab_right_sound_on.xml
new file mode 100644
index 0000000..61f677c
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_right_sound_on.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_right_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_right_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_right_confirm_yellow" />
+        
+</selector>
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
new file mode 100644
index 0000000..84b5751
--- /dev/null
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This is the general lock screen which shows information about the
+  state of the device, as well as instructions on how to get past it
+  depending on the state of the device.  It is the same for landscape
+  and portrait.-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:id="@+id/root">
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:background="#70000000"
+        android:gravity="center_horizontal">
+    
+        <TextView
+            android:id="@+id/carrier"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:layout_marginTop="20dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            />
+    
+        <TextView
+            android:id="@+id/time"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/carrier"
+            android:layout_marginTop="25dip"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textSize="55sp"
+            />
+    
+        <TextView
+            android:id="@+id/date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/time"
+            android:layout_marginTop="-12dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            />
+    
+        <View
+            android:id="@+id/divider"
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:layout_marginTop="10dip"
+            android:layout_below="@id/date"
+            android:background="@android:drawable/divider_horizontal_dark"
+            />
+    
+        <TextView
+            android:id="@+id/status1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/divider"
+            android:layout_marginTop="6dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:drawablePadding="4dip"
+            />
+    
+        <TextView
+            android:id="@+id/status2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/status1"
+            android:layout_marginTop="6dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:drawablePadding="4dip"
+            />
+    
+        <TextView
+            android:id="@+id/screenLocked"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/status2"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:gravity="center"
+            android:layout_marginTop="12dip"
+            />
+    
+        <com.android.internal.widget.SlidingTab
+            android:id="@+id/tab_selector"
+            android:orientation="horizontal"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_marginBottom="50dip" 
+            />
+    
+        <!-- emergency call button shown when sim is missing or PUKd -->
+        <Button
+            android:id="@+id/emergencyCallButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/screenLocked"
+            android:layout_marginTop="24dip"
+            android:drawableLeft="@drawable/ic_emergency"
+            android:drawablePadding="8dip"
+           />
+    
+    </RelativeLayout>
+
+</FrameLayout>
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
new file mode 100644
index 0000000..6aed301
--- /dev/null
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This is the general lock screen which shows information about the
+  state of the device, as well as instructions on how to get past it
+  depending on the state of the device.-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="horizontal"
+    android:background="#70000000"
+    android:id="@+id/root">
+     
+    <!-- left side -->
+    <RelativeLayout
+            android:layout_width="0dip"
+            android:layout_height="fill_parent"
+            android:layout_weight="1.0"
+            android:gravity="center_horizontal">
+
+        <TextView
+            android:id="@+id/carrier"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:layout_marginTop="20dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            />
+
+        <TextView
+            android:id="@+id/time"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/carrier"
+            android:layout_marginTop="25dip"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textSize="55sp"
+            />
+
+        <TextView
+            android:id="@+id/date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/time"
+            android:layout_marginTop="-12dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            />
+
+        <View
+            android:id="@+id/divider"
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:layout_marginTop="10dip"
+            android:layout_below="@id/date"
+            android:background="@android:drawable/divider_horizontal_dark"
+            />
+
+        <TextView
+            android:id="@+id/status1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/divider"
+            android:layout_marginTop="6dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:drawablePadding="4dip"
+            />
+
+        <TextView
+            android:id="@+id/status2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/status1"
+            android:layout_marginTop="6dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:drawablePadding="4dip"
+            />
+
+        <TextView
+            android:id="@+id/screenLocked"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/status2"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:gravity="center"
+            android:layout_marginTop="12dip"
+            />
+
+        <!-- emergency call button shown when sim is missing or PUKd -->
+        <Button
+            android:id="@+id/emergencyCallButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/screenLocked"
+            android:layout_marginTop="24dip"
+            android:drawableLeft="@drawable/ic_emergency"
+            android:drawablePadding="8dip"
+           />
+    </RelativeLayout>
+
+    <!-- right side -->
+    <com.android.internal.widget.SlidingTab
+        android:id="@+id/tab_selector"
+        android:orientation="vertical"
+        android:layout_width="wrap_content"
+        android:layout_height="fill_parent"
+        android:layout_marginBottom="50dip"
+        />
+
+</LinearLayout>
diff --git a/core/res/res/values-ar-rEG/donottranslate-cldr.xml b/core/res/res/values-ar-rEG/donottranslate-cldr.xml
index 2c20ffc..d662590 100644
--- a/core/res/res/values-ar-rEG/donottranslate-cldr.xml
+++ b/core/res/res/values-ar-rEG/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s، %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s، %3$s %2$s - %6$s، %8$s %7$s، %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E d MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE، d MMMM y</string>
 </resources>
diff --git a/core/res/res/values-bg-rBG/donottranslate-cldr.xml b/core/res/res/values-bg-rBG/donottranslate-cldr.xml
index 527cdb9..f03b060 100644
--- a/core/res/res/values-bg-rBG/donottranslate-cldr.xml
+++ b/core/res/res/values-bg-rBG/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%3$s %2$s %9$s, %1$s - %8$s %7$s y, %6$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_year">d MMM y, E</string>
 </resources>
diff --git a/core/res/res/values-ca-rES/donottranslate-cldr.xml b/core/res/res/values-ca-rES/donottranslate-cldr.xml
index d5abeef..a77aa38 100644
--- a/core/res/res/values-ca-rES/donottranslate-cldr.xml
+++ b/core/res/res/values-ca-rES/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s de %2$s de %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s de %2$s - %6$s %8$s de %7$s de %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E d MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE d MMM y</string>
 </resources>
diff --git a/core/res/res/values-cs/donottranslate-cldr.xml b/core/res/res/values-cs/donottranslate-cldr.xml
index 53dc312..6235b2c 100644
--- a/core/res/res/values-cs/donottranslate-cldr.xml
+++ b/core/res/res/values-cs/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s. %2$s - %6$s %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_year">E d. MMMM y</string>
 </resources>
diff --git a/core/res/res/values-da/donottranslate-cldr.xml b/core/res/res/values-da/donottranslate-cldr.xml
index a4faca2..a731174 100644
--- a/core/res/res/values-da/donottranslate-cldr.xml
+++ b/core/res/res/values-da/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s d. %3$s. %2$s - %6$s d. %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E d. MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE d. MMM y</string>
 </resources>
diff --git a/core/res/res/values-de/donottranslate-cldr.xml b/core/res/res/values-de/donottranslate-cldr.xml
index 8a9c1a7..ac6c195 100644
--- a/core/res/res/values-de/donottranslate-cldr.xml
+++ b/core/res/res/values-de/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s. - %8$s. %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d. MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE, d. MMM y</string>
 </resources>
diff --git a/core/res/res/values-el/donottranslate-cldr.xml b/core/res/res/values-el/donottranslate-cldr.xml
index e8f02fb..a0174f6 100644
--- a/core/res/res/values-el/donottranslate-cldr.xml
+++ b/core/res/res/values-el/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE, d MMM y</string>
 </resources>
diff --git a/core/res/res/values-en-rAU/donottranslate-cldr.xml b/core/res/res/values-en-rAU/donottranslate-cldr.xml
index 9811b68..cb254f3 100644
--- a/core/res/res/values-en-rAU/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rAU/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_year">E, d MMM y</string>
 </resources>
diff --git a/core/res/res/values-en-rCA/donottranslate-cldr.xml b/core/res/res/values-en-rCA/donottranslate-cldr.xml
index 1e250c7..597b0af 100644
--- a/core/res/res/values-en-rCA/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rCA/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%2$s %3$s-%8$s, %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s - %6$s, %7$s %8$s, %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, MMMM d</string>
+    <string name="abbrev_wday_month_day_year">E, MMM d, y</string>
 </resources>
diff --git a/core/res/res/values-en-rGB/donottranslate-cldr.xml b/core/res/res/values-en-rGB/donottranslate-cldr.xml
index 65545ba..5416b8e 100644
--- a/core/res/res/values-en-rGB/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rGB/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_year">E, d MMM y</string>
 </resources>
diff --git a/core/res/res/values-en-rIE/donottranslate-cldr.xml b/core/res/res/values-en-rIE/donottranslate-cldr.xml
index 2e59dcf..93743ba 100644
--- a/core/res/res/values-en-rIE/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rIE/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_year">E d MMM y</string>
 </resources>
diff --git a/core/res/res/values-en-rIN/donottranslate-cldr.xml b/core/res/res/values-en-rIN/donottranslate-cldr.xml
index e39a59a..9de1ba9 100644
--- a/core/res/res/values-en-rIN/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rIN/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_year">E d MMM y</string>
 </resources>
diff --git a/core/res/res/values-en-rNZ/donottranslate-cldr.xml b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
index 3a8b50b..e600878 100644
--- a/core/res/res/values-en-rNZ/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_year">E, d MMM y</string>
 </resources>
diff --git a/core/res/res/values-en-rUS/donottranslate-cldr.xml b/core/res/res/values-en-rUS/donottranslate-cldr.xml
index 286cc0e..14ef2a0 100644
--- a/core/res/res/values-en-rUS/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rUS/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%2$s %3$s – %8$s, %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s – %6$s, %7$s %8$s, %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, MMMM d</string>
+    <string name="abbrev_wday_month_day_year">EEE, MMM d, y</string>
 </resources>
diff --git a/core/res/res/values-en-rZA/donottranslate-cldr.xml b/core/res/res/values-en-rZA/donottranslate-cldr.xml
index 2e2d608..7c7529f 100644
--- a/core/res/res/values-en-rZA/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rZA/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_year">E dd MMM y</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/donottranslate-cldr.xml b/core/res/res/values-es-rUS/donottranslate-cldr.xml
index 7ade142..1ff3f05 100644
--- a/core/res/res/values-es-rUS/donottranslate-cldr.xml
+++ b/core/res/res/values-es-rUS/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s de %2$s de %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s de %2$s al %6$s %8$s de %7$s de %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E d \'de\' MMMM</string>
+    <string name="abbrev_wday_month_day_year">E d \'de\' MMM \'de\' y</string>
 </resources>
diff --git a/core/res/res/values-es/donottranslate-cldr.xml b/core/res/res/values-es/donottranslate-cldr.xml
index 0de0b64..7cefcce 100644
--- a/core/res/res/values-es/donottranslate-cldr.xml
+++ b/core/res/res/values-es/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s–%8$s de %2$s de %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s de %2$s – %6$s %8$s de %7$s de %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E d \'de\' MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE d \'de\' MMM \'de\' y</string>
 </resources>
diff --git a/core/res/res/values-fi-rFI/donottranslate-cldr.xml b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
index 151d935..59cf4ee 100644
--- a/core/res/res/values-fi-rFI/donottranslate-cldr.xml
+++ b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s. – %8$s. %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s. %2$s – %6$s %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E d. MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE d. MMM y</string>
 </resources>
diff --git a/core/res/res/values-fr/donottranslate-cldr.xml b/core/res/res/values-fr/donottranslate-cldr.xml
index bf93039..675cb7a 100644
--- a/core/res/res/values-fr/donottranslate-cldr.xml
+++ b/core/res/res/values-fr/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">du %3$s au %8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">du %1$s %3$s %2$s au %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">EEE d MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE d MMM y</string>
 </resources>
diff --git a/core/res/res/values-hi-rIN/donottranslate-cldr.xml b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
index 2a19da4..d9405d8 100644
--- a/core/res/res/values-hi-rIN/donottranslate-cldr.xml
+++ b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%9$s-%2$s-%3$s – %8$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE, d MMM y</string>
 </resources>
diff --git a/core/res/res/values-hr-rHR/donottranslate-cldr.xml b/core/res/res/values-hr-rHR/donottranslate-cldr.xml
index 6f8d6e5..70f4b64 100644
--- a/core/res/res/values-hr-rHR/donottranslate-cldr.xml
+++ b/core/res/res/values-hr-rHR/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s. - %8$s.%2$s.%9$s.</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s. - %6$s, %8$s.%7$s.%9$s.</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d. MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE, d.MMM.y.</string>
 </resources>
diff --git a/core/res/res/values-hu-rHU/donottranslate-cldr.xml b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
index 1940889..a34c541 100644
--- a/core/res/res/values-hu-rHU/donottranslate-cldr.xml
+++ b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%9$s. %2$s %3$s-%8$s.</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s. %2$s %3$s., %1$s - %7$s %8$s., %6$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_year">y. MMM d., E</string>
 </resources>
diff --git a/core/res/res/values-id-rID/donottranslate-cldr.xml b/core/res/res/values-id-rID/donottranslate-cldr.xml
index ee33241..6c1496f 100644
--- a/core/res/res/values-id-rID/donottranslate-cldr.xml
+++ b/core/res/res/values-id-rID/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s - %8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_year">E, d MMM y</string>
 </resources>
diff --git a/core/res/res/values-it/donottranslate-cldr.xml b/core/res/res/values-it/donottranslate-cldr.xml
index 5cc697c..34941e2 100644
--- a/core/res/res/values-it/donottranslate-cldr.xml
+++ b/core/res/res/values-it/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">EEE d MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE d MMM y</string>
 </resources>
diff --git a/core/res/res/values-ja/donottranslate-cldr.xml b/core/res/res/values-ja/donottranslate-cldr.xml
index dab8e2a..d4884bf 100644
--- a/core/res/res/values-ja/donottranslate-cldr.xml
+++ b/core/res/res/values-ja/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%9$s年%2$s%3$s日~%8$s日</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s年%2$s%3$s日 (%1$s)~%7$s%8$s日 (%6$s)</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">M月d日 (E)</string>
+    <string name="abbrev_wday_month_day_year">y年M月d日 (E)</string>
 </resources>
diff --git a/core/res/res/values-ko/donottranslate-cldr.xml b/core/res/res/values-ko/donottranslate-cldr.xml
index 6b792c6..67a5e7c 100644
--- a/core/res/res/values-ko/donottranslate-cldr.xml
+++ b/core/res/res/values-ko/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%9$s년 %2$s %3$s일 ~ %8$s일</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s년 %2$s %3$s일 %1$s ~ %7$s %8$s일 %6$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">MMMM d일 E</string>
+    <string name="abbrev_wday_month_day_year">y년 MMM d일 EEE</string>
 </resources>
diff --git a/core/res/res/values-lt-rLT/donottranslate-cldr.xml b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
index ad410e7..8a8822f 100644
--- a/core/res/res/values-lt-rLT/donottranslate-cldr.xml
+++ b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%9$s m. %2$s %3$s-%8$s d.</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s m. %2$s %3$s d., %1$s-%7$s %8$s d., %6$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">MMMM d \'d\'., E</string>
+    <string name="abbrev_wday_month_day_year">y \'m\'. MMM d \'d\'., E</string>
 </resources>
diff --git a/core/res/res/values-lv-rLV/donottranslate-cldr.xml b/core/res/res/values-lv-rLV/donottranslate-cldr.xml
index 2c6765a..3b6e55f 100644
--- a/core/res/res/values-lv-rLV/donottranslate-cldr.xml
+++ b/core/res/res/values-lv-rLV/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%9$s. gada %3$s.-%8$s. %2$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s. gada %3$s. %2$s-%6$s, y. gada %8$s. %7$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d. MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE, yyyy. \'g\'. dd. MMM</string>
 </resources>
diff --git a/core/res/res/values-nb/donottranslate-cldr.xml b/core/res/res/values-nb/donottranslate-cldr.xml
index ecf0111..62ec12c 100644
--- a/core/res/res/values-nb/donottranslate-cldr.xml
+++ b/core/res/res/values-nb/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s.–%8$s. %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s. %2$s–%6$s %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E d. MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE d. MMM y</string>
 </resources>
diff --git a/core/res/res/values-nl/donottranslate-cldr.xml b/core/res/res/values-nl/donottranslate-cldr.xml
index 2360e3f..101250e 100644
--- a/core/res/res/values-nl/donottranslate-cldr.xml
+++ b/core/res/res/values-nl/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E d MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE d MMM y</string>
 </resources>
diff --git a/core/res/res/values-pl/donottranslate-cldr.xml b/core/res/res/values-pl/donottranslate-cldr.xml
index f20a5b7..00a6d1c 100644
--- a/core/res/res/values-pl/donottranslate-cldr.xml
+++ b/core/res/res/values-pl/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s-%6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE, d MMM y</string>
 </resources>
diff --git a/core/res/res/values-pt-rPT/donottranslate-cldr.xml b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
index 197cb6e..f11ad2c 100644
--- a/core/res/res/values-pt-rPT/donottranslate-cldr.xml
+++ b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s de %2$s de %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s de %2$s - %6$s, %8$s de %7$s de %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">EEE, d \'de\' MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE, d \'de\' MMM \'de\' y</string>
 </resources>
diff --git a/core/res/res/values-pt/donottranslate-cldr.xml b/core/res/res/values-pt/donottranslate-cldr.xml
index 1111658..e80005e 100644
--- a/core/res/res/values-pt/donottranslate-cldr.xml
+++ b/core/res/res/values-pt/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s de %2$s de %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s de %2$s - %6$s, %8$s de %7$s de %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">EEE, d \'de\' MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE, d \'de\' MMM \'de\' y</string>
 </resources>
diff --git a/core/res/res/values-ro-rRO/donottranslate-cldr.xml b/core/res/res/values-ro-rRO/donottranslate-cldr.xml
index 4622445..ef34103 100644
--- a/core/res/res/values-ro-rRO/donottranslate-cldr.xml
+++ b/core/res/res/values-ro-rRO/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE, d MMM y</string>
 </resources>
diff --git a/core/res/res/values-ru/donottranslate-cldr.xml b/core/res/res/values-ru/donottranslate-cldr.xml
index 4870124..1b9938c 100644
--- a/core/res/res/values-ru/donottranslate-cldr.xml
+++ b/core/res/res/values-ru/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s г.</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%3$s %2$s - %8$s %7$s %9$s г.</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_year">E, d MMM y</string>
 </resources>
diff --git a/core/res/res/values-sk-rSK/donottranslate-cldr.xml b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
index 6478074..efd8e6a 100644
--- a/core/res/res/values-sk-rSK/donottranslate-cldr.xml
+++ b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s. - %8$s. %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s. %2$s - %6$s %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E d. MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE d. MMM y</string>
 </resources>
diff --git a/core/res/res/values-sl-rSI/donottranslate-cldr.xml b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
index ae16782..7bffe0c 100644
--- a/core/res/res/values-sl-rSI/donottranslate-cldr.xml
+++ b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s.–%8$s. %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s–%6$s, %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_year">E, d. MMM y</string>
 </resources>
diff --git a/core/res/res/values-sr-rRS/donottranslate-cldr.xml b/core/res/res/values-sr-rRS/donottranslate-cldr.xml
index 55ca968..60f81d8 100644
--- a/core/res/res/values-sr-rRS/donottranslate-cldr.xml
+++ b/core/res/res/values-sr-rRS/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s.</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s.</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_year">EEE, d. MMM y.</string>
 </resources>
diff --git a/core/res/res/values-sv/donottranslate-cldr.xml b/core/res/res/values-sv/donottranslate-cldr.xml
index 0172755..187e1b1 100644
--- a/core/res/res/values-sv/donottranslate-cldr.xml
+++ b/core/res/res/values-sv/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s–%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s – %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E d MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE d MMM y</string>
 </resources>
diff --git a/core/res/res/values-th-rTH/donottranslate-cldr.xml b/core/res/res/values-th-rTH/donottranslate-cldr.xml
index b3c76a3..8970549 100644
--- a/core/res/res/values-th-rTH/donottranslate-cldr.xml
+++ b/core/res/res/values-th-rTH/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s–%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s – %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E d MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE d MMM y</string>
 </resources>
diff --git a/core/res/res/values-tr/donottranslate-cldr.xml b/core/res/res/values-tr/donottranslate-cldr.xml
index fd8e762..9e614a6 100644
--- a/core/res/res/values-tr/donottranslate-cldr.xml
+++ b/core/res/res/values-tr/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%3$s %2$s %1$s - %8$s %7$s %6$s %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">dd MMMM E</string>
+    <string name="abbrev_wday_month_day_year">dd MMM y EEE</string>
 </resources>
diff --git a/core/res/res/values-uk-rUA/donottranslate-cldr.xml b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
index ed310c8..1b35326 100644
--- a/core/res/res/values-uk-rUA/donottranslate-cldr.xml
+++ b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%3$s – %8$s %2$s %9$s р.</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s – %6$s, %8$s %7$s %9$s р.</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE, d MMM y \'р\'.</string>
 </resources>
diff --git a/core/res/res/values-vi-rVN/donottranslate-cldr.xml b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
index 6f2d342..30e0887 100644
--- a/core/res/res/values-vi-rVN/donottranslate-cldr.xml
+++ b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">Ngày %3$s tháng %2$s - Ngày %8$s tháng M năm %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, ngày %3$s %2$s - %6$s, ngày %8$s %7$s năm %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E d MMMM</string>
+    <string name="abbrev_wday_month_day_year">EEE, d MMM y</string>
 </resources>
diff --git a/core/res/res/values-zh-rCN/donottranslate-cldr.xml b/core/res/res/values-zh-rCN/donottranslate-cldr.xml
index 5077e94..e852dd1 100644
--- a/core/res/res/values-zh-rCN/donottranslate-cldr.xml
+++ b/core/res/res/values-zh-rCN/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%9$s 年 %2$s %3$s - %8$s 日</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s 年 %2$s %3$s 日%1$s - %7$s %8$s 日%6$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">MMMM d 日E</string>
+    <string name="abbrev_wday_month_day_year">y 年 MMM d 日EEE</string>
 </resources>
diff --git a/core/res/res/values-zh-rTW/donottranslate-cldr.xml b/core/res/res/values-zh-rTW/donottranslate-cldr.xml
index 3e1acf1..63293d8 100644
--- a/core/res/res/values-zh-rTW/donottranslate-cldr.xml
+++ b/core/res/res/values-zh-rTW/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%9$s 年 %2$s %3$s 日至 %8$s 日</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s 年 %2$s %3$s 日%1$s至 %7$s %8$s 日%6$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">MMMM d 日E</string>
+    <string name="abbrev_wday_month_day_year">y 年 MMM d 日EEE</string>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 81da739..50382b3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3559,4 +3559,14 @@
         <attr name="detailSocialSummary" format="boolean" />
     </declare-styleable>
 
+    <!-- =============================== -->
+    <!-- TabSelector class attributes -->
+    <!-- =============================== -->
+    <eat-comment />
+
+    <declare-styleable name="SlidingTab">
+        <!-- Use "horizontal" for a row, "vertical" for a column.  The default is horizontal. -->
+        <attr name="orientation" />
+    </declare-styleable>
+
 </resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 5d3069b..3c0f0a4 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -84,6 +84,10 @@
     <color name="search_url_text_selected">@android:color/black</color>
     <color name="search_url_text_pressed">@android:color/black</color>
     <color name="search_widget_corpus_item_background">@android:color/lighter_gray</color>
+    
+    <!-- SlidingTab -->
+    <color name="sliding_tab_text_color_active">@android:color/black</color>
+    <color name="sliding_tab_text_color_shadow">@android:color/black</color>
 
 </resources>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index aaa1d8b..822a59a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -207,4 +207,11 @@
 
     <!-- Enables swipe versus poly-finger touch disambiguation in the KeyboardView -->
     <bool name="config_swipeDisambiguation">true</bool>
+
+    <!-- Enables special filtering code in the framework for raw touch events
+         from the touch driver.  This code exists for one particular device,
+         and should not be enabled for any others.  Hopefully in the future
+         it will be removed when the lower-level touch driver generates better
+         data. -->
+    <bool name="config_filterTouchEvents">false</bool>
 </resources>
diff --git a/core/res/res/values/donottranslate-cldr.xml b/core/res/res/values/donottranslate-cldr.xml
index 286cc0e..14ef2a0 100644
--- a/core/res/res/values/donottranslate-cldr.xml
+++ b/core/res/res/values/donottranslate-cldr.xml
@@ -144,4 +144,6 @@
     <string name="same_month_mdy1_mdy2">%2$s %3$s – %8$s, %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s – %6$s, %7$s %8$s, %9$s</string>
     <string name="short_format_month">%b</string>
+    <string name="full_wday_month_day_no_year">E, MMMM d</string>
+    <string name="abbrev_wday_month_day_year">EEE, MMM d, y</string>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index de30fe7..1394341 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1434,6 +1434,12 @@
 
     <!-- Displayed in a progress dialog while a username and password are being checked. -->
     <string name="lockscreen_glogin_checking_password">Checking...</string>
+    <!-- Displayed on lock screen's left tab - unlock -->
+    <string name="lockscreen_unlock_label">Unlock</string>
+    <!-- Displayed on lock screen's right tab - turn sound on -->
+    <string name="lockscreen_sound_on_label">Sound on</string>
+    <!-- Displayed on lock screen's right tab - turn sound off -->
+    <string name="lockscreen_sound_off_label">Sound off</string>
 
     <!-- A format string for 12-hour time of day, just the hour, not the minute, with lower-case "am" or "pm" (example: "3pm"). -->
     <string name="hour_ampm">"<xliff:g id="hour" example="3">%-l</xliff:g><xliff:g id="ampm" example="pm">%P</xliff:g>"</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 6e38138..a629bb2 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -676,6 +676,25 @@
     <style name="TextAppearance.Widget.TextView.SpinnerItem">
         <item name="android:textColor">@android:color/primary_text_light_disable_only</item>
     </style>
+    
+    <!-- @hide -->
+    <style name="TextAppearance.SlidingTabNormal" 
+        parent="@android:attr/textAppearanceMedium">
+        <item name="android:textColor">?android:attr/textColorTertiary</item>
+        <item name="android:textSize">28sp</item>
+        <item name="android:shadowColor">@android:color/sliding_tab_text_color_shadow</item>
+        <item name="android:shadowDx">0.0</item>
+        <item name="android:shadowDy">1.0</item>
+        <item name="android:shadowRadius">5.0</item>
+    </style>
+
+    <!-- @hide -->
+    <style name="TextAppearance.SlidingTabActive" 
+        parent="@android:attr/textAppearanceMedium">
+        <item name="android:textColor">@android:color/sliding_tab_text_color_active</item>
+        <item name="android:textSize">28sp</item>
+    </style>
+    
 
     <!-- @hide -->	
      <style name="TextAppearance.SearchResult">	
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 5aef56d..23888ff 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -28,7 +28,6 @@
 #include <GLES/glext.h>
 
 #include <time.h>
-#include <cutils/tztime.h>
 
 using namespace android;
 using namespace android::renderscript;
@@ -444,15 +443,9 @@
     time_t rawtime;
     time(&rawtime);
 
-    if (sc->mEnviroment.mTimeZone) {
-        struct tm timeinfo;
-        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
-        return timeinfo.tm_sec;
-    } else {
-        struct tm *timeinfo;
-        timeinfo = localtime(&rawtime);
-        return timeinfo->tm_sec;
-    }
+    struct tm *timeinfo;
+    timeinfo = localtime(&rawtime);
+    return timeinfo->tm_sec;
 }
 
 static int32_t SC_minute()
@@ -462,15 +455,9 @@
     time_t rawtime;
     time(&rawtime);
 
-    if (sc->mEnviroment.mTimeZone) {
-        struct tm timeinfo;
-        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
-        return timeinfo.tm_min;
-    } else {
-        struct tm *timeinfo;
-        timeinfo = localtime(&rawtime);
-        return timeinfo->tm_min;
-    }
+    struct tm *timeinfo;
+    timeinfo = localtime(&rawtime);
+    return timeinfo->tm_min;
 }
 
 static int32_t SC_hour()
@@ -480,15 +467,9 @@
     time_t rawtime;
     time(&rawtime);
 
-    if (sc->mEnviroment.mTimeZone) {
-        struct tm timeinfo;
-        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
-        return timeinfo.tm_hour;
-    } else {
-        struct tm *timeinfo;
-        timeinfo = localtime(&rawtime);
-        return timeinfo->tm_hour;
-    }
+    struct tm *timeinfo;
+    timeinfo = localtime(&rawtime);
+    return timeinfo->tm_hour;
 }
 
 static int32_t SC_day()
@@ -498,15 +479,9 @@
     time_t rawtime;
     time(&rawtime);
 
-    if (sc->mEnviroment.mTimeZone) {
-        struct tm timeinfo;
-        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
-        return timeinfo.tm_mday;
-    } else {
-        struct tm *timeinfo;
-        timeinfo = localtime(&rawtime);
-        return timeinfo->tm_mday;
-    }
+    struct tm *timeinfo;
+    timeinfo = localtime(&rawtime);
+    return timeinfo->tm_mday;
 }
 
 static int32_t SC_month()
@@ -516,15 +491,9 @@
     time_t rawtime;
     time(&rawtime);
 
-    if (sc->mEnviroment.mTimeZone) {
-        struct tm timeinfo;
-        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
-        return timeinfo.tm_mon;
-    } else {
-        struct tm *timeinfo;
-        timeinfo = localtime(&rawtime);
-        return timeinfo->tm_mon;
-    }
+    struct tm *timeinfo;
+    timeinfo = localtime(&rawtime);
+    return timeinfo->tm_mon;
 }
 
 static int32_t SC_year()
@@ -534,15 +503,9 @@
     time_t rawtime;
     time(&rawtime);
 
-    if (sc->mEnviroment.mTimeZone) {
-        struct tm timeinfo;
-        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
-        return timeinfo.tm_year;
-    } else {
-        struct tm *timeinfo;
-        timeinfo = localtime(&rawtime);
-        return timeinfo->tm_year;
-    }
+    struct tm *timeinfo;
+    timeinfo = localtime(&rawtime);
+    return timeinfo->tm_year;
 }
 
 static int32_t SC_uptimeMillis()
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index f089de1..c2b1b96 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -111,8 +111,17 @@
             try {
                 int newState = Integer.parseInt(event.get("SWITCH_STATE"));
                 if (newState != mDockState) {
+                    int oldState = mDockState;
                     mDockState = newState;
                     if (mSystemReady) {
+                        // Don't force screen on when undocking from the desk dock.
+                        // The change in power state will do this anyway.
+                        // FIXME - we should be configurable.
+                        if (oldState != Intent.EXTRA_DOCK_STATE_DESK ||
+                                newState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+                            mPowerManager.userActivityWithForce(SystemClock.uptimeMillis(),
+                                    false, true);
+                        }
                         update();
                     }
                 }
@@ -166,7 +175,6 @@
                     return;
                 }
                 // Pack up the values and broadcast them to everyone
-                mPowerManager.userActivityWithForce(SystemClock.uptimeMillis(), false, true);
                 Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
                 intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
                 
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index d68ccfa..a885df8 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -56,7 +56,7 @@
      * Turn on some hacks we have to improve the touch interaction with a
      * certain device whose screen currently is not all that good.
      */
-    static final boolean BAD_TOUCH_HACK = true;
+    static boolean BAD_TOUCH_HACK = false;
     
     private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
 
@@ -282,6 +282,9 @@
             lt = new LatencyTimer(100, 1000);
         }
 
+        BAD_TOUCH_HACK = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_filterTouchEvents);
+        
         mHapticFeedbackCallback = hapticFeedbackCallback;
         
         readExcludedDevices();
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index a83459e..39129d4 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -277,7 +277,8 @@
     PackageParser.Package mPlatformPackage;
 
     // Set of pending broadcasts for aggregating enable/disable of components.
-    final HashMap<String, String> mPendingBroadcasts = new HashMap<String, String>();
+    final HashMap<String, ArrayList<String>> mPendingBroadcasts
+            = new HashMap<String, ArrayList<String>>();
     static final int SEND_PENDING_BROADCAST = 1;
     // Delay time in millisecs
     static final int BROADCAST_DELAY = 10 * 1000;
@@ -289,30 +290,40 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case SEND_PENDING_BROADCAST : {
+                    String packages[];
+                    ArrayList components[];
                     int size = 0;
-                    String broadcastList[];
-                    HashMap<String, String> tmpMap;
                     int uids[];
                     synchronized (mPackages) {
+                        if (mPendingBroadcasts == null) {
+                            return;
+                        }
                         size = mPendingBroadcasts.size();
                         if (size <= 0) {
                             // Nothing to be done. Just return
                             return;
                         }
-                        broadcastList = new String[size];
-                        mPendingBroadcasts.keySet().toArray(broadcastList);
-                        tmpMap = new HashMap<String, String>(mPendingBroadcasts);
+                        packages = new String[size];
+                        components = new ArrayList[size];
                         uids = new int[size];
-                        for (int i = 0; i < size; i++) {
-                            PackageSetting ps = mSettings.mPackages.get(mPendingBroadcasts.get(broadcastList[i]));
+                        Iterator<HashMap.Entry<String, ArrayList<String>>>
+                                it = mPendingBroadcasts.entrySet().iterator();
+                        int i = 0;
+                        while (it.hasNext() && i < size) {
+                            HashMap.Entry<String, ArrayList<String>> ent = it.next();
+                            packages[i] = ent.getKey();
+                            components[i] = ent.getValue();
+                            PackageSetting ps = mSettings.mPackages.get(ent.getKey());
                             uids[i] = (ps != null) ? ps.userId : -1;
+                            i++;
                         }
+                        size = i;
                         mPendingBroadcasts.clear();
                     }
                     // Send broadcasts
                     for (int i = 0; i < size; i++) {
-                        String className = broadcastList[i];
-                        sendPackageChangedBroadcast(className, true, tmpMap.get(className), uids[i]);
+                        sendPackageChangedBroadcast(packages[i], true,
+                                (ArrayList<String>)components[i], uids[i]);
                     }
                     break;
                 }
@@ -5023,8 +5034,9 @@
         final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
         boolean sendNow = false;
         boolean isApp = (className == null);
-        String key = isApp ? packageName : className;
+        String componentName = isApp ? packageName : className;
         int packageUid = -1;
+        ArrayList<String> components;
         synchronized (mPackages) {
             pkgSetting = mSettings.mPackages.get(packageName);
             if (pkgSetting == null) {
@@ -5064,17 +5076,22 @@
             }
             mSettings.writeLP();
             packageUid = pkgSetting.userId;
+            components = mPendingBroadcasts.get(packageName);
+            boolean newPackage = components == null;
+            if (newPackage) {
+                components = new ArrayList<String>();
+            }
+            if (!components.contains(componentName)) {
+                components.add(componentName);
+            }
             if ((flags&PackageManager.DONT_KILL_APP) == 0) {
                 sendNow = true;
                 // Purge entry from pending broadcast list if another one exists already
                 // since we are sending one right away.
-                if (mPendingBroadcasts.get(key) != null) {
-                    mPendingBroadcasts.remove(key);
-                    // Can ignore empty list since its handled in the handler anyway
-                }
+                mPendingBroadcasts.remove(packageName);
             } else {
-                if (mPendingBroadcasts.get(key) == null) {
-                    mPendingBroadcasts.put(key, packageName);
+                if (newPackage) {
+                    mPendingBroadcasts.put(packageName, components);
                 }
                 if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) {
                     // Schedule a message
@@ -5087,7 +5104,7 @@
         try {
             if (sendNow) {
                 sendPackageChangedBroadcast(packageName,
-                        (flags&PackageManager.DONT_KILL_APP) != 0, key, packageUid);
+                        (flags&PackageManager.DONT_KILL_APP) != 0, components, packageUid);
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -5095,9 +5112,14 @@
     }
 
     private void sendPackageChangedBroadcast(String packageName,
-            boolean killFlag, String componentName, int packageUid) {
-        Bundle extras = new Bundle(2);
-        extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentName);
+            boolean killFlag, ArrayList<String> componentNames, int packageUid) {
+        if (false) Log.v(TAG, "Sending package changed: package=" + packageName
+                + " components=" + componentNames);
+        Bundle extras = new Bundle(4);
+        extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0));
+        String nameList[] = new String[componentNames.size()];
+        componentNames.toArray(nameList);
+        extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
         extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
         extras.putInt(Intent.EXTRA_UID, packageUid);
         sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras);   
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index c3aeca4..e728091 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -410,6 +410,13 @@
             = new ArrayList<BroadcastRecord>();
 
     /**
+     * Historical data of past broadcasts, for debugging.
+     */
+    static final int MAX_BROADCAST_HISTORY = 100;
+    final BroadcastRecord[] mBroadcastHistory
+            = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+
+    /**
      * Set when we current have a BROADCAST_INTENT_MSG in flight.
      */
     boolean mBroadcastsScheduled = false;
@@ -9392,6 +9399,17 @@
             }
 
             pw.println(" ");
+            pw.println("  Historical broadcasts:");
+            for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
+                BroadcastRecord r = mBroadcastHistory[i];
+                if (r == null) {
+                    break;
+                }
+                pw.println("  Historical Broadcast #" + i + ":");
+                r.dump(pw, "    ");
+            }
+            
+            pw.println(" ");
             pw.println("  mBroadcastsScheduled=" + mBroadcastsScheduled);
             if (mStickyBroadcasts != null) {
                 pw.println(" ");
@@ -11610,7 +11628,7 @@
                     Intent intent = (Intent)allSticky.get(i);
                     BroadcastRecord r = new BroadcastRecord(intent, null,
                             null, -1, -1, null, receivers, null, 0, null, null,
-                            false, true);
+                            false, true, true);
                     if (mParallelBroadcasts.size() == 0) {
                         scheduleBroadcastsLocked();
                     }
@@ -11835,7 +11853,7 @@
             BroadcastRecord r = new BroadcastRecord(intent, callerApp,
                     callerPackage, callingPid, callingUid, requiredPermission,
                     registeredReceivers, resultTo, resultCode, resultData, map,
-                    ordered, false);
+                    ordered, sticky, false);
             if (DEBUG_BROADCAST) Log.v(
                     TAG, "Enqueueing parallel broadcast " + r
                     + ": prev had " + mParallelBroadcasts.size());
@@ -11914,7 +11932,8 @@
                 || resultTo != null) {
             BroadcastRecord r = new BroadcastRecord(intent, callerApp,
                     callerPackage, callingPid, callingUid, requiredPermission,
-                    receivers, resultTo, resultCode, resultData, map, ordered, false);
+                    receivers, resultTo, resultCode, resultData, map, ordered,
+                    sticky, false);
             if (DEBUG_BROADCAST) Log.v(
                     TAG, "Enqueueing ordered broadcast " + r
                     + ": prev had " + mOrderedBroadcasts.size());
@@ -12132,17 +12151,17 @@
             }
             long now = SystemClock.uptimeMillis();
             BroadcastRecord r = mOrderedBroadcasts.get(0);
-            if ((r.startTime+BROADCAST_TIMEOUT) > now) {
+            if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
                 if (DEBUG_BROADCAST) Log.v(TAG,
                         "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
-                        + (r.startTime + BROADCAST_TIMEOUT));
+                        + (r.receiverTime + BROADCAST_TIMEOUT));
                 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
-                mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
+                mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
                 return;
             }
 
             Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
-            r.startTime = now;
+            r.receiverTime = now;
             r.anrCount++;
 
             // Current receiver has passed its expiration date.
@@ -12290,7 +12309,7 @@
                 }
                 performReceive(filter.receiverList.app, filter.receiverList.receiver,
                     new Intent(r.intent), r.resultCode,
-                    r.resultData, r.resultExtras, r.ordered, r.sticky);
+                    r.resultData, r.resultExtras, r.ordered, r.initialSticky);
                 if (ordered) {
                     r.state = BroadcastRecord.CALL_DONE_RECEIVE;
                 }
@@ -12308,6 +12327,17 @@
         }
     }
 
+    private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
+        if (r.callingUid < 0) {
+            // This was from a registerReceiver() call; ignore it.
+            return;
+        }
+        System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
+                MAX_BROADCAST_HISTORY-1);
+        r.finishTime = SystemClock.uptimeMillis();
+        mBroadcastHistory[0] = r;
+    }
+    
     private final void processNextBroadcast(boolean fromMsg) {
         synchronized(this) {
             BroadcastRecord r;
@@ -12325,6 +12355,7 @@
             // First, deliver any non-serialized broadcasts right away.
             while (mParallelBroadcasts.size() > 0) {
                 r = mParallelBroadcasts.remove(0);
+                r.dispatchTime = SystemClock.uptimeMillis();
                 final int N = r.receivers.size();
                 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
                         + r);
@@ -12335,6 +12366,7 @@
                             + target + ": " + r);
                     deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
                 }
+                addBroadcastToHistoryLocked(r);
                 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
                         + r);
             }
@@ -12392,7 +12424,7 @@
                         Log.w(TAG, "Hung broadcast discarded after timeout failure:"
                                 + " now=" + now
                                 + " dispatchTime=" + r.dispatchTime
-                                + " startTime=" + r.startTime
+                                + " startTime=" + r.receiverTime
                                 + " intent=" + r.intent
                                 + " numReceivers=" + numReceivers
                                 + " nextReceiver=" + r.nextReceiver
@@ -12436,6 +12468,7 @@
                             + r);
                     
                     // ... and on to the next...
+                    addBroadcastToHistoryLocked(r);
                     mOrderedBroadcasts.remove(0);
                     r = null;
                     looped = true;
@@ -12448,17 +12481,17 @@
 
             // Keep track of when this receiver started, and make sure there
             // is a timeout message pending to kill it if need be.
-            r.startTime = SystemClock.uptimeMillis();
+            r.receiverTime = SystemClock.uptimeMillis();
             if (recIdx == 0) {
-                r.dispatchTime = r.startTime;
+                r.dispatchTime = r.receiverTime;
 
                 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
                         + r);
                 if (DEBUG_BROADCAST) Log.v(TAG,
                         "Submitting BROADCAST_TIMEOUT_MSG for "
-                        + (r.startTime + BROADCAST_TIMEOUT));
+                        + (r.receiverTime + BROADCAST_TIMEOUT));
                 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
-                mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
+                mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
             }
 
             Object nextReceiver = r.receivers.get(recIdx);
@@ -12801,8 +12834,15 @@
                     }
                 }
                 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
                         null, false, false, MY_PID, Process.SYSTEM_UID);
+                if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
+                    broadcastIntentLocked(null, null,
+                            new Intent(Intent.ACTION_LOCALE_CHANGED),
+                            null, null, 0, null, null,
+                            null, false, false, MY_PID, Process.SYSTEM_UID);
+                }
                 
                 AttributeCache ac = AttributeCache.instance();
                 if (ac != null) {
diff --git a/services/java/com/android/server/am/BroadcastFilter.java b/services/java/com/android/server/am/BroadcastFilter.java
index 0eeb393..2e784d3 100644
--- a/services/java/com/android/server/am/BroadcastFilter.java
+++ b/services/java/com/android/server/am/BroadcastFilter.java
@@ -39,8 +39,16 @@
         receiverList.dumpLocal(pw, prefix);
     }
     
+    public void dumpBrief(PrintWriter pw, String prefix) {
+        dumpBroadcastFilterState(pw, prefix);
+    }
+    
     public void dumpInReceiverList(PrintWriter pw, Printer pr, String prefix) {
         super.dump(pr, prefix);
+        dumpBroadcastFilterState(pw, prefix);
+    }
+    
+    void dumpBroadcastFilterState(PrintWriter pw, String prefix) {
         if (requiredPermission != null) {
             pw.print(prefix); pw.print("requiredPermission="); pw.println(requiredPermission);
         }
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index db0a6cb..75c9600 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -41,11 +41,13 @@
     final int callingUid;   // the uid of who sent this
     final boolean ordered;  // serialize the send to receivers?
     final boolean sticky;   // originated from existing sticky data?
+    final boolean initialSticky; // initial broadcast from register to sticky?
     final String requiredPermission; // a permission the caller has required
     final List receivers;   // contains BroadcastFilter and ResolveInfo
     final IIntentReceiver resultTo; // who receives final result if non-null
     long dispatchTime;      // when dispatch started on this set of receivers
-    long startTime;         // when current receiver started for timeouts.
+    long receiverTime;      // when current receiver started for timeouts.
+    long finishTime;        // when we finished the broadcast.
     int resultCode;         // current result code value.
     String resultData;      // current result data value.
     Bundle resultExtras;    // current result extra data values.
@@ -73,28 +75,55 @@
     void dump(PrintWriter pw, String prefix) {
         pw.println(prefix + this);
         pw.println(prefix + intent);
+        if (sticky) {
+            Bundle bundle = intent.getExtras();
+            if (bundle != null) {
+                pw.println(prefix + "extras: " + bundle.toString());
+            }
+        }
         pw.println(prefix + "proc=" + callerApp);
         pw.println(prefix + "caller=" + callerPackage
                 + " callingPid=" + callingPid
                 + " callingUid=" + callingUid);
-        pw.println(prefix + "requiredPermission=" + requiredPermission);
+        if (requiredPermission != null) {
+            pw.println(prefix + "requiredPermission=" + requiredPermission);
+        }
         pw.println(prefix + "dispatchTime=" + dispatchTime + " ("
-                + (SystemClock.uptimeMillis()-dispatchTime) + " since now)");
-        pw.println(prefix + "startTime=" + startTime + " ("
-                + (SystemClock.uptimeMillis()-startTime) + " since now)");
-        pw.println(prefix + "anrCount=" + anrCount);
-        pw.println(prefix + "resultTo=" + resultTo
-              + " resultCode=" + resultCode + " resultData=" + resultData);
-        pw.println(prefix + "resultExtras=" + resultExtras);
-        pw.println(prefix + "resultAbort=" + resultAbort
-                + " ordered=" + ordered + " sticky=" + sticky);
-        pw.println(prefix + "nextReceiver=" + nextReceiver
-              + " receiver=" + receiver);
-        pw.println(prefix + "curFilter=" + curFilter);
-        pw.println(prefix + "curReceiver="
-                + ((curReceiver != null) ? curReceiver : "(null)"));
-        pw.println(prefix + "curApp=" + curApp);
+                + (SystemClock.uptimeMillis()-dispatchTime) + "ms since now)");
+        if (finishTime != 0) {
+            pw.println(prefix + "finishTime=" + finishTime + " ("
+                    + (SystemClock.uptimeMillis()-finishTime) + "ms since now)");
+        } else {
+            pw.println(prefix + "receiverTime=" + receiverTime + " ("
+                    + (SystemClock.uptimeMillis()-receiverTime) + "ms since now)");
+        }
+        if (anrCount != 0) {
+            pw.println(prefix + "anrCount=" + anrCount);
+        }
+        if (resultTo != null || resultCode != -1 || resultData != null) {
+            pw.println(prefix + "resultTo=" + resultTo
+                  + " resultCode=" + resultCode + " resultData=" + resultData);
+        }
+        if (resultExtras != null) {
+            pw.println(prefix + "resultExtras=" + resultExtras);
+        }
+        if (resultAbort || ordered || sticky || initialSticky) {
+            pw.println(prefix + "resultAbort=" + resultAbort
+                    + " ordered=" + ordered + " sticky=" + sticky
+                    + " initialSticky=" + initialSticky);
+        }
+        if (nextReceiver != 0 || receiver != null) {
+            pw.println(prefix + "nextReceiver=" + nextReceiver
+                  + " receiver=" + receiver);
+        }
+        if (curFilter != null) {
+            pw.println(prefix + "curFilter=" + curFilter);
+        }
+        if (curReceiver != null) {
+            pw.println(prefix + "curReceiver=" + curReceiver);
+        }
         if (curApp != null) {
+            pw.println(prefix + "curApp=" + curApp);
             pw.println(prefix + "curComponent="
                     + (curComponent != null ? curComponent.toShortString() : "--"));
             pw.println(prefix + "curSourceDir=" + curReceiver.applicationInfo.sourceDir);
@@ -114,7 +143,7 @@
             Object o = receivers.get(i);
             pw.println(prefix + "Receiver #" + i + ": " + o);
             if (o instanceof BroadcastFilter)
-                ((BroadcastFilter)o).dump(pw, p2);
+                ((BroadcastFilter)o).dumpBrief(pw, p2);
             else if (o instanceof ResolveInfo)
                 ((ResolveInfo)o).dump(printer, p2);
         }
@@ -124,7 +153,7 @@
             int _callingPid, int _callingUid, String _requiredPermission,
             List _receivers, IIntentReceiver _resultTo, int _resultCode,
             String _resultData, Bundle _resultExtras, boolean _serialized,
-            boolean _sticky) {
+            boolean _sticky, boolean _initialSticky) {
         intent = _intent;
         callerApp = _callerApp;
         callerPackage = _callerPackage;
@@ -138,6 +167,7 @@
         resultExtras = _resultExtras;
         ordered = _serialized;
         sticky = _sticky;
+        initialSticky = _initialSticky;
         nextReceiver = 0;
         state = IDLE;
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index c16b04d..aee45bff 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -41,6 +41,7 @@
 import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.SmsMessageBase;
 import com.android.internal.telephony.SMSDispatcher;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
 import com.android.internal.telephony.cdma.SmsMessage;
 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
 import com.android.internal.telephony.cdma.sms.UserData;
@@ -366,8 +367,19 @@
          */
 
         int refNumber = getNextConcatenatedRef() & 0x00FF;
+        int msgCount = parts.size();
+        int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN;
 
-        for (int i = 0, msgCount = parts.size(); i < msgCount; i++) {
+        for (int i = 0; i < msgCount; i++) {
+            TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false);
+            if (encoding != details.codeUnitSize
+                    && (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN
+                            || encoding == android.telephony.SmsMessage.ENCODING_7BIT)) {
+                encoding = details.codeUnitSize;
+            }
+        }
+
+        for (int i = 0; i < msgCount; i++) {
             SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
             concatRef.refNumber = refNumber;
             concatRef.seqNumber = i + 1;  // 1-based sequence
@@ -389,6 +401,12 @@
             UserData uData = new UserData();
             uData.payloadStr = parts.get(i);
             uData.userDataHeader = smsHeader;
+            if (encoding == android.telephony.SmsMessage.ENCODING_7BIT) {
+                uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
+            } else { // assume UTF-16
+                uData.msgEncoding = UserData.ENCODING_UNICODE_16;
+            }
+            uData.msgEncodingSet = true;
 
             /* By setting the statusReportRequested bit only for the
              * last message fragment, this will result in only one
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 3051e2f..bb3f2a7 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -67,6 +67,15 @@
     CdmaCellLocation cellLoc;
     CdmaCellLocation newCellLoc;
 
+     /** if time between NTIZ updates is less than mNitzUpdateSpacing the update may be ignored. */
+    private static final int NITZ_UPDATE_SPACING_DEFAULT = 1000 * 60 * 10;
+    private int mNitzUpdateSpacing = SystemProperties.getInt("ro.nitz_update_spacing",
+            NITZ_UPDATE_SPACING_DEFAULT);
+
+    /** If mNitzUpdateSpacing hasn't been exceeded but update is > mNitzUpdate do the update */
+    private static final int NITZ_UPDATE_DIFF_DEFAULT = 2000;
+    private int mNitzUpdateDiff = SystemProperties.getInt("ro.nitz_update_diff",
+            NITZ_UPDATE_DIFF_DEFAULT);
     /**
      *  Values correspond to ServiceStateTracker.DATA_ACCESS_ definitions.
      */
@@ -1420,45 +1429,62 @@
             try {
                 mWakeLock.acquire();
 
+                /**
+                 * Correct the NITZ time by how long its taken to get here.
+                 */
+                long millisSinceNitzReceived
+                        = SystemClock.elapsedRealtime() - nitzReceiveTime;
+
+                if (millisSinceNitzReceived < 0) {
+                    // Sanity check: something is wrong
+                    Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled "
+                                        + "backwards since NITZ time was received, "
+                                        + nitz);
+                    return;
+                }
+
+                if (millisSinceNitzReceived > Integer.MAX_VALUE) {
+                    // If the time is this far off, something is wrong > 24 days!
+                    Log.i(LOG_TAG, "NITZ: not setting time, processing has taken "
+                                    + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
+                                    + " days");
+                    return;
+                }
+
+                // Note: with range checks above, cast to int is safe
+                c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
+
                 if (getAutoTime()) {
-                    long millisSinceNitzReceived
-                            = SystemClock.elapsedRealtime() - nitzReceiveTime;
+                    /**
+                     * Update system time automatically
+                     */
+                    long gained = c.getTimeInMillis() - System.currentTimeMillis();
+                    long timeSinceLastUpdate = SystemClock.elapsedRealtime() - mSavedAtTime;
 
-                    if (millisSinceNitzReceived < 0) {
-                        // Sanity check: something is wrong
-                        Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled "
-                                            + "backwards since NITZ time was received, "
-                                            + nitz);
+                    if ((timeSinceLastUpdate > mNitzUpdateSpacing)
+                            || (Math.abs(gained) > mNitzUpdateDiff)) {
+                        Log.i(LOG_TAG, "NITZ: Auto updating time of day to " + c.getTime()
+                                + " NITZ receive delay=" + millisSinceNitzReceived
+                                + "ms gained=" + gained + "ms from " + nitz);
+
+                        setAndBroadcastNetworkSetTime(c.getTimeInMillis());
+                    } else {
+                        Log.i(LOG_TAG, "NITZ: ignore, a previous update was "
+                                + timeSinceLastUpdate + "ms ago and gained=" + gained + "ms");
                         return;
                     }
-
-                    if (millisSinceNitzReceived > Integer.MAX_VALUE) {
-                        // If the time is this far off, something is wrong > 24 days!
-                        Log.i(LOG_TAG, "NITZ: not setting time, processing has taken "
-                                        + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
-                                        + " days");
-                        return;
-                    }
-
-                    // Note: with range checks above, cast to int is safe
-                    c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
-
-                    Log.i(LOG_TAG, "NITZ: Setting time of day to " + c.getTime()
-                            + " NITZ receive delay(ms): " + millisSinceNitzReceived
-                        + " gained(ms): "
-                        + (c.getTimeInMillis() - System.currentTimeMillis())
-                            + " from " + nitz);
-
-                    setAndBroadcastNetworkSetTime(c.getTimeInMillis());
-                    Log.i(LOG_TAG, "NITZ: after Setting time of day");
                 }
+
+                /**
+                 * Update properties and save the time we did the update
+                 */
+                Log.i(LOG_TAG, "NITZ: update nitz time property");
                 SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
-                saveNitzTime(c.getTimeInMillis());
-                if (Config.LOGV) {
-                    long end = SystemClock.elapsedRealtime();
-                    Log.v(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start));
-                }
+                mSavedTime = c.getTimeInMillis();
+                mSavedAtTime = SystemClock.elapsedRealtime();
             } finally {
+                long end = SystemClock.elapsedRealtime();
+                Log.i(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start));
                 mWakeLock.release();
             }
         } catch (RuntimeException ex) {
@@ -1479,11 +1505,6 @@
         mSavedTimeZone = zoneId;
     }
 
-    private void saveNitzTime(long time) {
-        mSavedTime = time;
-        mSavedAtTime = SystemClock.elapsedRealtime();
-    }
-
     /**
      * Set the timezone and send out a sticky broadcast so the system can
      * determine if the timezone was set by the carrier.
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index 0ca3148..6ae316d 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -28,6 +28,7 @@
 import android.util.Log;
 
 import com.android.internal.telephony.IccUtils;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
 import com.android.internal.telephony.gsm.SmsMessage;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.SMSDispatcher;
@@ -165,8 +166,19 @@
             ArrayList<PendingIntent> deliveryIntents) {
 
         int refNumber = getNextConcatenatedRef() & 0x00FF;
+        int msgCount = parts.size();
+        int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN;
 
-        for (int i = 0, msgCount = parts.size(); i < msgCount; i++) {
+        for (int i = 0; i < msgCount; i++) {
+            TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false);
+            if (encoding != details.codeUnitSize
+                    && (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN
+                            || encoding == android.telephony.SmsMessage.ENCODING_7BIT)) {
+                encoding = details.codeUnitSize;
+            }
+        }
+
+        for (int i = 0; i < msgCount; i++) {
             SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
             concatRef.refNumber = refNumber;
             concatRef.seqNumber = i + 1;  // 1-based sequence
@@ -192,7 +204,8 @@
             }
 
             SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
-                    parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader));
+                    parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader),
+                    encoding);
 
             sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent);
         }
@@ -242,8 +255,19 @@
         }
 
         int refNumber = getNextConcatenatedRef() & 0x00FF;
+        int msgCount = parts.size();
+        int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN;
 
-        for (int i = 0, msgCount = parts.size(); i < msgCount; i++) {
+        for (int i = 0; i < msgCount; i++) {
+            TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false);
+            if (encoding != details.codeUnitSize
+                    && (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN
+                            || encoding == android.telephony.SmsMessage.ENCODING_7BIT)) {
+                encoding = details.codeUnitSize;
+            }
+        }
+
+        for (int i = 0; i < msgCount; i++) {
             SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
             concatRef.refNumber = refNumber;
             concatRef.seqNumber = i + 1;  // 1-based sequence
@@ -263,7 +287,8 @@
             }
 
             SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
-                    parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader));
+                    parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader),
+                    encoding);
 
             HashMap<String, Object> map = new HashMap<String, Object>();
             map.put("smsc", pdus.encodedScAddress);
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 569cf25..ebd60a9 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -225,6 +225,25 @@
     public static SubmitPdu getSubmitPdu(String scAddress,
             String destinationAddress, String message,
             boolean statusReportRequested, byte[] header) {
+        return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, header,
+                ENCODING_UNKNOWN);
+    }
+
+
+    /**
+     * Get an SMS-SUBMIT PDU for a destination address and a message using the
+     * specified encoding.
+     *
+     * @param scAddress Service Centre address.  Null means use default.
+     * @param encoding Encoding defined by constants in android.telephony.SmsMessage.ENCODING_*
+     * @return a <code>SubmitPdu</code> containing the encoded SC
+     *         address, if applicable, and the encoded message.
+     *         Returns null on encode error.
+     * @hide
+     */
+    public static SubmitPdu getSubmitPdu(String scAddress,
+            String destinationAddress, String message,
+            boolean statusReportRequested, byte[] header, int encoding) {
 
         // Perform null parameter checks.
         if (message == null || destinationAddress == null) {
@@ -237,18 +256,43 @@
         ByteArrayOutputStream bo = getSubmitPduHead(
                 scAddress, destinationAddress, mtiByte,
                 statusReportRequested, ret);
-
-        try {
+        // User Data (and length)
+        byte[] userData;
+        if (encoding == ENCODING_UNKNOWN) {
             // First, try encoding it with the GSM alphabet
+            encoding = ENCODING_7BIT;
+        }
+        try {
+            if (encoding == ENCODING_7BIT) {
+                userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header);
+            } else { //assume UCS-2
+                try {
+                    userData = encodeUCS2(message, header);
+                } catch(UnsupportedEncodingException uex) {
+                    Log.e(LOG_TAG,
+                            "Implausible UnsupportedEncodingException ",
+                            uex);
+                    return null;
+                }
+            }
+        } catch (EncodeException ex) {
+            // Encoding to the 7-bit alphabet failed. Let's see if we can
+            // send it as a UCS-2 encoded message
+            try {
+                userData = encodeUCS2(message, header);
+            } catch(UnsupportedEncodingException uex) {
+                Log.e(LOG_TAG,
+                        "Implausible UnsupportedEncodingException ",
+                        uex);
+                return null;
+            }
+        }
 
-            // User Data (and length)
-            byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header);
-
+        if (encoding == ENCODING_7BIT) {
             if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) {
                 // Message too long
                 return null;
             }
-
             // TP-Data-Coding-Scheme
             // Default encoding, uncompressed
             // To test writing messages to the SIM card, change this value 0x00
@@ -258,58 +302,51 @@
             // the receiver's SIM card. You can then send messages to yourself
             // (on a phone with this change) and they'll end up on the SIM card.
             bo.write(0x00);
-
-            // (no TP-Validity-Period)
-
-            bo.write(userData, 0, userData.length);
-        } catch (EncodeException ex) {
-            byte[] userData, textPart;
-            // Encoding to the 7-bit alphabet failed. Let's see if we can
-            // send it as a UCS-2 encoded message
-
-            try {
-                textPart = message.getBytes("utf-16be");
-            } catch (UnsupportedEncodingException uex) {
-                Log.e(LOG_TAG,
-                      "Implausible UnsupportedEncodingException ",
-                      uex);
-                return null;
-            }
-
-            if (header != null) {
-                // Need 1 byte for UDHL
-                userData = new byte[header.length + textPart.length + 1];
-
-                userData[0] = (byte)header.length;
-                System.arraycopy(header, 0, userData, 1, header.length);
-                System.arraycopy(textPart, 0, userData, header.length + 1, textPart.length);
-            }
-            else {
-                userData = textPart;
-            }
-
-            if (userData.length > MAX_USER_DATA_BYTES) {
+        } else { //assume UCS-2
+            if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) {
                 // Message too long
                 return null;
             }
-
             // TP-Data-Coding-Scheme
             // Class 3, UCS-2 encoding, uncompressed
             bo.write(0x0b);
-
-            // (no TP-Validity-Period)
-
-            // TP-UDL
-            bo.write(userData.length);
-
-            bo.write(userData, 0, userData.length);
         }
 
+        // (no TP-Validity-Period)
+        bo.write(userData, 0, userData.length);
         ret.encodedMessage = bo.toByteArray();
         return ret;
     }
 
     /**
+     * Packs header and UCS-2 encoded message. Includes TP-UDL & TP-UDHL if necessary
+     *
+     * @return
+     * @throws UnsupportedEncodingException
+     */
+    private static byte[] encodeUCS2(String message, byte[] header)
+        throws UnsupportedEncodingException {
+        byte[] userData, textPart;
+        textPart = message.getBytes("utf-16be");
+
+        if (header != null) {
+            // Need 1 byte for UDHL
+            userData = new byte[header.length + textPart.length + 1];
+
+            userData[0] = (byte)header.length;
+            System.arraycopy(header, 0, userData, 1, header.length);
+            System.arraycopy(textPart, 0, userData, header.length + 1, textPart.length);
+        }
+        else {
+            userData = textPart;
+        }
+        byte[] ret = new byte[userData.length+1];
+        ret[0] = (byte) (userData.length & 0xff );
+        System.arraycopy(userData, 0, ret, 1, userData.length);
+        return ret;
+    }
+
+    /**
      * Get an SMS-SUBMIT PDU for a destination address and a message
      *
      * @param scAddress Service Centre address.  Null means use default.