summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml85
-rw-r--r--core/java/android/accounts/AccountManager.java4
-rw-r--r--core/java/android/accounts/AccountManagerService.java4
-rw-r--r--core/java/android/accounts/IAccountManager.aidl5
-rw-r--r--core/java/android/app/Dialog.java3
-rw-r--r--core/java/android/content/DialogInterface.java1
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java4
-rw-r--r--core/java/android/provider/CallLog.java54
-rw-r--r--core/java/android/provider/ContactsContract.java292
-rw-r--r--core/java/android/provider/Downloads.java2
-rw-r--r--core/java/android/webkit/JWebCoreJavaBridge.java1
-rw-r--r--core/java/android/webkit/WebView.java11
-rw-r--r--core/java/android/webkit/WebViewCore.java12
-rw-r--r--keystore/java/android/security/SystemKeyStore.java29
-rw-r--r--keystore/tests/src/android/security/SystemKeyStoreTest.java11
-rw-r--r--opengl/libagl/Android.mk5
-rw-r--r--opengl/libs/Android.mk11
-rw-r--r--services/java/com/android/server/ConnectivityService.java13
-rw-r--r--services/java/com/android/server/PackageManagerService.java10
-rw-r--r--services/java/com/android/server/status/StatusBarPolicy.java67
20 files changed, 474 insertions, 150 deletions
diff --git a/api/current.xml b/api/current.xml
index 1142088..b690e42 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -14581,6 +14581,25 @@
<parameter name="key" type="java.lang.String">
</parameter>
</method>
+<method name="hasFeatures"
+ return="android.accounts.AccountManagerFuture&lt;java.lang.Boolean&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="features" type="java.lang.String[]">
+</parameter>
+<parameter name="callback" type="android.accounts.AccountManagerCallback&lt;java.lang.Boolean&gt;">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
<method name="invalidateAuthToken"
return="void"
abstract="false"
@@ -14690,25 +14709,6 @@
<parameter name="value" type="java.lang.String">
</parameter>
</method>
-<method name="testHasFeatures"
- return="android.accounts.AccountManagerFuture&lt;java.lang.Boolean&gt;"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="account" type="android.accounts.Account">
-</parameter>
-<parameter name="features" type="java.lang.String[]">
-</parameter>
-<parameter name="callback" type="android.accounts.AccountManagerCallback&lt;java.lang.Boolean&gt;">
-</parameter>
-<parameter name="handler" type="android.os.Handler">
-</parameter>
-</method>
<method name="updateCredentials"
return="android.accounts.AccountManagerFuture&lt;android.os.Bundle&gt;"
abstract="false"
@@ -20739,6 +20739,19 @@
<parameter name="onKeyListener" type="android.content.DialogInterface.OnKeyListener">
</parameter>
</method>
+<method name="setOnShowListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.content.DialogInterface.OnShowListener">
+</parameter>
+</method>
<method name="setOwnerActivity"
return="void"
abstract="false"
@@ -34002,6 +34015,27 @@
</parameter>
</method>
</interface>
+<interface name="DialogInterface.OnShowListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onShow"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dialog" type="android.content.DialogInterface">
+</parameter>
+</method>
+</interface>
<class name="Entity"
extends="java.lang.Object"
abstract="false"
@@ -119402,6 +119436,19 @@
visibility="public"
>
</constructor>
+<method name="getLastOutgoingCall"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
<field name="CACHED_NAME"
type="java.lang.String"
transient="false"
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 3bbfce8..414d963 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -254,12 +254,12 @@ public class AccountManager {
* The future result is a {@link Boolean} that is true if the account exists and has the
* specified features.
*/
- public AccountManagerFuture<Boolean> testHasFeatures(final Account account,
+ public AccountManagerFuture<Boolean> hasFeatures(final Account account,
final String[] features,
AccountManagerCallback<Boolean> callback, Handler handler) {
return new Future2Task<Boolean>(handler, callback) {
public void doWork() throws RemoteException {
- mService.testHasFeatures(mResponse, account, features);
+ mService.hasFeatures(mResponse, account, features);
}
public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index f5166c2..ee26d3c 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -449,7 +449,7 @@ public class AccountManagerService
return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
}
- public void testHasFeatures(IAccountManagerResponse response,
+ public void hasFeatures(IAccountManagerResponse response,
Account account, String[] features) {
checkReadAccountsPermission();
long identityToken = clearCallingIdentity();
@@ -501,7 +501,7 @@ public class AccountManagerService
}
protected String toDebugString(long now) {
- return super.toDebugString(now) + ", testHasFeatures"
+ return super.toDebugString(now) + ", hasFeatures"
+ ", " + mAccount
+ ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
}
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index cbd26ee..36a5653 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -31,8 +31,7 @@ interface IAccountManager {
String getUserData(in Account account, String key);
AuthenticatorDescription[] getAuthenticatorTypes();
Account[] getAccounts(String accountType);
- void testHasFeatures(in IAccountManagerResponse response, in Account account,
- in String[] features);
+ void hasFeatures(in IAccountManagerResponse response, in Account account, in String[] features);
void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features);
boolean addAccount(in Account account, String password, in Bundle extras);
void removeAccount(in IAccountManagerResponse response, in Account account);
@@ -47,7 +46,7 @@ interface IAccountManager {
String authTokenType, boolean notifyOnAuthFailure, boolean expectActivityLaunch,
in Bundle options);
void addAcount(in IAccountManagerResponse response, String accountType,
- String authTokenType, in String[] requiredFeatures, boolean expectActivityLaunch,
+ String authTokenType, in String[] requiredFeatures, boolean expectActivityLaunch,
in Bundle options);
void updateCredentials(in IAccountManagerResponse response, in Account account,
String authTokenType, boolean expectActivityLaunch, in Bundle options);
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index fa5d4a8..ed38240 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -995,8 +995,7 @@ public class Dialog implements DialogInterface, Window.Callback,
/**
* Sets a listener to be invoked when the dialog is shown.
- *
- * @hide Pending API council approval
+ * @param listener The {@link DialogInterface.OnShowListener} to use.
*/
public void setOnShowListener(OnShowListener listener) {
if (listener != null) {
diff --git a/core/java/android/content/DialogInterface.java b/core/java/android/content/DialogInterface.java
index 9f1036e..947eac6 100644
--- a/core/java/android/content/DialogInterface.java
+++ b/core/java/android/content/DialogInterface.java
@@ -94,7 +94,6 @@ public interface DialogInterface {
/**
* Interface used to allow the creator of a dialog to run some code when the
* dialog is shown.
- * @hide Pending API council approval
*/
interface OnShowListener {
/**
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index b59030d..fb44a62 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1873,8 +1873,8 @@ public class SQLiteDatabase extends SQLiteClosable {
* JNI method. If entire cache is wiped out, it could cause a big GC activity
* just because a (rogue) process is using the cache incorrectly.
*/
- Log.wtf(TAG, "Too many sql statements in database cache. Make sure your sql " +
- "statements are using prepared-sql-statement syntax with '?' for" +
+ Log.w(TAG, "Too many sql statements in database cache. Make sure your sql " +
+ "statements are using prepared-sql-statement syntax with '?' for " +
"bindargs, instead of using actual values");
Set<String> keySet = mCompiledQueries.keySet();
for (String s : keySet) {
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 7854423..d52632b 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -22,6 +22,7 @@ import com.android.internal.telephony.Connection;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.database.Cursor;
import android.net.Uri;
import android.text.TextUtils;
@@ -111,25 +112,25 @@ public class CallLog {
* <P>Type: TEXT</P>
*/
public static final String CACHED_NAME = "name";
-
+
/**
* The cached number type (Home, Work, etc) associated with the
* phone number, if it exists.
* This value is not guaranteed to be current, if the contact information
* associated with this number has changed.
- * <P>Type: INTEGER</P>
+ * <P>Type: INTEGER</P>
*/
public static final String CACHED_NUMBER_TYPE = "numbertype";
-
+
/**
* The cached number label, for a custom number type, associated with the
* phone number, if it exists.
* This value is not guaranteed to be current, if the contact information
* associated with this number has changed.
- * <P>Type: TEXT</P>
+ * <P>Type: TEXT</P>
*/
public static final String CACHED_NUMBER_LABEL = "numberlabel";
-
+
/**
* Adds a call to the call log.
*
@@ -137,15 +138,15 @@ public class CallLog {
* if the contact is unknown.
* @param context the context used to get the ContentResolver
* @param number the phone number to be added to the calls db
- * @param presentation the number presenting rules set by the network for
+ * @param presentation the number presenting rules set by the network for
* "allowed", "payphone", "restricted" or "unknown"
* @param callType enumerated values for "incoming", "outgoing", or "missed"
* @param start time stamp for the call in milliseconds
* @param duration call duration in seconds
- *
+ *
* {@hide}
*/
- public static Uri addCall(CallerInfo ci, Context context, String number,
+ public static Uri addCall(CallerInfo ci, Context context, String number,
int presentation, int callType, long start, int duration) {
final ContentResolver resolver = context.getContentResolver();
@@ -175,22 +176,47 @@ public class CallLog {
values.put(CACHED_NUMBER_TYPE, ci.numberType);
values.put(CACHED_NUMBER_LABEL, ci.numberLabel);
}
-
+
if ((ci != null) && (ci.person_id > 0)) {
ContactsContract.Contacts.markAsContacted(resolver, ci.person_id);
}
-
+
Uri result = resolver.insert(CONTENT_URI, values);
-
+
removeExpiredEntries(context);
-
+
return result;
}
-
+
+ /**
+ * Query the call log database for the last dialed number.
+ * @param context Used to get the content resolver.
+ * @return The last phone number dialed (outgoing) or an empty
+ * string if none exist yet.
+ */
+ public static String getLastOutgoingCall(Context context) {
+ final ContentResolver resolver = context.getContentResolver();
+ Cursor c = null;
+ try {
+ c = resolver.query(
+ CONTENT_URI,
+ new String[] {NUMBER},
+ TYPE + " = " + OUTGOING_TYPE,
+ null,
+ DEFAULT_SORT_ORDER + " LIMIT 1");
+ if (c == null || !c.moveToFirst()) {
+ return "";
+ }
+ return c.getString(0);
+ } finally {
+ if (c != null) c.close();
+ }
+ }
+
private static void removeExpiredEntries(Context context) {
final ContentResolver resolver = context.getContentResolver();
resolver.delete(CONTENT_URI, "_id IN " +
- "(SELECT _id FROM calls ORDER BY " + DEFAULT_SORT_ORDER
+ "(SELECT _id FROM calls ORDER BY " + DEFAULT_SORT_ORDER
+ " LIMIT -1 OFFSET 500)", null);
}
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 7fb9daf..93b5b4d 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -55,19 +55,21 @@ import java.io.InputStream;
* </p>
* <ul>
* <li>
- * 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.
+ * A row in the {@link Data} table can store any kind of personal data, such
+ * as a phone number or email addresses. The set 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.
* </li>
* <li>
- * A row in the {@link RawContacts} table represents a set of Data describing a
- * person and associated with a single account (for example, a single Gmail
- * account).
+ * A row in the {@link RawContacts} table represents a set of data describing a
+ * person and associated with a single account (for example, one of the user's
+ * Gmail accounts).
* </li>
* <li>
* A row in the {@link Contacts} table represents an aggregate of one or more
- * RawContacts presumably describing the same person.
+ * RawContacts presumably describing the same person. When data in or associated with
+ * the RawContacts table is changed, the affected aggregate contacts are updated as
+ * necessary.
* </li>
* </ul>
* <p>
@@ -75,7 +77,8 @@ import java.io.InputStream;
* </p>
* <ul>
* <li>
- * {@link Groups}, which contains information about raw contact groups - the
+ * {@link Groups}, which contains information about raw contact groups
+ * such as Gmail contact groups. The
* current API does not support the notion of groups spanning multiple accounts.
* </li>
* <li>
@@ -106,11 +109,15 @@ public final class ContactsContract {
public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
/**
- * An optional insert, update or delete URI parameter that allows the caller
+ * An optional URI parameter for insert, update, or delete queries
+ * that allows the caller
* to specify that it is a sync adapter. The default value is false. If true
- * the dirty flag is not automatically set and the "syncToNetwork" parameter
- * is set to false when calling
- * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}.
+ * {@link RawContacts#DIRTY} is not automatically set and the
+ * "syncToNetwork" parameter is set to false when calling
+ * {@link
+ * ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}.
+ * This prevents an unnecessary extra synchronization, see the discussion of
+ * the delete operation in {@link RawContacts}.
*/
public static final String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
@@ -459,19 +466,23 @@ public final class ContactsContract {
protected interface ContactNameColumns {
/**
- * The kind of data that is used as the display name for the contact, see
- * DisplayNameSources.
+ * The kind of data that is used as the display name for the contact, such as
+ * structured name or email address. See DisplayNameSources.
+ *
+ * TODO: convert DisplayNameSources to a link after it is un-hidden
*/
public static final String DISPLAY_NAME_SOURCE = "display_name_source";
/**
* The default text shown as the contact's display name. It is based on
* available data, see {@link #DISPLAY_NAME_SOURCE}.
+ *
+ * @see ContactsContract.ContactNameColumns#DISPLAY_NAME_ALTERNATIVE
*/
public static final String DISPLAY_NAME_PRIMARY = "display_name";
/**
- * Alternative representation of the display name. If display name is
+ * An alternative representation of the display name. If display name is
* based on the structured name and the structured name follows
* the Western full name style, then this field contains the "family name first"
* version of the full name. Otherwise, it is the same as DISPLAY_NAME_PRIMARY.
@@ -479,27 +490,42 @@ public final class ContactsContract {
public static final String DISPLAY_NAME_ALTERNATIVE = "display_name_alt";
/**
- * The type of alphabet used to capture the phonetic name. See
+ * The phonetic alphabet used to represent the {@link #PHONETIC_NAME}. See
* PhoneticNameStyle.
+ *
+ * TODO: convert PhoneticNameStyle to a link after it is un-hidden
*/
public static final String PHONETIC_NAME_STYLE = "phonetic_name_style";
/**
- * Pronunciation of the full name. See PhoneticNameStyle.
+ * <p>
+ * Pronunciation of the full name in the phonetic alphabet specified by
+ * {@link #PHONETIC_NAME_STYLE}.
+ * </p>
+ * <p>
+ * The value may be set manually by the user.
+ * This capability is is of interest only in countries
+ * with commonly used phonetic
+ * alphabets, such as Japan and Korea. See PhoneticNameStyle.
+ * </p>
+ *
+ * TODO: convert PhoneticNameStyle to a link after it is un-hidden
*/
public static final String PHONETIC_NAME = "phonetic_name";
/**
* Sort key that takes into account locale-based traditions for sorting
- * names in address books. More specifically, for Chinese names
- * the sort key is the name's Pinyin spelling; for Japanese names
+ * names in address books. The default
+ * sort key is {@link #DISPLAY_NAME_PRIMARY}. For Chinese names
+ * the sort key is the name's Pinyin spelling, and for Japanese names
* it is the Hiragana version of the phonetic name.
*/
public static final String SORT_KEY_PRIMARY = "sort_key";
/**
* Sort key based on the alternative representation of the full name,
- * specifically the one using the 'family name first' format for
+ * {@link #DISPLAY_NAME_ALTERNATIVE}. Thus for Western names,
+ * it is the one using the "family name first" format for
* Western names.
*/
public static final String SORT_KEY_ALTERNATIVE = "sort_key_alt";
@@ -808,7 +834,10 @@ public final class ContactsContract {
}
/**
- * Mark a contact as having been contacted.
+ * Mark a contact as having been contacted. This updates the
+ * {@link #TIMES_CONTACTED} and {@link #LAST_TIME_CONTACTED} for the
+ * contact, plus the corresponding values of any associated raw
+ * contacts.
*
* @param resolver the ContentResolver to use
* @param contactId the person who was contacted
@@ -1050,15 +1079,37 @@ public final class ContactsContract {
}
/**
- * Constants for the raw contacts table, which contains the base contact
- * information per sync source. Sync adapters and contact management apps
+ * Constants for the raw contacts table, which contains one row of contact
+ * information for each person in each synced account. Sync adapters and
+ * contact management apps
* are the primary consumers of this API.
+ *
+ * <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. The
+ * aggregation is reflected in the {@link RawContacts} table by the change of the
+ * {@link #CONTACT_ID} field, which is the reference to the aggregate contact.
+ * </p>
+ * <p>
+ * Changes to the structured name, organization, phone number, email address,
+ * or nickname trigger a re-aggregation.
+ * </p>
+ * <p>
+ * See also {@link AggregationExceptions} for a mechanism to control
+ * aggregation programmatically.
+ * </p>
+ *
* <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:
+ * <dd>
+ * <p>
+ * Raw contacts can be inserted incrementally or in a batch.
+ * The incremental method is more traditional but less efficient.
+ * It should be used
+ * only if no {@link Data} values are available at the time the raw contact is created:
* <pre>
* ContentValues values = new ContentValues();
* values.put(RawContacts.ACCOUNT_TYPE, accountType);
@@ -1066,9 +1117,10 @@ public final class ContactsContract {
* Uri rawContactUri = getContentResolver().insert(RawContacts.CONTENT_URI, values);
* long rawContactId = ContentUris.parseId(rawContactUri);
* </pre>
+ * </p>
* <p>
- * Once data rows are available, insert those. For example, here's how you would insert
- * a name:
+ * Once {@link Data} values become available, insert those.
+ * For example, here's how you would insert a name:
*
* <pre>
* values.clear();
@@ -1084,6 +1136,7 @@ public final class ContactsContract {
* and causes at most one aggregation pass.
* <pre>
* ArrayList&lt;ContentProviderOperation&gt; ops = Lists.newArrayList();
+ * ...
* int rawContactInsertIndex = ops.size();
* ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
* .withValue(RawContacts.ACCOUNT_TYPE, accountType)
@@ -1100,21 +1153,27 @@ public final class ContactsContract {
* </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.
+ * Note the use of {@link ContentProviderOperation.Builder#withValueBackReference(String, int)}
+ * to refer to the as-yet-unknown index value of the raw contact inserted in the
+ * first operation.
* </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>
+ * <dd><p>
+ * Raw contacts can be updated incrementally or in a batch.
+ * Batch mode should be used whenever possible.
+ * The procedures and considerations are analogous to those documented above for inserts.
+ * </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.
+ * contacts associated with a {@link Contacts} row are deleted, the {@link Contacts} row
+ * 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
+ * The invocation of {@code resolver.delete(...)}, does not immediately delete
+ * a raw contacts row.
+ * Instead, 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(...)}
@@ -1124,10 +1183,11 @@ public final class ContactsContract {
* 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:
+ * It is easy to find all raw contacts in a Contact:
* <pre>
* Cursor c = getContentResolver().query(RawContacts.CONTENT_URI,
* new String[]{RawContacts._ID},
@@ -1136,7 +1196,7 @@ public final class ContactsContract {
* </pre>
* </p>
* <p>
- * There are two ways to find raw contacts within a specific account,
+ * 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:
@@ -1178,19 +1238,11 @@ public final class ContactsContract {
* </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>
+ * TODO: include {@link #DISPLAY_NAME_PRIMARY}, {@link #DISPLAY_NAME_ALTERNATIVE},
+ * {@link #DISPLAY_NAME_SOURCE}, {@link #PHONETIC_NAME}, {@link #PHONETIC_NAME_STYLE},
+ * {@link #SORT_KEY_PRIMARY}, {@link #SORT_KEY_ALTERNATIVE}?
+ *
* <table class="jd-sumtable">
* <tr>
* <th colspan='4'>RawContacts</th>
@@ -1199,15 +1251,16 @@ public final class ContactsContract {
* <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>
+ * <td>Row ID. Sync adapters should try to preserve row IDs during updates. In other words,
+ * it is much better for a sync adapter to update a raw contact rather than to delete and
+ * re-insert it.</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
+ * <td>The ID of the row in the {@link ContactsContract.Contacts} table
+ * 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>
@@ -1238,7 +1291,8 @@ public final class ContactsContract {
* <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>
+ * After that, this value is typically updated via
+ * {@link ContactsContract.Contacts#markAsContacted}.</td>
* </tr>
* <tr>
* <td>long</td>
@@ -1247,14 +1301,16 @@ public final class ContactsContract {
* <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>
+ * After that, this value is typically updated via
+ * {@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:
+ * Changing this field immediately affects the corresponding aggregate contact:
* if any raw contacts in that aggregate contact are starred, then the contact
* itself is marked as starred.</td>
* </tr>
@@ -1267,7 +1323,8 @@ public final class ContactsContract {
* {@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}
+ * ringtone on a contact, use the field {@link ContactsContract.Contacts#CUSTOM_RINGTONE
+ * Contacts.CUSTOM_RINGTONE}
* instead.</td>
* </tr>
* <tr>
@@ -1284,16 +1341,27 @@ public final class ContactsContract {
* <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
+ * {@link #ACCOUNT_TYPE} identifies a specific account.
+ * For example, this will be the Gmail address if it is a Google 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>
+ * <td>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * To ensure uniqueness, new account types should be chosen according to the
+ * Java package naming convention. Thus a Google account is of type "com.google".
+ * </p>
+ * </td>
* </tr>
* <tr>
* <td>String</td>
@@ -1302,8 +1370,8 @@ public final class ContactsContract {
* <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
+ * will have an account name and type, but no source id. This
+ * indicates 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>
@@ -1335,7 +1403,8 @@ public final class ContactsContract {
* <td>String</td>
* <td>{@link #SYNC1}</td>
* <td>read/write</td>
- * <td>Generic column for use by sync adapters. Content provider
+ * <td>Generic column provided for arbitrary use by sync adapters.
+ * The content provider
* stores this information on behalf of the sync adapter but does not
* interpret it in any way.
* </td>
@@ -1372,46 +1441,69 @@ public final class ContactsContract {
}
/**
- * The content:// style URI for this table
+ * The content:// style URI for this table, which requests a directory of
+ * raw contact rows matching the selection criteria.
*/
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "raw_contacts");
/**
- * The MIME type of {@link #CONTENT_URI} providing a directory of
- * people.
+ * The MIME type of the results from {@link #CONTENT_URI} when a specific
+ * ID value is not provided, and multiple raw contacts may be returned.
*/
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact";
/**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
- * person.
+ * The MIME type of the results when a raw contact ID is appended to {@link #CONTENT_URI},
+ * yielding a subdirectory of a single person.
*/
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/raw_contact";
/**
- * Aggregation mode: aggregate asynchronously.
+ * Aggregation mode: aggregate immediately after insert or update operation(s) are complete.
*/
public static final int AGGREGATION_MODE_DEFAULT = 0;
/**
- * Aggregation mode: aggregate at the time the raw contact is inserted/updated.
- * TODO: deprecate. Aggregation is now synchronous, this value is a no-op
+ * Do not use.
+ *
+ * TODO: deprecate in favor of {@link #AGGREGATION_MODE_DEFAULT}
*/
public static final int AGGREGATION_MODE_IMMEDIATE = 1;
/**
- * If {@link #AGGREGATION_MODE} is {@link #AGGREGATION_MODE_SUSPENDED}, changes
- * to the raw contact do not cause its aggregation to be revisited. Note that changing
+ * <p>
+ * Aggregation mode: aggregation suspended temporarily, and is likely to be resumed later.
+ * Changes to the raw contact will update the associated aggregate contact but will not
+ * result in any change in how the contact is aggregated. Similar to
+ * {@link #AGGREGATION_MODE_DISABLED}, but maintains a link to the corresponding
+ * {@link Contacts} aggregate.
+ * </p>
+ * <p>
+ * This can be used to postpone aggregation until after a series of updates, for better
+ * performance and/or user experience.
+ * </p>
+ * <p>
+ * Note that changing
* {@link #AGGREGATION_MODE} from {@link #AGGREGATION_MODE_SUSPENDED} to
- * {@link #AGGREGATION_MODE_DEFAULT} does not trigger an aggregation pass. Any subsequent
+ * {@link #AGGREGATION_MODE_DEFAULT} does not trigger an aggregation pass, but any
+ * subsequent
* change to the raw contact's data will.
+ * </p>
*/
public static final int AGGREGATION_MODE_SUSPENDED = 2;
/**
- * Aggregation mode: never aggregate this raw contact (note that the raw contact will not
- * have a corresponding Aggregate and therefore will not be included in Aggregates
- * query results.)
+ * <p>
+ * Aggregation mode: never aggregate this raw contact. The raw contact will not
+ * have a corresponding {@link Contacts} aggregate and therefore will not be included in
+ * {@link Contacts} query results.
+ * </p>
+ * <p>
+ * For example, this mode can be used for a raw contact that is marked for deletion while
+ * waiting for the deletion to occur on the server side.
+ * </p>
+ *
+ * @see #AGGREGATION_MODE_SUSPENDED
*/
public static final int AGGREGATION_MODE_DISABLED = 3;
@@ -1441,9 +1533,11 @@ public final class ContactsContract {
}
/**
- * A sub-directory of a single raw contact that contains all of their
+ * A sub-directory of a single raw contact that contains all of its
* {@link ContactsContract.Data} rows. To access this directory
* append {@link Data#CONTENT_DIRECTORY} to the contact URI.
+ *
+ * TODO: deprecate in favor of {@link RawContacts.Entity}.
*/
public static final class Data implements BaseColumns, DataColumns {
/**
@@ -1460,26 +1554,24 @@ public final class ContactsContract {
/**
* <p>
- * A sub-directory of a single raw contact that contains all of their
+ * A sub-directory of a single raw contact that contains all of its
* {@link ContactsContract.Data} rows. To access this directory append
* {@link #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
+ * Entity has two ID fields: {@link #_ID} for the raw contact
+ * and {@link #DATA_ID} for the data rows.
+ * 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.
+ * null.
+ * </p>
+ * <p>
+ * Entity reads all
+ * data for a raw contact in one transaction, to guarantee
+ * consistency.
+ * </p>
*/
public static final class Entity implements BaseColumns, DataColumns {
/**
@@ -1501,6 +1593,11 @@ public final class ContactsContract {
public static final String DATA_ID = "data_id";
}
+ /**
+ * TODO: javadoc
+ * @param cursor
+ * @return
+ */
public static EntityIterator newEntityIterator(Cursor cursor) {
return new EntityIteratorImpl(cursor);
}
@@ -1839,7 +1936,12 @@ public final class ContactsContract {
* By convention, {@link #DATA15} is used for storing BLOBs (binary data).
* </p>
* <p>
- * Typically you should refrain from introducing new kinds of data for an other
+ * The sync adapter for a given account type must correctly handle every data type
+ * used in the corresponding raw contacts. Otherwise it could result in lost or
+ * corrupted data.
+ * </p>
+ * <p>
+ * Similarly, you should refrain from introducing new kinds of data for an other
* party's 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
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index a93cee7..3774156 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -27,7 +27,7 @@ import android.net.Uri;
*/
// For 1.0 the download manager can't deal with abuse from untrusted apps, so
// this API is hidden.
-public final class Downloads implements BaseColumns {
+public final class Downloads {
private Downloads() {}
/**
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index f350d13..e496d97 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -247,4 +247,5 @@ final class JWebCoreJavaBridge extends Handler {
private native void nativeUpdatePluginDirectories(String[] directories,
boolean reload);
public native void setNetworkOnLine(boolean online);
+ public native void setNetworkType(String type, String subtype);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 09ed931..db5641c 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -80,6 +80,7 @@ import java.io.IOException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
+import java.util.HashMap;
import java.util.Map;
import junit.framework.Assert;
@@ -1132,6 +1133,16 @@ public class WebView extends AbsoluteLayout
}
/**
+ * Inform WebView about the current network type.
+ * {@hide}
+ */
+ public void setNetworkType(String type, String subtype) {
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("type", type);
+ map.put("subtype", subtype);
+ mWebViewCore.sendMessage(EventHub.SET_NETWORK_TYPE, map);
+ }
+ /**
* Save the state of this WebView used in
* {@link android.app.Activity#onSaveInstanceState}. Please note that this
* method no longer stores the display data for this WebView. The previous
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 949b318..d509bb4 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -878,6 +878,8 @@ final class WebViewCore {
static final int HIDE_FULLSCREEN = 182;
+ static final int SET_NETWORK_TYPE = 183;
+
// private message ids
private static final int DESTROY = 200;
@@ -1110,6 +1112,16 @@ final class WebViewCore {
.setNetworkOnLine(msg.arg1 == 1);
break;
+ case SET_NETWORK_TYPE:
+ if (BrowserFrame.sJavaBridge == null) {
+ throw new IllegalStateException("No WebView " +
+ "has been created in this process!");
+ }
+ Map<String, String> map = (Map<String, String>) msg.obj;
+ BrowserFrame.sJavaBridge
+ .setNetworkType(map.get("type"), map.get("subtype"));
+ break;
+
case CLEAR_CACHE:
clearCache(msg.arg1 == 1);
break;
diff --git a/keystore/java/android/security/SystemKeyStore.java b/keystore/java/android/security/SystemKeyStore.java
index 452125a..61a4293 100644
--- a/keystore/java/android/security/SystemKeyStore.java
+++ b/keystore/java/android/security/SystemKeyStore.java
@@ -35,6 +35,7 @@ import javax.crypto.SecretKey;
public class SystemKeyStore {
private static final String SYSTEM_KEYSTORE_DIRECTORY = "misc/systemkeys";
+ private static final String KEY_FILE_EXTENSION = ".sks";
private static SystemKeyStore mInstance = new SystemKeyStore();
private SystemKeyStore() { }
@@ -43,6 +44,28 @@ public class SystemKeyStore {
return mInstance;
}
+ public static String toHexString(byte[] keyData) {
+ if (keyData == null) {
+ return null;
+ }
+ int keyLen = keyData.length;
+ int expectedStringLen = keyData.length * 2;
+ StringBuilder sb = new StringBuilder(expectedStringLen);
+ for (int i = 0; i < keyData.length; i++) {
+ String hexStr = Integer.toString(keyData[i] & 0x00FF, 16);
+ if (hexStr.length() == 1) {
+ hexStr = "0" + hexStr;
+ }
+ sb.append(hexStr);
+ }
+ return sb.toString();
+ }
+
+ public String generateNewKeyHexString(int numBits, String algName, String keyName)
+ throws NoSuchAlgorithmException {
+ return toHexString(generateNewKey(numBits, algName, keyName));
+ }
+
public byte[] generateNewKey(int numBits, String algName, String keyName)
throws NoSuchAlgorithmException {
@@ -78,10 +101,14 @@ public class SystemKeyStore {
private File getKeyFile(String keyName) {
File sysKeystoreDir = new File(Environment.getDataDirectory(),
SYSTEM_KEYSTORE_DIRECTORY);
- File keyFile = new File(sysKeystoreDir, keyName);
+ File keyFile = new File(sysKeystoreDir, keyName + KEY_FILE_EXTENSION);
return keyFile;
}
+ public String retrieveKeyHexString(String keyName) {
+ return toHexString(retrieveKey(keyName));
+ }
+
public byte[] retrieveKey(String keyName) {
File keyFile = getKeyFile(keyName);
diff --git a/keystore/tests/src/android/security/SystemKeyStoreTest.java b/keystore/tests/src/android/security/SystemKeyStoreTest.java
index a85f889..bbeceeb 100644
--- a/keystore/tests/src/android/security/SystemKeyStoreTest.java
+++ b/keystore/tests/src/android/security/SystemKeyStoreTest.java
@@ -32,6 +32,7 @@ import android.test.suitebuilder.annotation.MediumTest;
public class SystemKeyStoreTest extends ActivityUnitTestCase<Activity> {
private static final String keyName = "TestKey";
+ private static final String keyName2 = "TestKey2";
private SystemKeyStore mSysKeyStore = null;
public SystemKeyStoreTest() {
@@ -43,6 +44,7 @@ public class SystemKeyStoreTest extends ActivityUnitTestCase<Activity> {
mSysKeyStore = SystemKeyStore.getInstance();
try {
mSysKeyStore.deleteKey(keyName);
+ mSysKeyStore.deleteKey(keyName2);
} catch (Exception e) { }
super.setUp();
}
@@ -51,6 +53,7 @@ public class SystemKeyStoreTest extends ActivityUnitTestCase<Activity> {
protected void tearDown() throws Exception {
try {
mSysKeyStore.deleteKey(keyName);
+ mSysKeyStore.deleteKey(keyName2);
} catch (Exception e) { }
super.tearDown();
}
@@ -67,6 +70,14 @@ public class SystemKeyStoreTest extends ActivityUnitTestCase<Activity> {
mSysKeyStore.deleteKey(keyName);
byte[] nullKey = mSysKeyStore.retrieveKey(keyName);
assertNull(nullKey);
+
+ String newKeyStr = mSysKeyStore.generateNewKeyHexString(128, "AES", keyName2);
+ assertNotNull(newKeyStr);
+ String recKeyStr = mSysKeyStore.retrieveKeyHexString(keyName2);
+ assertEquals(newKeyStr, recKeyStr);
+ mSysKeyStore.deleteKey(keyName2);
+ String nullKey2 = mSysKeyStore.retrieveKeyHexString(keyName);
+ assertNull(nullKey2);
} catch (Exception e) {
fail();
}
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index 9837845..c2e9f31 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -39,6 +39,11 @@ endif
ifneq ($(TARGET_SIMULATOR),true)
# we need to access the private Bionic header <bionic_tls.h>
+ # on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER
+ # behavior from the bionic Android.mk file
+ ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+ endif
LOCAL_C_INCLUDES += bionic/libc/private
endif
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 7353385..6b7020f 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -20,6 +20,11 @@ LOCAL_MODULE:= libEGL
ifeq ($(TARGET_SIMULATOR),true)
else
LOCAL_SHARED_LIBRARIES += libdl
+ # Bionic's private TLS header relies on the ARCH_ARM_HAVE_TLS_REGISTER to
+ # select the appropriate TLS codepath
+ ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+ endif
# we need to access the private Bionic header <bionic_tls.h>
LOCAL_C_INCLUDES += bionic/libc/private
endif
@@ -75,6 +80,9 @@ ifeq ($(TARGET_SIMULATOR),true)
else
LOCAL_SHARED_LIBRARIES += libdl
# we need to access the private Bionic header <bionic_tls.h>
+ ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+ endif
LOCAL_C_INCLUDES += bionic/libc/private
endif
@@ -108,6 +116,9 @@ ifeq ($(TARGET_SIMULATOR),true)
else
LOCAL_SHARED_LIBRARIES += libdl
# we need to access the private Bionic header <bionic_tls.h>
+ ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+ endif
LOCAL_C_INCLUDES += bionic/libc/private
endif
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 80129d0..5a8d35f 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -180,6 +180,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private ConnectivityService(Context context) {
if (DBG) Log.v(TAG, "ConnectivityService starting up");
+
+ // setup our unique device name
+ String id = Settings.Secure.getString(context.getContentResolver(),
+ Settings.Secure.ANDROID_ID);
+ if (id != null && id.length() > 0) {
+ String name = new String("android_").concat(id);
+ SystemProperties.set("net.hostname", name);
+ }
+
mContext = context;
mNetTrackers = new NetworkStateTracker[
ConnectivityManager.MAX_NETWORK_TYPE+1];
@@ -1248,11 +1257,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
info = (NetworkInfo) msg.obj;
int type = info.getType();
NetworkInfo.State state = info.getState();
- if(mNetAttributes[type].mLastState == state) {
+ if (mNetAttributes[type].mLastState == state) {
if (DBG) {
// TODO - remove this after we validate the dropping doesn't break anything
Log.d(TAG, "Dropping ConnectivityChange for " +
- info.getTypeName() +": " +
+ info.getTypeName() + ": " +
state + "/" + info.getDetailedState());
}
return;
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 5566979..170477f 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -455,7 +455,9 @@ class PackageManagerService extends IPackageManager.Stub {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);
- int scanMode = SCAN_MONITOR;
+ // Set flag to monitor and not change apk file paths when
+ // scanning install directories.
+ int scanMode = SCAN_MONITOR | SCAN_NO_PATHS;
if (mNoDexOpt) {
Log.w(TAG, "Running ENG build: no pre-dexopt!");
scanMode |= SCAN_NO_DEX;
@@ -573,12 +575,12 @@ class PackageManagerService extends IPackageManager.Stub {
mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
mFrameworkInstallObserver.startWatching();
scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM,
- scanMode | SCAN_NO_DEX | SCAN_NO_PATHS);
+ scanMode | SCAN_NO_DEX);
mSystemAppDir = new File(Environment.getRootDirectory(), "app");
mSystemInstallObserver = new AppDirObserver(
mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
mSystemInstallObserver.startWatching();
- scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM, scanMode | SCAN_NO_PATHS);
+ scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM, scanMode);
mAppInstallDir = new File(dataDir, "app");
if (mInstaller == null) {
// Make sure these dirs exist, when we are running in
@@ -3754,7 +3756,7 @@ class PackageManagerService extends IPackageManager.Stub {
(mIsRom ? PackageParser.PARSE_IS_SYSTEM : 0) |
PackageParser.PARSE_CHATTY |
PackageParser.PARSE_MUST_BE_APK,
- SCAN_MONITOR);
+ SCAN_MONITOR | SCAN_NO_PATHS);
if (p != null) {
synchronized (mPackages) {
grantPermissionsLP(p, false);
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index bee0930..42c0254 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -43,6 +43,9 @@ import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.text.format.DateFormat;
+import android.text.style.RelativeSizeSpan;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -61,6 +64,7 @@ import com.android.internal.telephony.cdma.EriInfo;
import com.android.internal.telephony.cdma.TtyIntent;
import com.android.server.am.BatteryStatsService;
+import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
@@ -532,10 +536,69 @@ public class StatusBarPolicy {
sInstance = new StatusBarPolicy(context, service);
}
+ private final CharSequence getSmallTime() {
+ boolean b24 = DateFormat.is24HourFormat(mContext);
+ int res;
+
+ if (b24) {
+ res = R.string.twenty_four_hour_time_format;
+ } else {
+ res = R.string.twelve_hour_time_format;
+ }
+
+ String format = mContext.getString(res);
+
+ /*
+ * Search for an unquoted "a" in the format string, so we can
+ * add dummy characters around it to let us find it again after
+ * formatting and change its size.
+ */
+ int a = -1;
+ boolean quoted = false;
+ for (int i = 0; i < format.length(); i++) {
+ char c = format.charAt(i);
+
+ if (c == '\'') {
+ quoted = !quoted;
+ }
+
+ if (!quoted && c == 'a') {
+ a = i;
+ break;
+ }
+ }
+
+ final char MAGIC1 = '\uEF00';
+ final char MAGIC2 = '\uEF01';
+
+ if (a >= 0) {
+ format = format.substring(0, a) + MAGIC1 + "a" + MAGIC2 +
+ format.substring(a + 1);
+ }
+
+ String result = new SimpleDateFormat(format).format(mCalendar.getTime());
+
+ int magic1 = result.indexOf(MAGIC1);
+ int magic2 = result.indexOf(MAGIC2);
+
+ if (magic1 >= 0 && magic2 > magic1) {
+ SpannableStringBuilder formatted = new SpannableStringBuilder(result);
+
+ formatted.setSpan(new RelativeSizeSpan(0.7f), magic1, magic2,
+ Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+
+ formatted.delete(magic2, magic2 + 1);
+ formatted.delete(magic1, magic1 + 1);
+
+ return formatted;
+ } else {
+ return result;
+ }
+ }
+
private final void updateClock() {
mCalendar.setTimeInMillis(System.currentTimeMillis());
- mClockData.text = DateFormat.getTimeFormat(mContext)
- .format(mCalendar.getTime());
+ mClockData.text = getSmallTime();
mService.updateIcon(mClockIcon, mClockData, null);
}