Merge change Ie122606f into eclair
* changes:
Add code to use Gservices provided values for throtting NITZ updates.
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=""android.intent.action.LOCALE_CHANGED""
+ 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=""android.intent.extra.changed_component_name_list""
+ 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/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index e98b286..f606346 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -195,7 +195,12 @@
if (mDefaultWallpaper != null) {
return mDefaultWallpaper;
}
- mWallpaper = getCurrentWallpaperLocked(context);
+ mWallpaper = null;
+ try {
+ mWallpaper = getCurrentWallpaperLocked(context);
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "No memory load current wallpaper", e);
+ }
if (mWallpaper == null && returnDefault) {
mDefaultWallpaper = getDefaultWallpaperLocked(context);
return mDefaultWallpaper;
@@ -279,7 +284,12 @@
} catch (IOException e) {
}
- return generateBitmap(context, bm, width, height);
+ try {
+ return generateBitmap(context, bm, width, height);
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "Can't generate default bitmap", e);
+ return bm;
+ }
}
} catch (RemoteException e) {
}
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("limit", "3")
+ * .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, "Mike Sullivan");
+ * 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<ContentProviderOperation> 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, "Mike Sullivan")
+ * .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 + "<>0", null, null, null);
+ * ...
+ * Cursor c2 = getContentResolver().query(rawContactUri,
+ * RawContacts.DELETED + "<>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<ContentProviderOperation> 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<ContentProviderOperation> 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<ContentProviderOperation> 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 + "=?" + " 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 + "=?" + " 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<ContentProviderOperation> 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, "Bob Parr")
+ * .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/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index d1dd311..70af91f 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -502,10 +502,14 @@
// List of names of Bluetooth devices for which auto pairing should be
// disabled.
- private final ArrayList<String> mAutoPairingNameBlacklist =
+ private final ArrayList<String> mAutoPairingExactNameBlacklist =
new ArrayList<String>(Arrays.asList(
"Motorola IHF1000", "i.TechBlueBAND", "X5 Stereo v1.3"));
+ private final ArrayList<String> mAutoPairingPartialNameBlacklist =
+ new ArrayList<String>(Arrays.asList(
+ "BMW", "Audi"));
+
// If this is an outgoing connection, store the address.
// There can be only 1 pending outgoing connection at a time,
private String mPendingOutgoingBonding;
@@ -585,9 +589,13 @@
String name = getRemoteName(address);
if (name != null) {
- for (String blacklistName : mAutoPairingNameBlacklist) {
+ for (String blacklistName : mAutoPairingExactNameBlacklist) {
if (name.equals(blacklistName)) return true;
}
+
+ for (String blacklistName : mAutoPairingPartialNameBlacklist) {
+ if (name.startsWith(blacklistName)) return true;
+ }
}
return false;
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index a8d9f1d..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
@@ -1595,7 +1595,7 @@
* @param scaleInPercent The initial scale in percent.
*/
public void setInitialScale(int scaleInPercent) {
- mInitialScale = scaleInPercent;
+ mInitialScaleInPercent = scaleInPercent;
}
/**
@@ -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
@@ -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/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
index c09ecfb..251ecbc 100644
--- a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -24,6 +24,7 @@
import android.os.HandlerThread;
import android.os.Process;
import android.service.wallpaper.WallpaperService;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.content.Context;
@@ -134,8 +135,8 @@
final Drawable background = mBackground;
final int dw = frame.width();
final int dh = frame.height();
- final int bw = mBackground.getIntrinsicWidth();
- final int bh = mBackground.getIntrinsicHeight();
+ final int bw = background != null ? background.getIntrinsicWidth() : 0;
+ final int bh = background != null ? background.getIntrinsicHeight() : 0;
final int availw = dw-bw;
final int availh = dh-bh;
int xPixels = availw < 0 ? (int)(availw*mXOffset+.5f) : (availw/2);
@@ -148,7 +149,9 @@
c.drawColor(0xff000000);
c.restore();
}
- background.draw(c);
+ if (background != null) {
+ background.draw(c);
+ }
}
sh.unlockCanvasAndPost(c);
}
@@ -156,7 +159,11 @@
void updateWallpaper() {
synchronized (mLock) {
- mBackground = mWallpaperManager.getFastDrawable();
+ try {
+ mBackground = mWallpaperManager.getFastDrawable();
+ } catch (RuntimeException e) {
+ Log.w("ImageWallpaper", "Unable to load wallpaper!", e);
+ }
}
}
}
diff --git a/core/java/com/android/internal/widget/DigitalClock.java b/core/java/com/android/internal/widget/DigitalClock.java
new file mode 100644
index 0000000..ca71722
--- /dev/null
+++ b/core/java/com/android/internal/widget/DigitalClock.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import com.android.internal.R;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.graphics.Typeface;
+import android.os.Handler;
+import android.provider.Settings;
+import android.text.format.DateFormat;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.text.DateFormatSymbols;
+import java.util.Calendar;
+
+/**
+ * Displays the time
+ */
+public class DigitalClock extends LinearLayout {
+
+ private final static String M12 = "h:mm";
+ private final static String M24 = "kk:mm";
+
+ private Calendar mCalendar;
+ private String mFormat;
+ private TextView mTimeDisplay;
+ private AmPm mAmPm;
+ private ContentObserver mFormatChangeObserver;
+ private boolean mLive = true;
+ private boolean mAttached;
+
+ /* called by system on minute ticks */
+ private final Handler mHandler = new Handler();
+ private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mLive && intent.getAction().equals(
+ Intent.ACTION_TIMEZONE_CHANGED)) {
+ mCalendar = Calendar.getInstance();
+ }
+ updateTime();
+ }
+ };
+
+ static class AmPm {
+ private TextView mAmPm;
+ private String mAmString, mPmString;
+
+ AmPm(View parent, Typeface tf) {
+ mAmPm = (TextView) parent.findViewById(R.id.am_pm);
+ if (tf != null) {
+ mAmPm.setTypeface(tf);
+ }
+
+ String[] ampm = new DateFormatSymbols().getAmPmStrings();
+ mAmString = ampm[0];
+ mPmString = ampm[1];
+ }
+
+ void setShowAmPm(boolean show) {
+ mAmPm.setVisibility(show ? View.VISIBLE : View.GONE);
+ }
+
+ void setIsMorning(boolean isMorning) {
+ mAmPm.setText(isMorning ? mAmString : mPmString);
+ }
+ }
+
+ private class FormatChangeObserver extends ContentObserver {
+ public FormatChangeObserver() {
+ super(new Handler());
+ }
+ @Override
+ public void onChange(boolean selfChange) {
+ setDateFormat();
+ updateTime();
+ }
+ }
+
+ public DigitalClock(Context context) {
+ this(context, null);
+ }
+
+ public DigitalClock(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mTimeDisplay = (TextView) findViewById(R.id.timeDisplay);
+ mTimeDisplay.setTypeface(Typeface.createFromFile("/system/fonts/Clockopia.ttf"));
+ mAmPm = new AmPm(this, Typeface.createFromFile("/system/fonts/DroidSans-Bold.ttf"));
+ mCalendar = Calendar.getInstance();
+
+ setDateFormat();
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (mAttached) return;
+ mAttached = true;
+
+ if (mLive) {
+ /* monitor time ticks, time changed, timezone */
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_TIME_TICK);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
+ }
+
+ /* monitor 12/24-hour display preference */
+ mFormatChangeObserver = new FormatChangeObserver();
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.CONTENT_URI, true, mFormatChangeObserver);
+
+ updateTime();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ if (!mAttached) return;
+ mAttached = false;
+
+ if (mLive) {
+ mContext.unregisterReceiver(mIntentReceiver);
+ }
+ mContext.getContentResolver().unregisterContentObserver(
+ mFormatChangeObserver);
+ }
+
+
+ void updateTime(Calendar c) {
+ mCalendar = c;
+ updateTime();
+ }
+
+ private void updateTime() {
+ if (mLive) {
+ mCalendar.setTimeInMillis(System.currentTimeMillis());
+ }
+
+ CharSequence newTime = DateFormat.format(mFormat, mCalendar);
+ mTimeDisplay.setText(newTime);
+ mAmPm.setIsMorning(mCalendar.get(Calendar.AM_PM) == 0);
+ }
+
+ private void setDateFormat() {
+ mFormat = android.text.format.DateFormat.is24HourFormat(getContext())
+ ? M24 : M12;
+ mAmPm.setShowAmPm(mFormat.equals(M12));
+ }
+
+ void setLive(boolean live) {
+ mLive = live;
+ }
+}
diff --git a/core/java/com/android/internal/widget/SlidingTab.java b/core/java/com/android/internal/widget/SlidingTab.java
index 6bcecc3..4a411d7 100644
--- a/core/java/com/android/internal/widget/SlidingTab.java
+++ b/core/java/com/android/internal/widget/SlidingTab.java
@@ -20,6 +20,7 @@
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;
@@ -36,11 +37,15 @@
/**
* 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.
+ * the threshold will cause the registered OnTriggerListener.onTrigger() to be called with
+ * whichHandle being {@link OnTriggerListener#LEFT_HANDLE} or {@link OnTriggerListener#RIGHT_HANDLE}
+ * Equivalently, selecting a tab will result in a call to
+ * {@link OnTriggerListener#onGrabbedStateChange(View, int)} with one of these two states. Releasing
+ * the tab will result in whichHandle being {@link OnTriggerListener#NO_HANDLE}.
*
*/
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
@@ -48,7 +53,7 @@
private static final int MSG_ANIMATE = 100;
// TODO: Make these configurable
- private static final float TARGET_ZONE = 2.0f / 3.0f;
+ private static final float THRESHOLD = 2.0f / 3.0f;
private static final long VIBRATE_SHORT = 30;
private static final long VIBRATE_LONG = 40;
@@ -69,35 +74,35 @@
private Slider mRightSlider;
private Slider mCurrentSlider;
private boolean mTracking;
- private float mTargetZone;
+ private float mThreshold;
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.
+ * by moving it beyond a threshold.
*/
public interface OnTriggerListener {
/**
* The interface was triggered because the user let go of the handle without reaching the
- * target zone.
+ * threshold.
*/
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.
+ * the threshold.
*/
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.
+ * the threshold.
*/
public static final int RIGHT_HANDLE = 2;
/**
- * Called when the user moves a handle beyond the target zone.
+ * Called when the user moves a handle beyond the threshold.
*
* @param v The view that was triggered.
* @param whichHandle Which "dial handle" the user grabbed,
@@ -144,6 +149,7 @@
private final ImageView tab;
private final TextView text;
private final ImageView target;
+ private int currentState = STATE_NORMAL;
/**
* Constructor
@@ -221,6 +227,7 @@
} else {
text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabNormal);
}
+ currentState = state;
}
void showTarget() {
@@ -249,15 +256,17 @@
* @param alignment which side to align the widget to
*/
void layout(int l, int t, int r, int b, int alignment) {
- final int handleWidth = tab.getBackground().getIntrinsicWidth();
- final int handleHeight = tab.getBackground().getIntrinsicHeight();
- final int targetWidth = target.getDrawable().getIntrinsicWidth();
- final int targetHeight = target.getDrawable().getIntrinsicHeight();
+ 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 leftTarget = (int) (THRESHOLD * parentWidth) - targetWidth + handleWidth / 2;
+ final int rightTarget = (int) ((1.0f - THRESHOLD) * parentWidth) - handleWidth / 2;
final int left = (parentWidth - handleWidth) / 2;
final int right = left + handleWidth;
@@ -282,8 +291,8 @@
// 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;
+ final int top = (int) (THRESHOLD * parentHeight) + handleHeight / 2 - targetHeight;
+ final int bottom = (int) ((1.0f - THRESHOLD) * parentHeight) - handleHeight / 2;
if (alignment == ALIGN_TOP) {
tab.layout(left, 0, right, handleHeight);
text.layout(left, 0 - parentHeight, right, 0);
@@ -296,6 +305,10 @@
}
}
+ public void updateDrawableStates() {
+ setState(currentState);
+ }
+
public int getTabWidth() {
return tab.getDrawable().getIntrinsicWidth();
}
@@ -347,10 +360,11 @@
throw new RuntimeException(LOG_TAG + " cannot have UNSPECIFIED dimensions");
}
- final int leftTabWidth = (int) (mDensity * mLeftSlider.getTabWidth() + 0.5f);
- final int rightTabWidth = (int) (mDensity * mRightSlider.getTabWidth() + 0.5f);
- final int leftTabHeight = (int) (mDensity * mLeftSlider.getTabHeight() + 0.5f);
- final int rightTabHeight = (int) (mDensity * mRightSlider.getTabHeight() + 0.5f);
+ 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()) {
@@ -395,12 +409,12 @@
if (leftHit) {
mCurrentSlider = mLeftSlider;
mOtherSlider = mRightSlider;
- mTargetZone = isHorizontal() ? TARGET_ZONE : 1.0f - TARGET_ZONE;
+ mThreshold = isHorizontal() ? THRESHOLD : 1.0f - THRESHOLD;
setGrabbedState(OnTriggerListener.LEFT_HANDLE);
} else {
mCurrentSlider = mRightSlider;
mOtherSlider = mLeftSlider;
- mTargetZone = isHorizontal() ? 1.0f - TARGET_ZONE : TARGET_ZONE;
+ mThreshold = isHorizontal() ? 1.0f - THRESHOLD : THRESHOLD;
setGrabbedState(OnTriggerListener.RIGHT_HANDLE);
}
mCurrentSlider.setState(Slider.STATE_PRESSED);
@@ -424,16 +438,16 @@
case MotionEvent.ACTION_MOVE:
moveHandle(x, y);
float position = isHorizontal() ? x : y;
- float target = mTargetZone * (isHorizontal() ? getWidth() : getHeight());
- boolean targetZoneReached;
+ float target = mThreshold * (isHorizontal() ? getWidth() : getHeight());
+ boolean thresholdReached;
if (isHorizontal()) {
- targetZoneReached = mCurrentSlider == mLeftSlider ?
+ thresholdReached = mCurrentSlider == mLeftSlider ?
position > target : position < target;
} else {
- targetZoneReached = mCurrentSlider == mLeftSlider ?
+ thresholdReached = mCurrentSlider == mLeftSlider ?
position < target : position > target;
}
- if (!mTriggered && targetZoneReached) {
+ if (!mTriggered && thresholdReached) {
mTriggered = true;
mTracking = false;
mCurrentSlider.setState(Slider.STATE_ACTIVE);
@@ -441,14 +455,14 @@
OnTriggerListener.LEFT_HANDLE : OnTriggerListener.RIGHT_HANDLE);
// TODO: This is a place holder for the real animation. It just holds
- // the screen for 500ms.
+ // the screen for the duration of the animation for now.
mAnimating = true;
mHandler.postDelayed(new Runnable() {
public void run() {
resetView();
mAnimating = false;
}
- }, 500);
+ }, ANIMATION_DURATION);
}
if (isHorizontal() && (y <= handle.getBottom() && y >= handle.getTop()) ||
@@ -522,6 +536,7 @@
mLeftSlider.setTarget(targetId);
mLeftSlider.setBarBackgroundResource(barId);
mLeftSlider.setTabBackgroundResource(tabId);
+ mLeftSlider.updateDrawableStates();
}
/**
@@ -549,6 +564,7 @@
mRightSlider.setTarget(targetId);
mRightSlider.setBarBackgroundResource(barId);
mRightSlider.setTabBackgroundResource(tabId);
+ mRightSlider.updateDrawableStates();
}
/**
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/blank_tile.png b/core/res/res/drawable-hdpi/blank_tile.png
index e2a386c..63b9296 100644
--- a/core/res/res/drawable-hdpi/blank_tile.png
+++ b/core/res/res/drawable-hdpi/blank_tile.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/loading_tile.png b/core/res/res/drawable-hdpi/loading_tile.png
index 691ca45..f5a80c9 100644
--- a/core/res/res/drawable-hdpi/loading_tile.png
+++ b/core/res/res/drawable-hdpi/loading_tile.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/no_tile_128.png b/core/res/res/drawable-hdpi/no_tile_128.png
index 86b998d..a9b007d 100644
--- a/core/res/res/drawable-hdpi/no_tile_128.png
+++ b/core/res/res/drawable-hdpi/no_tile_128.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_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_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_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/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
index 84b5751..6f7010e 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -38,58 +38,80 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
- android:layout_marginTop="20dip"
+ android:layout_alignParentRight="true"
+ android:layout_marginTop="16dip"
+ android:layout_marginRight="16dip"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
/>
- <TextView
- android:id="@+id/time"
+ <!-- time and date -->
+ <com.android.internal.widget.DigitalClock 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"
- />
+ android:layout_marginBottom="8dip"
+ android:layout_marginTop="16dip"
+ android:layout_marginLeft="24dip"
+ >
+
+ <TextView android:id="@+id/timeDisplay"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="bottom"
+ android:textSize="72sp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:shadowColor="#C0000000"
+ android:shadowDx="0"
+ android:shadowDy="0"
+ android:shadowRadius="3.0"
+ />
+
+
+ <TextView android:id="@+id/am_pm"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:gravity="bottom"
+ android:textSize="22sp"
+ android:singleLine="true"
+ android:layout_marginLeft="8dip"
+ android:layout_marginBottom="-6dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:shadowColor="#C0000000"
+ android:shadowDx="0"
+ android:shadowDy="0"
+ android:shadowRadius="3.0"
+ />
+
+ </com.android.internal.widget.DigitalClock>
<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:layout_marginLeft="24dip"
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_below="@id/date"
android:layout_marginTop="6dip"
+ android:layout_marginLeft="24dip"
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:layout_marginLeft="24dip"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
android:drawablePadding="4dip"
/>
@@ -98,9 +120,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/status2"
+ android:layout_marginLeft="24dip"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
- android:gravity="center"
android:layout_marginTop="12dip"
/>
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index 6aed301..a9edb6b 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -33,7 +33,8 @@
android:layout_width="0dip"
android:layout_height="fill_parent"
android:layout_weight="1.0"
- android:gravity="center_horizontal">
+ android:layout_marginLeft="24dip"
+ android:gravity="left">
<TextView
android:id="@+id/carrier"
@@ -42,45 +43,62 @@
android:layout_alignParentTop="true"
android:layout_marginTop="20dip"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
/>
- <TextView
- android:id="@+id/time"
+ <com.android.internal.widget.DigitalClock 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"
- />
+ android:layout_marginBottom="8dip"
+ android:layout_marginTop="56dip"
+ >
+
+ <TextView android:id="@+id/timeDisplay"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="bottom"
+ android:textSize="72sp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:shadowColor="#C0000000"
+ android:shadowDx="0"
+ android:shadowDy="0"
+ android:shadowRadius="3.0"
+ />
+
+
+ <TextView android:id="@+id/am_pm"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:gravity="bottom"
+ android:textSize="22sp"
+ android:singleLine="true"
+ android:layout_marginLeft="8dip"
+ android:layout_marginBottom="-6dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:shadowColor="#C0000000"
+ android:shadowDx="0"
+ android:shadowDy="0"
+ android:shadowRadius="3.0"
+ />
+
+ </com.android.internal.widget.DigitalClock>
<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:layout_marginTop="6dip"
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_below="@id/date"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
android:drawablePadding="4dip"
/>
@@ -91,7 +109,6 @@
android:layout_below="@id/status1"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
android:drawablePadding="4dip"
/>
@@ -101,7 +118,6 @@
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"
/>
@@ -124,7 +140,7 @@
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
- android:layout_marginBottom="50dip"
+ android:layout_marginRight="50dip"
/>
</LinearLayout>
diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
index 3e00ae8e1..6da82e9 100644
--- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
@@ -35,56 +35,73 @@
android:layout_width="0dip"
android:layout_height="fill_parent"
android:layout_weight="1.0"
- android:gravity="center_horizontal"
+ android:layout_marginLeft="24dip"
+ android:gravity="left"
>
<TextView
+ android:id="@+id/status1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ />
+
+ <TextView
android:id="@+id/carrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="5dip"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
- />
- <TextView
- android:id="@+id/centerDot"
- android:visibility="gone"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="5dip"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
android:textSize="17sp"
+ android:drawablePadding="4dip"
+ android:layout_marginTop="32dip"
/>
- <TextView
- android:id="@+id/time"
+ <com.android.internal.widget.DigitalClock android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:layout_marginTop="5dip"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:textSize="35sp"
- />
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_marginBottom="8dip"
+ android:layout_marginTop="8dip"
+ >
+
+ <TextView android:id="@+id/timeDisplay"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="bottom"
+ android:textSize="72sp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:shadowColor="#C0000000"
+ android:shadowDx="0"
+ android:shadowDy="0"
+ android:shadowRadius="3.0"
+ />
+
+
+ <TextView android:id="@+id/am_pm"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:gravity="bottom"
+ android:textSize="22sp"
+ android:singleLine="true"
+ android:layout_marginLeft="8dip"
+ android:layout_marginBottom="-6dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:shadowColor="#C0000000"
+ android:shadowDx="0"
+ android:shadowDy="0"
+ android:shadowRadius="3.0"
+ />
+
+ </com.android.internal.widget.DigitalClock>
+
<TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_marginTop="-12dip"
+ android:layout_below="@id/time"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="17sp"
/>
-
- <View
- android:id="@+id/divider"
- android:layout_width="fill_parent"
- android:layout_height="1dip"
- android:layout_centerHorizontal="true"
- android:background="@android:drawable/divider_horizontal_dark"
- />
-
<!-- used for instructions such as "draw pattern to unlock", the next alarm, and charging
status. -->
<LinearLayout
@@ -95,22 +112,12 @@
android:gravity="center"
>
<TextView
- android:id="@+id/status1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="17sp"
- android:drawablePadding="4dip"
- />
- <TextView
android:id="@+id/statusSep"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
android:textSize="17sp"
/>
<TextView
@@ -119,7 +126,6 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
android:textSize="17sp"
android:drawablePadding="4dip"
/>
@@ -136,13 +142,14 @@
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
+ android:layout_marginBottom="16dip"
>
<!-- option 1: a single emergency call button -->
<RelativeLayout android:id="@+id/footerNormal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:gravity="center"
+ android:gravity="left"
>
<Button android:id="@+id/emergencyCallAlone"
android:layout_width="wrap_content"
@@ -162,7 +169,7 @@
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:gravity="center"
+ android:gravity="left"
>
<Button android:id="@+id/forgotPattern"
android:layout_width="fill_parent"
@@ -193,4 +200,4 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
-</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
\ No newline at end of file
+</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index 0525356..2856794 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -27,78 +27,99 @@
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:background="#70000000"
- >
+ >
- <LinearLayout
- android:id="@+id/carrierAndDate"
- android:orientation="horizontal"
- android:layout_width="wrap_content"
+ <RelativeLayout
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="13dip"
>
<TextView
android:id="@+id/carrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentRight="true"
+ android:layout_marginTop="16dip"
+ android:layout_marginRight="16dip"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="17sp"
/>
- <TextView
- android:id="@+id/centerDot"
+
+ <com.android.internal.widget.DigitalClock android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="5dip"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="17sp"
- />
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_marginBottom="8dip"
+ android:layout_marginTop="16dip"
+ android:layout_marginLeft="24dip"
+ >
+
+ <TextView android:id="@+id/timeDisplay"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="bottom"
+ android:textSize="72sp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:shadowColor="#C0000000"
+ android:shadowDx="0"
+ android:shadowDy="0"
+ android:shadowRadius="3.0"
+ />
+
+
+ <TextView android:id="@+id/am_pm"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:gravity="bottom"
+ android:textSize="22sp"
+ android:singleLine="true"
+ android:layout_marginLeft="8dip"
+ android:layout_marginBottom="-6dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:shadowColor="#C0000000"
+ android:shadowDx="0"
+ android:shadowDy="0"
+ android:shadowRadius="3.0"
+ />
+
+ </com.android.internal.widget.DigitalClock>
+
<TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
+ android:layout_below="@id/time"
+ android:layout_marginLeft="24dip"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="17sp"
/>
- </LinearLayout>
-
- <TextView
- android:id="@+id/time"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:layout_marginTop="-9dip"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:textSize="48sp"
- />
+
+ </RelativeLayout>
<View
android:id="@+id/divider"
+ android:layout_below="@id/date"
android:layout_width="fill_parent"
android:layout_height="1dip"
- android:layout_marginTop="-4dip"
- android:layout_centerHorizontal="true"
+ android:layout_marginTop="8dip"
+ android:layout_marginBottom="8dip"
android:background="@android:drawable/divider_horizontal_dark"
- />
+ />
<!-- used for instructions such as "draw pattern to unlock", the next alarm, and charging
status. -->
<LinearLayout
android:orientation="horizontal"
- android:layout_width="wrap_content"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dip"
- android:gravity="center"
+ android:layout_marginLeft="24dip"
+ android:gravity="left"
>
<TextView
android:id="@+id/status1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
android:textSize="17sp"
android:drawablePadding="4dip"
/>
@@ -109,7 +130,6 @@
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
android:textSize="17sp"
/>
<TextView
@@ -118,7 +138,6 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
android:textSize="17sp"
android:drawablePadding="4dip"
/>
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/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 d1ae571..1394341 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1436,8 +1436,10 @@
<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 - mute/unmute -->
- <string name="lockscreen_mute_unmute_label">Sound</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/data/fonts/Android.mk b/data/fonts/Android.mk
index a8abf8b..597cb57 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -22,7 +22,8 @@
DroidSerif-Bold.ttf \
DroidSerif-Italic.ttf \
DroidSerif-BoldItalic.ttf \
- DroidSansMono.ttf
+ DroidSansMono.ttf \
+ Clockopia.ttf
ifneq ($(NO_FALLBACK_FONT),true)
copy_from += DroidSansFallback.ttf
diff --git a/data/fonts/Clockopia.ttf b/data/fonts/Clockopia.ttf
new file mode 100644
index 0000000..123ea4f
--- /dev/null
+++ b/data/fonts/Clockopia.ttf
Binary files differ
diff --git a/include/media/stagefright/HardwareAPI.h b/include/media/stagefright/HardwareAPI.h
new file mode 100644
index 0000000..7e1f08d
--- /dev/null
+++ b/include/media/stagefright/HardwareAPI.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#ifndef HARDWARE_API_H_
+
+#define HARDWARE_API_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <ui/ISurface.h>
+#include <utils/RefBase.h>
+
+#include <OMX_Component.h>
+
+extern android::VideoRenderer *createRenderer(
+ const android::sp<android::ISurface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight);
+
+#endif // HARDWARE_API_H_
+
diff --git a/include/media/stagefright/QComHardwareRenderer.h b/include/media/stagefright/QComHardwareRenderer.h
deleted file mode 100644
index 8292dd5..0000000
--- a/include/media/stagefright/QComHardwareRenderer.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef QCOM_HARDWARE_RENDERER_H_
-
-#define QCOM_HARDWARE_RENDERER_H_
-
-#include <media/stagefright/VideoRenderer.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-class ISurface;
-class MemoryHeapPmem;
-
-class QComHardwareRenderer : public VideoRenderer {
-public:
- QComHardwareRenderer(
- const sp<ISurface> &surface,
- size_t displayWidth, size_t displayHeight,
- size_t decodedWidth, size_t decodedHeight);
-
- virtual ~QComHardwareRenderer();
-
- virtual void render(
- const void *data, size_t size, void *platformPrivate);
-
-private:
- sp<ISurface> mISurface;
- size_t mDisplayWidth, mDisplayHeight;
- size_t mDecodedWidth, mDecodedHeight;
- size_t mFrameSize;
- sp<MemoryHeapPmem> mMemoryHeap;
-
- bool getOffset(void *platformPrivate, size_t *offset);
- void publishBuffers(uint32_t pmem_fd);
-
- QComHardwareRenderer(const QComHardwareRenderer &);
- QComHardwareRenderer &operator=(const QComHardwareRenderer &);
-};
-
-} // namespace android
-
-#endif // QCOM_HARDWARE_RENDERER_H_
diff --git a/include/media/stagefright/TIHardwareRenderer.h b/include/media/stagefright/TIHardwareRenderer.h
deleted file mode 100644
index ef42648..0000000
--- a/include/media/stagefright/TIHardwareRenderer.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef TI_HARDWARE_RENDERER_H_
-
-#define TI_HARDWARE_RENDERER_H_
-
-#include <media/stagefright/VideoRenderer.h>
-#include <utils/RefBase.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-class ISurface;
-class Overlay;
-
-class TIHardwareRenderer : public VideoRenderer {
-public:
- TIHardwareRenderer(
- const sp<ISurface> &surface,
- size_t displayWidth, size_t displayHeight,
- size_t decodedWidth, size_t decodedHeight);
-
- virtual ~TIHardwareRenderer();
-
- virtual void render(
- const void *data, size_t size, void *platformPrivate);
-
-private:
- sp<ISurface> mISurface;
- size_t mDisplayWidth, mDisplayHeight;
- size_t mDecodedWidth, mDecodedHeight;
- size_t mFrameSize;
- sp<Overlay> mOverlay;
- Vector<void *> mOverlayAddresses;
- bool mIsFirstFrame;
- size_t mIndex;
-
- TIHardwareRenderer(const TIHardwareRenderer &);
- TIHardwareRenderer &operator=(const TIHardwareRenderer &);
-};
-
-} // namespace android
-
-#endif // TI_HARDWARE_RENDERER_H_
-
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index a36304c..28d7c48 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -26,6 +26,8 @@
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
#include <ui/FramebufferNativeWindow.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
#include <hardware/copybit.h>
@@ -46,12 +48,15 @@
LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
const sp<Client>& client, int32_t i)
: LayerBaseClient(flinger, display, client, i),
- mNeedsBlending(false)
+ mNeedsBlending(false), mBlitEngine(0)
{
}
LayerBuffer::~LayerBuffer()
{
+ if (mBlitEngine) {
+ copybit_close(mBlitEngine);
+ }
}
void LayerBuffer::onFirstRef()
@@ -69,6 +74,10 @@
sGrallocModule = (gralloc_module_t const *)module;
}
}
+
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+ copybit_open(module, &mBlitEngine);
+ }
}
sp<LayerBaseClient::Surface> LayerBuffer::createSurface() const
@@ -350,6 +359,35 @@
return;
}
+ if (mLayer.mBlitEngine) {
+ // create our temporary buffer and corresponding EGLImageKHR.
+ // note that the size of this buffer doesn't really matter,
+ // the final image will always be drawn with proper aspect ratio.
+
+ int w = buffers.w;
+ int h = buffers.h;
+ mTempGraphicBuffer.clear();
+ mTempGraphicBuffer = new GraphicBuffer(
+ w, h, HAL_PIXEL_FORMAT_RGBX_8888,
+ GraphicBuffer::USAGE_HW_TEXTURE |
+ GraphicBuffer::USAGE_HW_2D);
+
+ if (mTempGraphicBuffer->initCheck() == NO_ERROR) {
+ NativeBuffer& dst(mTempBuffer);
+ dst.img.w = mTempGraphicBuffer->getStride();
+ dst.img.h = mTempGraphicBuffer->getHeight();
+ dst.img.format = mTempGraphicBuffer->getPixelFormat();
+ dst.img.handle = (native_handle_t *)mTempGraphicBuffer->handle;
+ dst.img.base = 0;
+ dst.crop.l = 0;
+ dst.crop.t = 0;
+ dst.crop.r = mTempGraphicBuffer->getWidth();
+ dst.crop.b = mTempGraphicBuffer->getHeight();
+ } else {
+ mTempGraphicBuffer.clear();
+ }
+ }
+
mBufferHeap = buffers;
mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);
mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
@@ -438,15 +476,35 @@
#if defined(EGL_ANDROID_image_native_buffer)
if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) {
- // NOTE: Assume the buffer is allocated with the proper USAGE flags
- sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
- src.crop.r, src.crop.b, src.img.format,
- GraphicBuffer::USAGE_HW_TEXTURE,
- src.img.w, src.img.handle, false);
+ copybit_device_t* copybit = mLayer.mBlitEngine;
+ if (copybit) {
+ // create our EGLImageKHR the first time
+ if (mTexture.image == EGL_NO_IMAGE_KHR) {
+ err = NO_MEMORY;
+ if (mTempGraphicBuffer!=0) {
+ err = mLayer.initializeEglImage(
+ mTempGraphicBuffer, &mTexture);
+ // once the EGLImage has been created (whether it fails
+ // or not) we don't need the graphic buffer reference
+ // anymore.
+ mTempGraphicBuffer.clear();
+ }
+ }
- graphicBuffer->setVerticalStride(src.img.h);
+ if (err == NO_ERROR) {
+ // NOTE: Assume the buffer is allocated with the proper USAGE flags
+ const NativeBuffer& dst(mTempBuffer);
+ region_iterator clip(Region(Rect(dst.crop.r, dst.crop.b)));
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+ err = copybit->stretch(copybit, &dst.img, &src.img,
+ &dst.crop, &src.crop, &clip);
- err = mLayer.initializeEglImage(graphicBuffer, &mTexture);
+ }
+ } else {
+ err = INVALID_OPERATION;
+ }
}
#endif
else {
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 47482f4..1abb103 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -135,8 +135,9 @@
status_t mStatus;
ISurface::BufferHeap mBufferHeap;
size_t mBufferSize;
- mutable sp<GraphicBuffer> mTempBitmap;
mutable LayerBase::Texture mTexture;
+ NativeBuffer mTempBuffer;
+ mutable sp<GraphicBuffer> mTempGraphicBuffer;
};
class OverlaySource : public Source {
@@ -205,6 +206,7 @@
sp<Surface> mSurface;
bool mInvalidate;
bool mNeedsBlending;
+ copybit_device_t* mBlitEngine;
};
// ---------------------------------------------------------------------------
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 0efba9c..c5e22e5 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -118,8 +118,6 @@
LOGE_IF(err, "fb buffer 1 allocation failed w=%d, h=%d, err=%s",
fbDev->width, fbDev->height, strerror(-err));
- LOGE("xDpi %d", fbDev->xdpi);
- LOGE("yDpi %d", fbDev->ydpi);
const_cast<uint32_t&>(android_native_window_t::flags) = fbDev->flags;
const_cast<float&>(android_native_window_t::xdpi) = fbDev->xdpi;
const_cast<float&>(android_native_window_t::ydpi) = fbDev->ydpi;
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 20fb4f3..25da813 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -6,15 +6,12 @@
LOCAL_C_INCLUDES := $(PV_INCLUDES)
LOCAL_CFLAGS := $(PV_CFLAGS_MINUS_VISIBILITY)
-LOCAL_C_INCLUDES += $(TOP)/hardware/ti/omap3/liboverlay
LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
LOCAL_SRC_FILES:= \
OMX.cpp \
OMXNodeInstance.cpp \
- QComHardwareRenderer.cpp \
- SoftwareRenderer.cpp \
- TIHardwareRenderer.cpp
+ SoftwareRenderer.cpp
LOCAL_SHARED_LIBRARIES := \
libbinder \
@@ -25,7 +22,11 @@
libopencore_common
ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
- LOCAL_LDLIBS += -lpthread
+ LOCAL_LDLIBS += -lpthread -ldl
+endif
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_PRELINK_MODULE:= false
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 9ac0d44..4ccd4bd 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -27,9 +27,7 @@
#include <binder/IMemory.h>
#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/QComHardwareRenderer.h>
#include <media/stagefright/SoftwareRenderer.h>
-#include <media/stagefright/TIHardwareRenderer.h>
#include <media/stagefright/VideoRenderer.h>
#include <OMX_Component.h>
@@ -431,27 +429,37 @@
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
size_t displayWidth, size_t displayHeight) {
+ Mutex::Autolock autoLock(mLock);
+
VideoRenderer *impl = NULL;
- static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+ static void *libHandle = NULL;
- if (colorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
- && !strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
- LOGW("Using QComHardwareRenderer.");
- impl =
- new QComHardwareRenderer(
- surface,
- displayWidth, displayHeight,
- encodedWidth, encodedHeight);
- } else if (colorFormat == OMX_COLOR_FormatCbYCrY
- && !strcmp(componentName, "OMX.TI.Video.Decoder")) {
- LOGW("Using TIHardwareRenderer.");
- impl =
- new TIHardwareRenderer(
- surface,
- displayWidth, displayHeight,
- encodedWidth, encodedHeight);
- } else {
+ if (!libHandle) {
+ libHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
+ }
+
+ if (libHandle) {
+ typedef VideoRenderer *(*CreateRendererFunc)(
+ const sp<ISurface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight);
+
+ CreateRendererFunc func =
+ (CreateRendererFunc)dlsym(
+ libHandle,
+ "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
+ "OMX_COLOR_FORMATTYPEjjjj");
+
+ if (func) {
+ impl = (*func)(surface, componentName, colorFormat,
+ displayWidth, displayHeight, encodedWidth, encodedHeight);
+ }
+ }
+
+ if (!impl) {
LOGW("Using software renderer.");
impl = new SoftwareRenderer(
colorFormat,
diff --git a/media/libstagefright/omx/QComHardwareRenderer.cpp b/media/libstagefright/omx/QComHardwareRenderer.cpp
deleted file mode 100644
index c65d1f3..0000000
--- a/media/libstagefright/omx/QComHardwareRenderer.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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.
- */
-
-#include <binder/MemoryHeapBase.h>
-#include <binder/MemoryHeapPmem.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/QComHardwareRenderer.h>
-#include <ui/ISurface.h>
-
-namespace android {
-
-////////////////////////////////////////////////////////////////////////////////
-
-typedef struct PLATFORM_PRIVATE_ENTRY
-{
- /* Entry type */
- uint32_t type;
-
- /* Pointer to platform specific entry */
- void *entry;
-
-} PLATFORM_PRIVATE_ENTRY;
-
-typedef struct PLATFORM_PRIVATE_LIST
-{
- /* Number of entries */
- uint32_t nEntries;
-
- /* Pointer to array of platform specific entries *
- * Contiguous block of PLATFORM_PRIVATE_ENTRY elements */
- PLATFORM_PRIVATE_ENTRY *entryList;
-
-} PLATFORM_PRIVATE_LIST;
-
-// data structures for tunneling buffers
-typedef struct PLATFORM_PRIVATE_PMEM_INFO
-{
- /* pmem file descriptor */
- uint32_t pmem_fd;
- uint32_t offset;
-
-} PLATFORM_PRIVATE_PMEM_INFO;
-
-#define PLATFORM_PRIVATE_PMEM 1
-
-QComHardwareRenderer::QComHardwareRenderer(
- const sp<ISurface> &surface,
- size_t displayWidth, size_t displayHeight,
- size_t decodedWidth, size_t decodedHeight)
- : mISurface(surface),
- mDisplayWidth(displayWidth),
- mDisplayHeight(displayHeight),
- mDecodedWidth(decodedWidth),
- mDecodedHeight(decodedHeight),
- mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) {
- CHECK(mISurface.get() != NULL);
- CHECK(mDecodedWidth > 0);
- CHECK(mDecodedHeight > 0);
-}
-
-QComHardwareRenderer::~QComHardwareRenderer() {
- mISurface->unregisterBuffers();
-}
-
-void QComHardwareRenderer::render(
- const void *data, size_t size, void *platformPrivate) {
- size_t offset;
- if (!getOffset(platformPrivate, &offset)) {
- return;
- }
-
- mISurface->postBuffer(offset);
-
- // Since we cannot tell how long it'll take until surface flinger
- // has displayed the data onscreen, we'll just have to guess...
- // We must not return the buffer to the decoder before it's been displayed.
- usleep(25000);
-}
-
-bool QComHardwareRenderer::getOffset(void *platformPrivate, size_t *offset) {
- *offset = 0;
-
- PLATFORM_PRIVATE_LIST *list = (PLATFORM_PRIVATE_LIST *)platformPrivate;
- for (uint32_t i = 0; i < list->nEntries; ++i) {
- if (list->entryList[i].type != PLATFORM_PRIVATE_PMEM) {
- continue;
- }
-
- PLATFORM_PRIVATE_PMEM_INFO *info =
- (PLATFORM_PRIVATE_PMEM_INFO *)list->entryList[i].entry;
-
- if (info != NULL) {
- if (mMemoryHeap.get() == NULL) {
- publishBuffers(info->pmem_fd);
- }
-
- if (mMemoryHeap.get() == NULL) {
- return false;
- }
-
- *offset = info->offset;
-
- return true;
- }
- }
-
- return false;
-}
-
-void QComHardwareRenderer::publishBuffers(uint32_t pmem_fd) {
- sp<MemoryHeapBase> master =
- reinterpret_cast<MemoryHeapBase *>(pmem_fd);
-
- master->setDevice("/dev/pmem");
-
- uint32_t heap_flags = master->getFlags() & MemoryHeapBase::NO_CACHING;
- mMemoryHeap = new MemoryHeapPmem(master, heap_flags);
- mMemoryHeap->slap();
-
- ISurface::BufferHeap bufferHeap(
- mDisplayWidth, mDisplayHeight,
- mDecodedWidth, mDecodedHeight,
- PIXEL_FORMAT_YCbCr_420_SP,
- mMemoryHeap);
-
- status_t err = mISurface->registerBuffers(bufferHeap);
- CHECK_EQ(err, OK);
-}
-
-} // namespace android
diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp
index 4ed6869..39de504 100644
--- a/media/libstagefright/omx/SoftwareRenderer.cpp
+++ b/media/libstagefright/omx/SoftwareRenderer.cpp
@@ -79,7 +79,7 @@
default:
{
- LOGW("Cannot render color format %ld", mColorFormat);
+ LOGW("Cannot render color format %d", mColorFormat);
break;
}
}
diff --git a/media/libstagefright/omx/TIHardwareRenderer.cpp b/media/libstagefright/omx/TIHardwareRenderer.cpp
deleted file mode 100644
index ebade4a..0000000
--- a/media/libstagefright/omx/TIHardwareRenderer.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "TIHardwareRenderer"
-#include <utils/Log.h>
-
-#include <media/stagefright/TIHardwareRenderer.h>
-#include <media/stagefright/MediaDebug.h>
-#include <ui/ISurface.h>
-#include <ui/Overlay.h>
-
-#include "v4l2_utils.h"
-
-#define CACHEABLE_BUFFERS 0x1
-
-namespace android {
-
-////////////////////////////////////////////////////////////////////////////////
-
-TIHardwareRenderer::TIHardwareRenderer(
- const sp<ISurface> &surface,
- size_t displayWidth, size_t displayHeight,
- size_t decodedWidth, size_t decodedHeight)
- : mISurface(surface),
- mDisplayWidth(displayWidth),
- mDisplayHeight(displayHeight),
- mDecodedWidth(decodedWidth),
- mDecodedHeight(decodedHeight),
- mFrameSize(mDecodedWidth * mDecodedHeight * 2),
- mIsFirstFrame(true),
- mIndex(0) {
- CHECK(mISurface.get() != NULL);
- CHECK(mDecodedWidth > 0);
- CHECK(mDecodedHeight > 0);
-
- sp<OverlayRef> ref = mISurface->createOverlay(
- mDisplayWidth, mDisplayHeight, OVERLAY_FORMAT_CbYCrY_422_I);
-
- if (ref.get() == NULL) {
- LOGE("Unable to create the overlay!");
- return;
- }
-
- mOverlay = new Overlay(ref);
- mOverlay->setParameter(CACHEABLE_BUFFERS, 0);
-
- for (size_t i = 0; i < (size_t)mOverlay->getBufferCount(); ++i) {
- mapping_data_t *data =
- (mapping_data_t *)mOverlay->getBufferAddress((void *)i);
-
- mOverlayAddresses.push(data->ptr);
- }
-}
-
-TIHardwareRenderer::~TIHardwareRenderer() {
- if (mOverlay.get() != NULL) {
- mOverlay->destroy();
- mOverlay.clear();
-
- // XXX apparently destroying an overlay is an asynchronous process...
- sleep(1);
- }
-}
-
-void TIHardwareRenderer::render(
- const void *data, size_t size, void *platformPrivate) {
- // CHECK_EQ(size, mFrameSize);
-
- if (mOverlay.get() == NULL) {
- return;
- }
-
-#if 0
- size_t i = 0;
- for (; i < mOverlayAddresses.size(); ++i) {
- if (mOverlayAddresses[i] == data) {
- break;
- }
-
- if (mIsFirstFrame) {
- LOGI("overlay buffer #%d: %p", i, mOverlayAddresses[i]);
- }
- }
-
- if (i == mOverlayAddresses.size()) {
- LOGE("No suitable overlay buffer found.");
- return;
- }
-
- mOverlay->queueBuffer((void *)i);
-
- overlay_buffer_t overlay_buffer;
- if (!mIsFirstFrame) {
- CHECK_EQ(mOverlay->dequeueBuffer(&overlay_buffer), OK);
- } else {
- mIsFirstFrame = false;
- }
-#else
- memcpy(mOverlayAddresses[mIndex], data, size);
-
- mOverlay->queueBuffer((void *)mIndex);
-
- if (++mIndex == mOverlayAddresses.size()) {
- mIndex = 0;
- }
-
- overlay_buffer_t overlay_buffer;
- if (!mIsFirstFrame) {
- CHECK_EQ(mOverlay->dequeueBuffer(&overlay_buffer), OK);
- } else {
- mIsFirstFrame = false;
- }
-#endif
-}
-
-} // namespace android
-
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/SystemBackupAgent.java b/services/java/com/android/server/SystemBackupAgent.java
index 8903ebd..67abe55 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/java/com/android/server/SystemBackupAgent.java
@@ -45,8 +45,16 @@
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
// We only back up the data under the current "wallpaper" schema with metadata
- addHelper("wallpaper", new AbsoluteFileBackupHelper(SystemBackupAgent.this,
- new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO }));
+ WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
+ Context.WALLPAPER_SERVICE);
+ String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO };
+ if (wallpaper != null && wallpaper.mName != null && wallpaper.mName.length() > 0) {
+ // When the wallpaper has a name, back up the info by itself.
+ // TODO: Don't rely on the innards of the service object like this!
+ // TODO: Send a delete for any stored wallpaper image in this case?
+ files = new String[] { WALLPAPER_INFO };
+ }
+ addHelper("wallpaper", new AbsoluteFileBackupHelper(SystemBackupAgent.this, files));
super.onBackup(oldState, data, newState);
}
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/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
index 85e0422..fea366c 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
@@ -26,6 +26,7 @@
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
+import java.util.regex.Pattern;
public class FsUtils {
@@ -121,4 +122,38 @@
return url;
}
+ public static boolean diffIgnoreSpaces(String file1, String file2) throws IOException {
+ BufferedReader br1 = new BufferedReader(new FileReader(file1));
+ BufferedReader br2 = new BufferedReader(new FileReader(file2));
+ boolean same = true;
+ Pattern trailingSpace = Pattern.compile("\\s+$");
+
+ while(true) {
+ String line1 = br1.readLine();
+ String line2 = br2.readLine();
+
+ if (line1 == null && line2 == null)
+ break;
+ if (line1 != null) {
+ line1 = trailingSpace.matcher(line1).replaceAll("");
+ } else {
+ line1 = "";
+ }
+ if (line2 != null) {
+ line2 = trailingSpace.matcher(line2).replaceAll("");
+ } else {
+ line2 = "";
+ }
+ if(!line1.equals(line2)) {
+ same = false;
+ break;
+ }
+ }
+
+ br1.close();
+ br2.close();
+
+ return same;
+ }
+
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index 235e10e..8983612 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -249,28 +249,11 @@
File expected = new File(expectedResultFile);
if (actual.exists() && expected.exists()) {
try {
- boolean passing = true;
- BufferedReader fr = new BufferedReader(new FileReader(actual));
- BufferedReader fe = new BufferedReader(new FileReader(expected));
- while (true) {
- String s1 = fr.readLine();
- String s2 = fe.readLine();
- if (s1 == null && s2 == null)
- break; // both files are the same
- if (s1 == null || s2 == null || !s1.equals(s2)) {
- passing = false;
- break;
- }
- }
-
- if (passing) {
+ if (FsUtils.diffIgnoreSpaces(actualResultFile, expectedResultFile)) {
passedCase(testFile);
} else {
failedCase(testFile);
}
-
- fe.close();
- fr.close();
} catch (FileNotFoundException ex) {
Log.e(LOGTAG, "File not found : " + ex.getMessage());
} catch (IOException ex) {