Merge "Recycle MotionEvents properly in GestureDetector"
diff --git a/api/current.xml b/api/current.xml
index 444b002..40739da 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -13833,7 +13833,7 @@
>
<parameter name="parcel" type="android.os.Parcel">
</parameter>
-<parameter name="flags" type="int">
+<parameter name="flagz" type="int">
</parameter>
</method>
<field name="CREATOR"
@@ -38899,6 +38899,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_PHYSICAL_DOCK_STATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.intent.extra.PHYSICAL_DOCK_STATE""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_REMOTE_INTENT_TOKEN"
type="java.lang.String"
transient="false"
@@ -60401,6 +60412,102 @@
</parameter>
</constructor>
</class>
+<class name="ImageFormat"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ImageFormat"
+ type="android.graphics.ImageFormat"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getBitsPerPixel"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="format" type="int">
+</parameter>
+</method>
+<field name="JPEG"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="256"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NV16"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NV21"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RGB_565"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="UNKNOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="YUY2"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="20"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="Interpolator"
extends="java.lang.Object"
abstract="false"
@@ -64462,7 +64569,7 @@
value="256"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -64616,7 +64723,7 @@
value="17"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -64627,7 +64734,7 @@
value="20"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -64638,7 +64745,7 @@
value="16"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -119450,6 +119557,17 @@
visibility="public"
>
</field>
+<field name="OperationFailedStorageBusy"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="OperationFailedStorageMounted"
type="int"
transient="false"
@@ -136998,6 +137116,21 @@
<parameter name="context" type="android.content.Context">
</parameter>
</method>
+<method name="createRecognitionManager"
+ return="android.speech.RecognitionManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="serviceComponent" type="android.content.ComponentName">
+</parameter>
+</method>
<method name="destroy"
return="void"
abstract="false"
@@ -137396,6 +137529,30 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="getVoiceDetailsIntent"
+ return="android.content.Intent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<field name="ACTION_GET_LANGUAGE_DETAILS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.speech.action.GET_LANGUAGE_DETAILS""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_RECOGNIZE_SPEECH"
type="java.lang.String"
transient="false"
@@ -137418,6 +137575,17 @@
visibility="public"
>
</field>
+<field name="DETAILS_META_DATA"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.speech.DETAILS""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_LANGUAGE"
type="java.lang.String"
transient="false"
@@ -137440,6 +137608,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_LANGUAGE_PREFERENCE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.speech.extra.LANGUAGE_PREFERENCE""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_MAX_RESULTS"
type="java.lang.String"
transient="false"
@@ -137539,6 +137718,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_SUPPORTED_LANGUAGES"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.speech.extra.SUPPORTED_LANGUAGES""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="LANGUAGE_MODEL_FREE_FORM"
type="java.lang.String"
transient="false"
@@ -172890,6 +173080,19 @@
visibility="public"
>
</method>
+<method name="dispatchConfigurationChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="newConfig" type="android.content.res.Configuration">
+</parameter>
+</method>
<method name="dispatchDisplayHint"
return="void"
abstract="false"
@@ -174581,6 +174784,19 @@
visibility="public"
>
</method>
+<method name="onConfigurationChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="newConfig" type="android.content.res.Configuration">
+</parameter>
+</method>
<method name="onCreateContextMenu"
return="void"
abstract="false"
@@ -190965,6 +191181,17 @@
visibility="public"
>
</method>
+<method name="getBlockNetworkLoads"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getBuiltInZoomControls"
return="boolean"
abstract="false"
@@ -191393,6 +191620,19 @@
<parameter name="flag" type="boolean">
</parameter>
</method>
+<method name="setBlockNetworkLoads"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="flag" type="boolean">
+</parameter>
+</method>
<method name="setBuiltInZoomControls"
return="void"
abstract="false"
diff --git a/camera/libcameraservice/FakeCamera.cpp b/camera/libcameraservice/FakeCamera.cpp
index 3daf47d..6749899 100644
--- a/camera/libcameraservice/FakeCamera.cpp
+++ b/camera/libcameraservice/FakeCamera.cpp
@@ -234,7 +234,7 @@
uint8_t y0, y1, u, v;
pixels = inputRGB[i];
- temp = (ALPHA*(pixels & 0x001F) + BETA*(pixels>>11) );
+ temp = (BETA*(pixels & 0x001F) + ALPHA*(pixels>>11) );
y0 = y_tab[(temp>>SHIFT1) + ((pixels>>3) & 0x00FC)];
G_ds += (pixels>>1) & 0x03E0;
@@ -242,7 +242,7 @@
R_ds += (pixels>>6) & 0x03E0;
pixels = inputRGB[i+1];
- temp = (ALPHA*(pixels & 0x001F) + BETA*(pixels>>11) );
+ temp = (BETA*(pixels & 0x001F) + ALPHA*(pixels>>11) );
y1 = y_tab[(temp>>SHIFT1) + ((pixels>>3) & 0x00FC)];
G_ds += (pixels>>1) & 0x03E0;
@@ -255,8 +255,8 @@
tmp = R_ds - B_ds;
- u = cb_tab[(((R_ds-G_ds)<<SHIFT2) + DELTA*tmp)>>(SHIFT2+2)];
- v = cr_tab[(((B_ds-G_ds)<<SHIFT2) - GAMMA*tmp)>>(SHIFT2+2)];
+ u = cb_tab[(((B_ds-G_ds)<<SHIFT2) - GAMMA*tmp)>>(SHIFT2+2)];
+ v = cr_tab[(((R_ds-G_ds)<<SHIFT2) + DELTA*tmp)>>(SHIFT2+2)];
tempY[0] = y0;
tempY[1] = y1;
diff --git a/common/java/com/android/common/OperationScheduler.java b/common/java/com/android/common/OperationScheduler.java
index c7b12d3..0c7ca83 100644
--- a/common/java/com/android/common/OperationScheduler.java
+++ b/common/java/com/android/common/OperationScheduler.java
@@ -158,12 +158,35 @@
time = Math.max(time, moratoriumTimeMillis);
}
time = Math.max(time, lastSuccessTimeMillis + options.minTriggerMillis);
- time = Math.max(time, lastErrorTimeMillis + options.backoffFixedMillis +
- options.backoffIncrementalMillis * errorCount);
+ if (errorCount > 0) {
+ time = Math.max(time, lastErrorTimeMillis + options.backoffFixedMillis +
+ options.backoffIncrementalMillis * errorCount);
+ }
return time;
}
/**
+ * Return the last time the operation completed. Does not modify any state.
+ *
+ * @return the wall clock time when {@link #onSuccess()} was last called.
+ */
+ public long getLastSuccessTimeMillis() {
+ return mStorage.getLong(PREFIX + "lastSuccessTimeMillis", 0);
+ }
+
+ /**
+ * Return the last time the operation was attempted. Does not modify any state.
+ *
+ * @return the wall clock time when {@link #onSuccess()} or {@link
+ * #onTransientError()} was last called.
+ */
+ public long getLastAttemptTimeMillis() {
+ return Math.max(
+ mStorage.getLong(PREFIX + "lastSuccessTimeMillis", 0),
+ mStorage.getLong(PREFIX + "lastErrorTimeMillis", 0));
+ }
+
+ /**
* Fetch a {@link SharedPreferences} property, but force it to be before
* a certain time, updating the value if necessary. This is to recover
* gracefully from clock rollbacks which could otherwise strand our timers.
@@ -273,9 +296,7 @@
* where there is reason to hope things might start working better.
*/
public void resetTransientError() {
- mStorage.edit()
- .remove(PREFIX + "lastErrorTimeMillis")
- .remove(PREFIX + "errorCount").commit();
+ mStorage.edit().remove(PREFIX + "errorCount").commit();
}
/**
diff --git a/common/tests/src/com/android/common/OperationSchedulerTest.java b/common/tests/src/com/android/common/OperationSchedulerTest.java
index 28178b5..f728eea 100644
--- a/common/tests/src/com/android/common/OperationSchedulerTest.java
+++ b/common/tests/src/com/android/common/OperationSchedulerTest.java
@@ -28,6 +28,8 @@
OperationScheduler scheduler = new OperationScheduler(storage);
OperationScheduler.Options options = new OperationScheduler.Options();
assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
+ assertEquals(0, scheduler.getLastSuccessTimeMillis());
+ assertEquals(0, scheduler.getLastAttemptTimeMillis());
long beforeTrigger = System.currentTimeMillis();
scheduler.setTriggerTimeMillis(beforeTrigger + 1000000);
@@ -49,6 +51,9 @@
long beforeError = System.currentTimeMillis();
scheduler.onTransientError();
long afterError = System.currentTimeMillis();
+ assertEquals(0, scheduler.getLastSuccessTimeMillis());
+ assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis());
+ assertTrue(afterError >= scheduler.getLastAttemptTimeMillis());
assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
options.backoffFixedMillis = 1000000;
options.backoffIncrementalMillis = 500000;
@@ -59,9 +64,18 @@
beforeError = System.currentTimeMillis();
scheduler.onTransientError();
afterError = System.currentTimeMillis();
+ assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis());
+ assertTrue(afterError >= scheduler.getLastAttemptTimeMillis());
assertTrue(beforeError + 2000000 <= scheduler.getNextTimeMillis(options));
assertTrue(afterError + 2000000 >= scheduler.getNextTimeMillis(options));
+ // Reset transient error: no backoff interval
+ scheduler.resetTransientError();
+ assertEquals(0, scheduler.getLastSuccessTimeMillis());
+ assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
+ assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis());
+ assertTrue(afterError >= scheduler.getLastAttemptTimeMillis());
+
// Permanent error holds true even if transient errors are reset
// However, we remember that the transient error was reset...
scheduler.onPermanentError();
@@ -75,6 +89,10 @@
long beforeSuccess = System.currentTimeMillis();
scheduler.onSuccess();
long afterSuccess = System.currentTimeMillis();
+ assertTrue(beforeSuccess <= scheduler.getLastAttemptTimeMillis());
+ assertTrue(afterSuccess >= scheduler.getLastAttemptTimeMillis());
+ assertTrue(beforeSuccess <= scheduler.getLastSuccessTimeMillis());
+ assertTrue(afterSuccess >= scheduler.getLastSuccessTimeMillis());
assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
// The moratorium is not reset by success!
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 4761f98..bf9e07d 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -66,10 +66,10 @@
* The event types an {@link AccessibilityService} is interested in.
*
* @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED
+ * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED
* @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED
* @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED
* @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED
- * @see android.view.accessibility.AccessibilityEvent#TYPE_ACTIVITY_STARTED
* @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
* @see android.view.accessibility.AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED
*/
@@ -115,7 +115,7 @@
return 0;
}
- public void writeToParcel(Parcel parcel, int flags) {
+ public void writeToParcel(Parcel parcel, int flagz) {
parcel.writeInt(eventTypes);
parcel.writeStringArray(packageNames);
parcel.writeInt(feedbackType);
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index be2bdbe..8bc7428 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -296,8 +296,7 @@
* <ul>
* <li> {@link AccountManager#KEY_INTENT}, or
* <li> {@link AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of
- * the account that was added, plus {@link AccountManager#KEY_AUTHTOKEN} if an authTokenType
- * was supplied, or
+ * the account that was added, or
* <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
* indicate an error
* </ul>
@@ -368,8 +367,7 @@
* <ul>
* <li> {@link AccountManager#KEY_INTENT}, or
* <li> {@link AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of
- * the account that was added, plus {@link AccountManager#KEY_AUTHTOKEN} if an authTokenType
- * was supplied, or
+ * the account that was added, or
* <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
* indicate an error
* </ul>
@@ -378,7 +376,7 @@
*/
public abstract Bundle updateCredentials(AccountAuthenticatorResponse response,
Account account, String authTokenType, Bundle options) throws NetworkErrorException;
-
+
/**
* Checks if the account supports all the specified authenticator specific features.
* @param response to send the result back to the AccountManager, will never be null
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index be15ac9..43a0f30 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -67,6 +67,8 @@
* cause the running thread to block until the result is returned. Keep in mind that one
* should not block the main thread in this way. Instead one should either use a callback,
* thus making the call asynchronous, or make the blocking call on a separate thread.
+ * getResult() will throw an {@link IllegalStateException} if you call it from the main thread
+ * before the request has completed, i.e. before the callback has been invoked.
* <p>
* If one wants to ensure that the callback is invoked from a specific handler then they should
* pass the handler to the request. This makes it easier to ensure thread-safety by running
@@ -149,6 +151,8 @@
* Get the password that is associated with the account. Returns null if the account does
* not exist.
* <p>
+ * It is safe to call this method from the main thread.
+ * <p>
* Requires that the caller has permission
* {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
* with the same UID as the Authenticator for the account.
@@ -166,6 +170,8 @@
* Get the user data named by "key" that is associated with the account.
* Returns null if the account does not exist or if it does not have a value for key.
* <p>
+ * It is safe to call this method from the main thread.
+ * <p>
* Requires that the caller has permission
* {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
* with the same UID as the Authenticator for the account.
@@ -185,6 +191,8 @@
* @return an array that contains all the authenticators known to the AccountManager service.
* This array will be empty if there are no authenticators and will never return null.
* <p>
+ * It is safe to call this method from the main thread.
+ * <p>
* No permission is required to make this call.
*/
public AuthenticatorDescription[] getAuthenticatorTypes() {
@@ -201,6 +209,8 @@
* @return an array that contains all the accounts known to the AccountManager service.
* This array will be empty if there are no accounts and will never return null.
* <p>
+ * It is safe to call this method from the main thread.
+ * <p>
* Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}
*/
public Account[] getAccounts() {
@@ -219,6 +229,8 @@
* @return an array that contains the accounts that match the specified type. This array
* will be empty if no accounts match. It will never return null.
* <p>
+ * It is safe to call this method from the main thread.
+ * <p>
* Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}
*/
public Account[] getAccountsByType(String type) {
@@ -243,6 +255,22 @@
* {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
* which will then block until the request completes.
* <p>
+ * Do not block the main thread waiting this method's result.
+ * <p>
+ * Not allowed from main thread (but allowed from other threads):
+ * <pre>
+ * Boolean result = hasFeatures(account, features, callback, handler).getResult();
+ * </pre>
+ * Allowed from main thread:
+ * <pre>
+ * hasFeatures(account, features, new AccountManagerCallback<Boolean>() {
+ * public void run(AccountManagerFuture<Boolean> future) {
+ * Boolean result = future.getResult();
+ * // use result
+ * }
+ * }, handler);
+ * </pre>
+ * <p>
* Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}.
*
* @param account The {@link Account} to test
@@ -274,6 +302,8 @@
/**
* Add an account to the AccountManager's set of known accounts.
* <p>
+ * It is safe to call this method from the main thread.
+ * <p>
* Requires that the caller has permission
* {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
* with the same UID as the Authenticator for the account.
@@ -304,6 +334,22 @@
* {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
* which will then block until the request completes.
* <p>
+ * Do not block the main thread waiting this method's result.
+ * <p>
+ * Not allowed from main thread (but allowed from other threads):
+ * <pre>
+ * Boolean result = removeAccount(account, callback, handler).getResult();
+ * </pre>
+ * Allowed from main thread:
+ * <pre>
+ * removeAccount(account, new AccountManagerCallback<Boolean>() {
+ * public void run(AccountManagerFuture<Boolean> future) {
+ * Boolean result = future.getResult();
+ * // use result
+ * }
+ * }, handler);
+ * </pre>
+ * <p>
* Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param account The {@link Account} to remove
@@ -334,6 +380,8 @@
* Removes the given authtoken. If this authtoken does not exist for the given account type
* then this call has no effect.
* <p>
+ * It is safe to call this method from the main thread.
+ * <p>
* Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
* @param accountType the account type of the authtoken to invalidate
* @param authToken the authtoken to invalidate
@@ -353,6 +401,8 @@
* asking the authenticaticor to generate one. If the account or the
* authtoken do not exist then null is returned.
* <p>
+ * It is safe to call this method from the main thread.
+ * <p>
* Requires that the caller has permission
* {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
* with the same UID as the Authenticator for the account.
@@ -381,6 +431,8 @@
* Sets the password for the account. The password may be null. If the account does not exist
* then this call has no affect.
* <p>
+ * It is safe to call this method from the main thread.
+ * <p>
* Requires that the caller has permission
* {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
* with the same UID as the Authenticator for the account.
@@ -404,6 +456,8 @@
* Sets the password for account to null. If the account does not exist then this call
* has no effect.
* <p>
+ * It is safe to call this method from the main thread.
+ * <p>
* Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
* @param account the account whose password is to be cleared. Must not be null.
*/
@@ -424,6 +478,8 @@
* Sets account's userdata named "key" to the specified value. If the account does not
* exist then this call has no effect.
* <p>
+ * It is safe to call this method from the main thread.
+ * <p>
* Requires that the caller has permission
* {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
* with the same UID as the Authenticator for the account.
@@ -452,6 +508,8 @@
* Sets the authtoken named by "authTokenType" to the value specified by authToken.
* If the account does not exist then this call has no effect.
* <p>
+ * It is safe to call this method from the main thread.
+ * <p>
* Requires that the caller has permission
* {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
* with the same UID as the Authenticator for the account.
@@ -473,6 +531,8 @@
* {@link #getAuthToken(Account, String, boolean, AccountManagerCallback, Handler)}
* then extracts and returns the value of {@link #KEY_AUTHTOKEN} from its result.
* <p>
+ * It is not safe to call this method from the main thread. See {@link #getAuthToken}.
+ * <p>
* Requires that the caller has permission {@link android.Manifest.permission#USE_CREDENTIALS}.
* @param account the account whose authtoken is to be retrieved, must not be null
* @param authTokenType the type of authtoken to retrieve
@@ -505,9 +565,8 @@
* in the result.
* <p>
* If the authenticator needs to prompt the user for credentials it will return an intent to
- * the activity that will do the prompting. If an activity is supplied then that activity
- * will be used to launch the intent and the result will come from it. Otherwise a result will
- * be returned that contains the intent.
+ * an activity that will do the prompting. The supplied activity will be used to launch the
+ * intent and the result will come from the launched activity.
* <p>
* This call returns immediately but runs asynchronously and the result is accessed via the
* {@link AccountManagerFuture} that is returned. This future is also passed as the sole
@@ -518,6 +577,23 @@
* {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
* which will then block until the request completes.
* <p>
+ * Do not block the main thread waiting this method's result.
+ * <p>
+ * Not allowed from main thread (but allowed from other threads):
+ * <pre>
+ * Bundle result = getAuthToken(
+ * account, authTokenType, options, activity, callback, handler).getResult();
+ * </pre>
+ * Allowed from main thread:
+ * <pre>
+ * getAuthToken(account, authTokenType, options, activity, new AccountManagerCallback<Bundle>() {
+ * public void run(AccountManagerFuture<Bundle> future) {
+ * Bundle result = future.getResult();
+ * // use result
+ * }
+ * }, handler);
+ * </pre>
+ * <p>
* Requires that the caller has permission {@link android.Manifest.permission#USE_CREDENTIALS}.
*
* @param account The account whose credentials are to be updated.
@@ -525,8 +601,9 @@
* May be null.
* @param options authenticator specific options for the request
* @param activity If the authenticator returns a {@link #KEY_INTENT} in the result then
- * the intent will be started with this activity. If activity is null then the result will
- * be returned as-is.
+ * the intent will be started with this activity. If you do not with to have the intent
+ * started automatically then use the other form,
+ * {@link #getAuthToken(Account, String, boolean, AccountManagerCallback, android.os.Handler)}
* @param callback A callback to invoke when the request completes. If null then
* no callback is invoked.
* @param handler The {@link Handler} to use to invoke the callback. If null then the
@@ -578,6 +655,23 @@
* {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
* which will then block until the request completes.
* <p>
+ * Do not block the main thread waiting this method's result.
+ * <p>
+ * Not allowed from main thread (but allowed from other threads):
+ * <pre>
+ * Bundle result = getAuthToken(
+ * account, authTokenType, notifyAuthFailure, callback, handler).getResult();
+ * </pre>
+ * Allowed from main thread:
+ * <pre>
+ * getAuthToken(account, authTokenType, notifyAuthFailure, new AccountManagerCallback<Bundle>() {
+ * public void run(AccountManagerFuture<Bundle> future) {
+ * Bundle result = future.getResult();
+ * // use result
+ * }
+ * }, handler);
+ * </pre>
+ * <p>
* Requires that the caller has permission {@link android.Manifest.permission#USE_CREDENTIALS}.
*
* @param account The account whose credentials are to be updated.
@@ -625,6 +719,23 @@
* {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
* which will then block until the request completes.
* <p>
+ * Do not block the main thread waiting this method's result.
+ * <p>
+ * Not allowed from main thread (but allowed from other threads):
+ * <pre>
+ * Bundle result = addAccount(
+ * account, authTokenType, features, options, activity, callback, handler).getResult();
+ * </pre>
+ * Allowed from main thread:
+ * <pre>
+ * addAccount(account, authTokenType, features, options, activity, new AccountManagerCallback<Bundle>() {
+ * public void run(AccountManagerFuture<Bundle> future) {
+ * Bundle result = future.getResult();
+ * // use result
+ * }
+ * }, handler);
+ * </pre>
+ * <p>
* Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param accountType The type of account to add. This must not be null.
@@ -646,7 +757,6 @@
* <ul>
* <li> {@link #KEY_INTENT}, or
* <li> {@link #KEY_ACCOUNT_NAME}, {@link #KEY_ACCOUNT_TYPE}
- * and {@link #KEY_AUTHTOKEN} (if an authTokenType was specified).
* </ul>
*/
public AccountManagerFuture<Bundle> addAccount(final String accountType,
@@ -667,6 +777,51 @@
}.start();
}
+ /**
+ * Queries for accounts that match the given account type and feature set.
+ * <p>
+ * This call returns immediately but runs asynchronously and the result is accessed via the
+ * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
+ * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
+ * method asynchronously then they will generally pass in a callback object that will get
+ * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
+ * they will generally pass null for the callback and instead call
+ * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
+ * which will then block until the request completes.
+ * <p>
+ * Do not block the main thread waiting this method's result.
+ * <p>
+ * Not allowed from main thread (but allowed from other threads):
+ * <pre>
+ * Account[] result =
+ * getAccountsByTypeAndFeatures(accountType, features, callback, handler).getResult();
+ * </pre>
+ * Allowed from main thread:
+ * <pre>
+ * getAccountsByTypeAndFeatures(accountType, features, new AccountManagerCallback<Account[]>() {
+ * public void run(AccountManagerFuture<Account[]> future) {
+ * Account[] result = future.getResult();
+ * // use result
+ * }
+ * }, handler);
+ * </pre>
+ * <p>
+ * Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}.
+ *
+ * @param type The type of {@link Account} to return. If null is passed in then an empty
+ * array will be returned.
+ * @param features the features with which to filter the accounts list. Each returned account
+ * will have all specified features. This may be null, which will mean the account list will
+ * not be filtered by features, making this functionally identical to
+ * {@link #getAccountsByType(String)}.
+ * @param callback A callback to invoke when the request completes. If null then
+ * no callback is invoked.
+ * @param handler The {@link Handler} to use to invoke the callback. If null then the
+ * main thread's {@link Handler} is used.
+ * @return an {@link AccountManagerFuture} that represents the future result of the call.
+ * The future result is a an {@link Account} array that contains accounts of the specified
+ * type that match all the requested features.
+ */
public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
final String type, final String[] features,
AccountManagerCallback<Account[]> callback, Handler handler) {
@@ -709,6 +864,23 @@
* {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
* which will then block until the request completes.
* <p>
+ * Do not block the main thread waiting this method's result.
+ * <p>
+ * Not allowed from main thread (but allowed from other threads):
+ * <pre>
+ * Bundle result = confirmCredentials(
+ * account, options, activity, callback, handler).getResult();
+ * </pre>
+ * Allowed from main thread:
+ * <pre>
+ * confirmCredentials(account, options, activity, new AccountManagerCallback<Bundle>() {
+ * public void run(AccountManagerFuture<Bundle> future) {
+ * Bundle result = future.getResult();
+ * // use result
+ * }
+ * }, handler);
+ * </pre>
+ * <p>
* Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param account The account whose credentials are to be checked
@@ -757,6 +929,23 @@
* {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
* which will then block until the request completes.
* <p>
+ * Do not block the main thread waiting this method's result.
+ * <p>
+ * Not allowed from main thread (but allowed from other threads):
+ * <pre>
+ * Bundle result = updateCredentials(
+ * account, authTokenType, options, activity, callback, handler).getResult();
+ * </pre>
+ * Allowed from main thread:
+ * <pre>
+ * updateCredentials(account, authTokenType, options, activity, new AccountManagerCallback<Bundle>() {
+ * public void run(AccountManagerFuture<Bundle> future) {
+ * Bundle result = future.getResult();
+ * // use result
+ * }
+ * }, handler);
+ * </pre>
+ * <p>
* Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param account The account whose credentials are to be updated.
@@ -775,7 +964,7 @@
* <ul>
* <li> {@link #KEY_INTENT}, which is to be used to prompt the user for the credentials
* <li> {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE} if the user enters the correct
- * credentials, and optionally a {@link #KEY_AUTHTOKEN} if an authTokenType was provided.
+ * credentials.
* </ul>
* If the user presses "back" then the request will be canceled.
*/
@@ -807,6 +996,22 @@
* {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
* which will then block until the request completes.
* <p>
+ * Do not block the main thread waiting this method's result.
+ * <p>
+ * Not allowed from main thread (but allowed from other threads):
+ * <pre>
+ * Bundle result = editProperties(accountType, activity, callback, handler).getResult();
+ * </pre>
+ * Allowed from main thread:
+ * <pre>
+ * editProperties(accountType, activity, new AccountManagerCallback<Bundle>() {
+ * public void run(AccountManagerFuture<Bundle> future) {
+ * Bundle result = future.getResult();
+ * // use result
+ * }
+ * }, handler);
+ * </pre>
+ * <p>
* Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param accountType The account type of the authenticator whose properties are to be edited.
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 7850124..770554e 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -466,7 +466,8 @@
public TestFeaturesSession(IAccountManagerResponse response,
Account account, String[] features) {
- super(response, account.type, false /* expectActivityLaunch */);
+ super(response, account.type, false /* expectActivityLaunch */,
+ true /* stripAuthTokenFromResult */);
mFeatures = features;
mAccount = account;
}
@@ -520,7 +521,8 @@
private class RemoveAccountSession extends Session {
final Account mAccount;
public RemoveAccountSession(IAccountManagerResponse response, Account account) {
- super(response, account.type, false /* expectActivityLaunch */);
+ super(response, account.type, false /* expectActivityLaunch */,
+ true /* stripAuthTokenFromResult */);
mAccount = account;
}
@@ -794,7 +796,8 @@
}
}
- new Session(response, account.type, expectActivityLaunch) {
+ new Session(response, account.type, expectActivityLaunch,
+ false /* stripAuthTokenFromResult */) {
protected String toDebugString(long now) {
if (loginOptions != null) loginOptions.keySet();
return super.toDebugString(now) + ", getAuthToken"
@@ -945,7 +948,8 @@
checkManageAccountsPermission();
long identityToken = clearCallingIdentity();
try {
- new Session(response, accountType, expectActivityLaunch) {
+ new Session(response, accountType, expectActivityLaunch,
+ true /* stripAuthTokenFromResult */) {
public void run() throws RemoteException {
mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
options);
@@ -970,7 +974,8 @@
checkManageAccountsPermission();
long identityToken = clearCallingIdentity();
try {
- new Session(response, account.type, expectActivityLaunch) {
+ new Session(response, account.type, expectActivityLaunch,
+ true /* stripAuthTokenFromResult */) {
public void run() throws RemoteException {
mAuthenticator.confirmCredentials(this, account, options);
}
@@ -990,7 +995,8 @@
checkManageAccountsPermission();
long identityToken = clearCallingIdentity();
try {
- new Session(response, account.type, expectActivityLaunch) {
+ new Session(response, account.type, expectActivityLaunch,
+ true /* stripAuthTokenFromResult */) {
public void run() throws RemoteException {
mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
}
@@ -1012,7 +1018,8 @@
checkManageAccountsPermission();
long identityToken = clearCallingIdentity();
try {
- new Session(response, accountType, expectActivityLaunch) {
+ new Session(response, accountType, expectActivityLaunch,
+ true /* stripAuthTokenFromResult */) {
public void run() throws RemoteException {
mAuthenticator.editProperties(this, mAccountType);
}
@@ -1034,7 +1041,8 @@
public GetAccountsByTypeAndFeatureSession(IAccountManagerResponse response,
String type, String[] features) {
- super(response, type, false /* expectActivityLaunch */);
+ super(response, type, false /* expectActivityLaunch */,
+ true /* stripAuthTokenFromResult */);
mFeatures = features;
}
@@ -1176,11 +1184,14 @@
IAccountAuthenticator mAuthenticator = null;
+ private final boolean mStripAuthTokenFromResult;
+
public Session(IAccountManagerResponse response, String accountType,
- boolean expectActivityLaunch) {
+ boolean expectActivityLaunch, boolean stripAuthTokenFromResult) {
super();
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
+ mStripAuthTokenFromResult = stripAuthTokenFromResult;
mResponse = response;
mAccountType = accountType;
mExpectActivityLaunch = expectActivityLaunch;
@@ -1319,6 +1330,9 @@
response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
"null bundle returned");
} else {
+ if (mStripAuthTokenFromResult) {
+ result.remove(AccountManager.KEY_AUTHTOKEN);
+ }
response.onResult(result);
}
} catch (RemoteException e) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 56e44c8..13cc3ba 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1392,7 +1392,7 @@
r.startsNotResumed = notResumed;
r.createdConfig = config;
- synchronized (mRelaunchingActivities) {
+ synchronized (mPackages) {
mRelaunchingActivities.add(r);
}
@@ -1523,8 +1523,11 @@
}
public void scheduleConfigurationChanged(Configuration config) {
- synchronized (mRelaunchingActivities) {
- mPendingConfiguration = config;
+ synchronized (mPackages) {
+ if (mPendingConfiguration == null ||
+ mPendingConfiguration.isOtherSeqNewer(config)) {
+ mPendingConfiguration = config;
+ }
}
queueOrSendMessage(H.CONFIGURATION_CHANGED, config);
}
@@ -2060,6 +2063,7 @@
= new HashMap<IBinder, Service>();
AppBindData mBoundApplication;
Configuration mConfiguration;
+ Configuration mResConfiguration;
Application mInitialApplication;
final ArrayList<Application> mAllApplications
= new ArrayList<Application>();
@@ -2073,14 +2077,6 @@
boolean mSystemThread = false;
boolean mJitEnabled = false;
- /**
- * Activities that are enqueued to be relaunched. This list is accessed
- * by multiple threads, so you must synchronize on it when accessing it.
- */
- final ArrayList<ActivityRecord> mRelaunchingActivities
- = new ArrayList<ActivityRecord>();
- Configuration mPendingConfiguration = null;
-
// These can be accessed by multiple threads; mPackages is the lock.
// XXX For now we keep around information about all packages we have
// seen, not removing entries from this map.
@@ -2092,6 +2088,9 @@
DisplayMetrics mDisplayMetrics = null;
HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
= new HashMap<ResourcesKey, WeakReference<Resources> >();
+ final ArrayList<ActivityRecord> mRelaunchingActivities
+ = new ArrayList<ActivityRecord>();
+ Configuration mPendingConfiguration = null;
// The lock of mProviderMap protects the following variables.
final HashMap<String, ProviderRecord> mProviderMap
@@ -3555,7 +3554,7 @@
// First: make sure we have the most recent configuration and most
// recent version of the activity, or skip it if some previous call
// had taken a more recent version.
- synchronized (mRelaunchingActivities) {
+ synchronized (mPackages) {
int N = mRelaunchingActivities.size();
IBinder token = tmp.token;
tmp = null;
@@ -3585,8 +3584,12 @@
// assume that is really what we want regardless of what we
// may have pending.
if (mConfiguration == null
- || mConfiguration.diff(tmp.createdConfig) != 0) {
- changedConfig = tmp.createdConfig;
+ || (tmp.createdConfig.isOtherSeqNewer(mConfiguration)
+ && mConfiguration.diff(tmp.createdConfig) != 0)) {
+ if (changedConfig == null
+ || tmp.createdConfig.isOtherSeqNewer(changedConfig)) {
+ changedConfig = tmp.createdConfig;
+ }
}
}
@@ -3761,62 +3764,81 @@
}
}
- final void handleConfigurationChanged(Configuration config) {
+ final void applyConfigurationToResourcesLocked(Configuration config) {
+ if (mResConfiguration == null) {
+ mResConfiguration = new Configuration();
+ }
+ if (!mResConfiguration.isOtherSeqNewer(config)) {
+ return;
+ }
+ mResConfiguration.updateFrom(config);
+ DisplayMetrics dm = getDisplayMetricsLocked(true);
- synchronized (mRelaunchingActivities) {
- if (mPendingConfiguration != null) {
- config = mPendingConfiguration;
- mPendingConfiguration = null;
- }
+ // set it for java, this also affects newly created Resources
+ if (config.locale != null) {
+ Locale.setDefault(config.locale);
}
- ArrayList<ComponentCallbacks> callbacks
- = new ArrayList<ComponentCallbacks>();
+ Resources.updateSystemConfiguration(config, dm);
- if (DEBUG_CONFIGURATION) Log.v(TAG, "Handle configuration changed: "
- + config);
+ ContextImpl.ApplicationPackageManager.configurationChanged();
+ //Log.i(TAG, "Configuration changed in " + currentPackageName());
- synchronized(mPackages) {
+ Iterator<WeakReference<Resources>> it =
+ mActiveResources.values().iterator();
+ //Iterator<Map.Entry<String, WeakReference<Resources>>> it =
+ // mActiveResources.entrySet().iterator();
+ while (it.hasNext()) {
+ WeakReference<Resources> v = it.next();
+ Resources r = v.get();
+ if (r != null) {
+ r.updateConfiguration(config, dm);
+ //Log.i(TAG, "Updated app resources " + v.getKey()
+ // + " " + r + ": " + r.getConfiguration());
+ } else {
+ //Log.i(TAG, "Removing old resources " + v.getKey());
+ it.remove();
+ }
+ }
+ }
+
+ final void handleConfigurationChanged(Configuration config) {
+
+ ArrayList<ComponentCallbacks> callbacks = null;
+
+ synchronized (mPackages) {
+ if (mPendingConfiguration != null) {
+ if (!mPendingConfiguration.isOtherSeqNewer(config)) {
+ config = mPendingConfiguration;
+ }
+ mPendingConfiguration = null;
+ }
+
+ if (config == null) {
+ return;
+ }
+
+ if (DEBUG_CONFIGURATION) Log.v(TAG, "Handle configuration changed: "
+ + config);
+
+ applyConfigurationToResourcesLocked(config);
+
if (mConfiguration == null) {
mConfiguration = new Configuration();
}
+ if (!mConfiguration.isOtherSeqNewer(config)) {
+ return;
+ }
mConfiguration.updateFrom(config);
- DisplayMetrics dm = getDisplayMetricsLocked(true);
-
- // set it for java, this also affects newly created Resources
- if (config.locale != null) {
- Locale.setDefault(config.locale);
- }
-
- Resources.updateSystemConfiguration(config, dm);
-
- ContextImpl.ApplicationPackageManager.configurationChanged();
- //Log.i(TAG, "Configuration changed in " + currentPackageName());
- {
- Iterator<WeakReference<Resources>> it =
- mActiveResources.values().iterator();
- //Iterator<Map.Entry<String, WeakReference<Resources>>> it =
- // mActiveResources.entrySet().iterator();
- while (it.hasNext()) {
- WeakReference<Resources> v = it.next();
- Resources r = v.get();
- if (r != null) {
- r.updateConfiguration(config, dm);
- //Log.i(TAG, "Updated app resources " + v.getKey()
- // + " " + r + ": " + r.getConfiguration());
- } else {
- //Log.i(TAG, "Removing old resources " + v.getKey());
- it.remove();
- }
- }
- }
callbacks = collectComponentCallbacksLocked(false, config);
}
- final int N = callbacks.size();
- for (int i=0; i<N; i++) {
- performConfigurationChanged(callbacks.get(i), config);
+ if (callbacks != null) {
+ final int N = callbacks.size();
+ for (int i=0; i<N; i++) {
+ performConfigurationChanged(callbacks.get(i), config);
+ }
}
}
@@ -3856,7 +3878,7 @@
ArrayList<ComponentCallbacks> callbacks
= new ArrayList<ComponentCallbacks>();
- synchronized(mPackages) {
+ synchronized (mPackages) {
callbacks = collectComponentCallbacksLocked(true, null);
}
@@ -4348,6 +4370,25 @@
"Unable to instantiate Application():" + e.toString(), e);
}
}
+
+ ViewRoot.addConfigCallback(new ComponentCallbacks() {
+ public void onConfigurationChanged(Configuration newConfig) {
+ synchronized (mPackages) {
+ if (mPendingConfiguration == null ||
+ mPendingConfiguration.isOtherSeqNewer(newConfig)) {
+ mPendingConfiguration = newConfig;
+
+ // We need to apply this change to the resources
+ // immediately, because upon returning the view
+ // hierarchy will be informed about it.
+ applyConfigurationToResourcesLocked(newConfig);
+ }
+ }
+ queueOrSendMessage(H.CONFIGURATION_CHANGED, newConfig);
+ }
+ public void onLowMemory() {
+ }
+ });
}
private final void detach()
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 52cdc74..ce5f1bf 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1690,6 +1690,25 @@
}
/**
+ * Gets the name of the web search activity.
+ *
+ * @return The name of the default activity for web searches. This activity
+ * can be used to get web search suggestions. Returns {@code null} if
+ * there is no default web search activity.
+ *
+ * @hide
+ */
+ public ComponentName getWebSearchActivity() {
+ ComponentName globalSearch = getGlobalSearchActivity();
+ if (globalSearch == null) {
+ return null;
+ }
+ Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
+ intent.setPackage(globalSearch.getPackageName());
+ return intent.resolveActivity(mContext.getPackageManager());
+ }
+
+ /**
* Similar to {@link #startSearch} but actually fires off the search query after invoking
* the search dialog. Made available for testing purposes.
*
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 8ec5bd4..6767332 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -56,6 +56,8 @@
* <li><a href="#ServiceLifecycle">Service Lifecycle</a>
* <li><a href="#Permissions">Permissions</a>
* <li><a href="#ProcessLifecycle">Process Lifecycle</a>
+ * <li><a href="#LocalServiceSample">Local Service Sample</a>
+ * <li><a href="#RemoteMessengerServiceSample">Remote Messenger Service Sample</a>
* </ol>
*
* <a name="ServiceLifecycle"></a>
@@ -166,6 +168,64 @@
* (such as an {@link android.app.Activity}) can, of course, increase the
* importance of the overall
* process beyond just the importance of the service itself.
+ *
+ * <a name="LocalServiceSample"></a>
+ * <h3>Local Service Sample</h3>
+ *
+ * <p>One of the most common uses of a Service is as a secondary component
+ * running alongside other parts of an application, in the same process as
+ * the rest of the components. All components of an .apk run in the same
+ * process unless explicitly stated otherwise, so this is a typical situation.
+ *
+ * <p>When used in this way, by assuming the
+ * components are in the same process, you can greatly simplify the interaction
+ * between them: clients of the service can simply cast the IBinder they
+ * receive from it to a concrete class published by the service.
+ *
+ * <p>An example of this use of a Service is shown here. First is the Service
+ * itself, publishing a custom class when bound:
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LocalService.java
+ * service}
+ *
+ * <p>With that done, one can now write client code that directly accesses the
+ * running service, such as:
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.java
+ * bind}
+ *
+ * <a name="RemoteMessengerServiceSample"></a>
+ * <h3>Remote Messenger Service Sample</h3>
+ *
+ * <p>If you need to be able to write a Service that can perform complicated
+ * communication with clients in remote processes (beyond simply the use of
+ * {@link Context#startService(Intent) Context.startService} to send
+ * commands to it), then you can use the {@link android.os.Messenger} class
+ * instead of writing full AIDL files.
+ *
+ * <p>An example of a Service that uses Messenger as its client interface
+ * is shown here. First is the Service itself, publishing a Messenger to
+ * an internal Handler when bound:
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.java
+ * service}
+ *
+ * <p>If we want to make this service run in a remote process (instead of the
+ * standard one for its .apk), we can use <code>android:process</code> in its
+ * manifest tag to specify one:
+ *
+ * {@sample development/samples/ApiDemos/AndroidManifest.xml remote_service_declaration}
+ *
+ * <p>Note that the name "remote" chosen here is arbitrary, and you can use
+ * other names if you want additional processes. The ':' prefix appends the
+ * name to your package's standard process name.
+ *
+ * <p>With that done, clients can now bind to the service and send messages
+ * to it. Note that this allows clients to register with it to receive
+ * messages back as well:
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.java
+ * bind}
*/
public abstract class Service extends ContextWrapper implements ComponentCallbacks {
private static final String TAG = "Service";
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index b792965..251813e 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -112,11 +112,9 @@
/** Default priority when not set or when the device is unpaired */
public static final int PRIORITY_UNDEFINED = -1;
- /** The voice dialer 'works' but the user experience is poor. The voice
- * recognizer has trouble dealing with the 8kHz SCO signal, and it still
- * requires visual confirmation. Disable for cupcake.
- */
- public static final boolean DISABLE_BT_VOICE_DIALING = true;
+ /** Set this to true to prevent the bluetooth headset from
+ * activating the VoiceDialer. */
+ public static final boolean DISABLE_BT_VOICE_DIALING = false;
/**
* An interface for notifying BluetoothHeadset IPC clients when they have
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d31b25b..1b0437c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1815,11 +1815,18 @@
/**
* Broadcast Action: A sticky broadcast indicating the phone was docked
- * or undocked. Includes the extra
- * field {@link #EXTRA_DOCK_STATE}, containing the current dock state. It also
- * includes the boolean extra field {@link #EXTRA_CAR_MODE_ENABLED}, indicating
- * the state of the car mode.
- * This is intended for monitoring the current dock state.
+ * or undocked.
+ *
+ * <p>The intent will have the following extra values:
+ * <ul>
+ * <li><em>{@link #EXTRA_DOCK_STATE}</em> - the current dock
+ * state, which depends on the state of the car mode.</li>
+ * <li><em>{@link #EXTRA_PHYSICAL_DOCK_STATE}</em> - the physical dock
+ * state.</li>
+ * <li><em>{@link #EXTRA_CAR_MODE_ENABLED}</em> - a boolean indicating the
+ * state of the car mode.</li>
+ * </ul>
+ * <p>This is intended for monitoring the current dock state.
* To launch an activity from a dock state change, use {@link #CATEGORY_CAR_DOCK}
* or {@link #CATEGORY_DESK_DOCK} instead.
*/
@@ -2154,6 +2161,16 @@
public static final int EXTRA_DOCK_STATE_CAR = 2;
/**
+ * Used as an int extra field in {@link android.content.Intent#ACTION_DOCK_EVENT}
+ * intents to request the physical dock state. Possible values are
+ * {@link android.content.Intent#EXTRA_DOCK_STATE_UNDOCKED},
+ * {@link android.content.Intent#EXTRA_DOCK_STATE_DESK}, or
+ * {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}.
+ */
+ public static final String EXTRA_PHYSICAL_DOCK_STATE =
+ "android.intent.extra.PHYSICAL_DOCK_STATE";
+
+ /**
* Used as an boolean extra field in {@link android.content.Intent#ACTION_DOCK_EVENT}
* intents to indicate that the car mode is enabled or not.
*/
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 4ddb819..317e5a9 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -115,6 +115,11 @@
private static final long DEFAULT_MAX_SYNC_RETRY_TIME_IN_SECONDS = 60 * 60; // one hour
/**
+ * How long to wait before retrying a sync that failed due to one already being in progress.
+ */
+ private static final int DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS = 10;
+
+ /**
* An error notification is sent if sync of any of the providers has been failing for this long.
*/
private static final long ERROR_NOTIFICATION_DELAY_MS = 1000 * 60 * 10; // 10 minutes
@@ -807,6 +812,14 @@
+ "it achieved some success");
}
scheduleSyncOperation(operation);
+ } else if (syncResult.syncAlreadyInProgress) {
+ if (isLoggable) {
+ Log.d(TAG, "retrying sync operation that failed because there was already a "
+ + "sync in progress: " + operation);
+ }
+ scheduleSyncOperation(new SyncOperation(operation.account, operation.syncSource,
+ operation.authority, operation.extras,
+ DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS));
} else if (syncResult.hasSoftError()) {
if (isLoggable) {
Log.d(TAG, "retrying sync operation because it encountered a soft error: "
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ff2ed3d..8576de2 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1153,7 +1153,9 @@
*
* @return Returns a ResolveInfo containing the final activity intent that
* was determined to be the best action. Returns null if no
- * matching activity was found.
+ * matching activity was found. If multiple matching activities are
+ * found and there is no default set, returns a ResolveInfo
+ * containing something else, such as the activity resolver.
*
* @see #MATCH_DEFAULT_ONLY
* @see #GET_INTENT_FILTERS
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index aa5f128..6490b65 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -193,6 +193,11 @@
public int uiMode;
/**
+ * @hide Internal book-keeping.
+ */
+ public int seq;
+
+ /**
* Construct an invalid Configuration. You must call {@link #setToDefaults}
* for this object to be valid. {@more}
*/
@@ -220,6 +225,7 @@
orientation = o.orientation;
screenLayout = o.screenLayout;
uiMode = o.uiMode;
+ seq = o.seq;
}
public String toString() {
@@ -250,6 +256,10 @@
sb.append(screenLayout);
sb.append(" uiMode=");
sb.append(uiMode);
+ if (seq != 0) {
+ sb.append(" seq=");
+ sb.append(seq);
+ }
sb.append('}');
return sb.toString();
}
@@ -260,7 +270,7 @@
public void setToDefaults() {
fontScale = 1;
mcc = mnc = 0;
- locale = Locale.getDefault();
+ locale = null;
userSetLocale = false;
touchscreen = TOUCHSCREEN_UNDEFINED;
keyboard = KEYBOARD_UNDEFINED;
@@ -271,6 +281,7 @@
orientation = ORIENTATION_UNDEFINED;
screenLayout = SCREENLAYOUT_SIZE_UNDEFINED;
uiMode = UI_MODE_TYPE_NORMAL;
+ seq = 0;
}
/** {@hide} */
@@ -357,6 +368,10 @@
uiMode = delta.uiMode;
}
+ if (delta.seq != 0) {
+ seq = delta.seq;
+ }
+
return changed;
}
@@ -456,6 +471,35 @@
}
/**
+ * @hide Return true if the sequence of 'other' is better than this. Assumes
+ * that 'this' is your current sequence and 'other' is a new one you have
+ * received some how and want to compare with what you have.
+ */
+ public boolean isOtherSeqNewer(Configuration other) {
+ if (other == null) {
+ // Sanity check.
+ return false;
+ }
+ if (other.seq == 0) {
+ // If the other sequence is not specified, then we must assume
+ // it is newer since we don't know any better.
+ return true;
+ }
+ if (seq == 0) {
+ // If this sequence is not specified, then we also consider the
+ // other is better. Yes we have a preference for other. Sue us.
+ return true;
+ }
+ int diff = other.seq - seq;
+ if (diff > 0x10000) {
+ // If there has been a sufficiently large jump, assume the
+ // sequence has wrapped around.
+ return false;
+ }
+ return diff > 0;
+ }
+
+ /**
* Parcelable methods
*/
public int describeContents() {
@@ -488,6 +532,7 @@
dest.writeInt(orientation);
dest.writeInt(screenLayout);
dest.writeInt(uiMode);
+ dest.writeInt(seq);
}
public static final Parcelable.Creator<Configuration> CREATOR
@@ -522,6 +567,7 @@
orientation = source.readInt();
screenLayout = source.readInt();
uiMode = source.readInt();
+ seq = source.readInt();
}
public int compareTo(Configuration that) {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ae8e297..a5e39d4 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -39,6 +39,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
+import java.util.Locale;
/**
* Class for accessing an application's resources. This sits on top of the
@@ -1259,6 +1260,9 @@
if (config != null) {
configChanges = mConfiguration.updateFrom(config);
}
+ if (mConfiguration.locale == null) {
+ mConfiguration.locale = Locale.getDefault();
+ }
if (metrics != null) {
mMetrics.setTo(metrics);
mMetrics.updateMetrics(mCompatibilityInfo,
diff --git a/core/java/android/database/sqlite/SQLiteClosable.java b/core/java/android/database/sqlite/SQLiteClosable.java
index 7776520..e589f34 100644
--- a/core/java/android/database/sqlite/SQLiteClosable.java
+++ b/core/java/android/database/sqlite/SQLiteClosable.java
@@ -16,6 +16,8 @@
package android.database.sqlite;
+import android.database.CursorWindow;
+
/**
* An object create from a SQLiteDatabase that can be closed.
*/
@@ -29,9 +31,9 @@
synchronized(mLock) {
if (mReferenceCount <= 0) {
throw new IllegalStateException(
- "attempt to acquire a reference on an already-closed SQLiteClosable obj.");
+ "attempt to acquire a reference on an already-closed " + getObjInfo());
}
- mReferenceCount++;
+ mReferenceCount++;
}
}
@@ -52,4 +54,24 @@
}
}
}
+
+ private String getObjInfo() {
+ StringBuilder buff = new StringBuilder();
+ buff.append(this.getClass().getName());
+ buff.append(" Obj");
+ buff.append(" (");
+ if (this instanceof SQLiteDatabase) {
+ buff.append("database = ");
+ buff.append(((SQLiteDatabase)this).getPath());
+ } else if (this instanceof SQLiteProgram || this instanceof SQLiteStatement ||
+ this instanceof SQLiteQuery) {
+ buff.append("mSql = ");
+ buff.append(((SQLiteProgram)this).mSql);
+ } else if (this instanceof CursorWindow) {
+ buff.append("mStartPos = ");
+ buff.append(((CursorWindow)this).getStartPosition());
+ }
+ buff.append(") ");
+ return buff.toString();
+ }
}
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index 79527b4..eb85822 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -44,6 +44,9 @@
*/
/* package */ int nStatement = 0;
+ /** when in cache and is in use, this member is set */
+ private boolean mInUse = false;
+
/* package */ SQLiteCompiledSql(SQLiteDatabase db, String sql) {
mDatabase = db;
this.nHandle = db.mNativeHandle;
@@ -92,6 +95,18 @@
}
}
+ /* package */ synchronized boolean isInUse() {
+ return mInUse;
+ }
+
+ /* package */ synchronized void acquire() {
+ mInUse = true;
+ }
+
+ /* package */ synchronized void release() {
+ mInUse = false;
+ }
+
/**
* Make sure that the native resource is cleaned up.
*/
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 2d0aa39..2bb2f5d 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -58,32 +58,51 @@
// add it to the cache of compiled-sqls
db.addToCompiledQueries(sql, mCompiledSql);
+ mCompiledSql.acquire();
+ } else {
+ // it is already in compiled-sql cache.
+ if (mCompiledSql.isInUse()) {
+ // but the CompiledSql in cache is in use by some other SQLiteProgram object.
+ // we can't have two different SQLiteProgam objects can't share the same
+ // CompiledSql object. create a new one.
+ // finalize it when I am done with it in "this" object.
+ mCompiledSql = new SQLiteCompiledSql(db, sql);
+ } else {
+ // the CompiledSql in cache is NOT in use by any other SQLiteProgram object.
+ // it is safe to give it to this SQLIteProgram Object.
+ mCompiledSql.acquire();
+ }
}
nStatement = mCompiledSql.nStatement;
}
@Override
protected void onAllReferencesReleased() {
- releaseCompiledSqlIfInCache();
+ releaseCompiledSqlIfNotInCache();
mDatabase.releaseReference();
mDatabase.removeSQLiteClosable(this);
}
@Override
protected void onAllReferencesReleasedFromContainer() {
- releaseCompiledSqlIfInCache();
+ releaseCompiledSqlIfNotInCache();
mDatabase.releaseReference();
}
- private void releaseCompiledSqlIfInCache() {
+ private void releaseCompiledSqlIfNotInCache() {
if (mCompiledSql == null) {
return;
}
synchronized(mDatabase.mCompiledQueries) {
if (!mDatabase.mCompiledQueries.containsValue(mCompiledSql)) {
+ // it is NOT in compiled-sql cache. i.e., responsibility of
+ // release this statement is on me.
mCompiledSql.releaseSqlStatement();
mCompiledSql = null; // so that GC doesn't call finalize() on it
nStatement = 0;
+ } else {
+ // it is in compiled-sql cache. reset its CompiledSql#mInUse flag
+ mCompiledSql.release();
}
}
}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index c0bff66..6dba94d 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -26,7 +26,7 @@
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
-import android.graphics.PixelFormat;
+import android.graphics.ImageFormat;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -192,7 +192,7 @@
* The callback that delivers the preview frames.
*
* @param data The contents of the preview frame in the format defined
- * by {@link android.graphics.PixelFormat}, which can be queried
+ * by {@link android.graphics.ImageFormat}, which can be queried
* with {@link android.hardware.Camera.Parameters#getPreviewFormat()}.
* If {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}
* is never called, the default will be the YCbCr_420_SP
@@ -276,7 +276,7 @@
* Adds a pre-allocated buffer to the callback buffer queue.
* Preview width and height can be determined from getPreviewSize, and bitsPerPixel can be
* found from from {@link android.hardware.Camera.Parameters#getPreviewFormat()} and
- * {@link android.graphics.PixelFormat#getPixelFormatInfo(int, PixelFormat)}
+ * {@link android.graphics.ImageFormat#getBitsPerPixel(int)}
*
* Alternatively, a buffer from a previous callback may be passed in or used
* to determine the size of new preview frame buffers.
@@ -1086,15 +1086,15 @@
/**
* Sets the image format for preview pictures.
* <p>If this is never called, the default format will be
- * {@link android.graphics.PixelFormat#YCbCr_420_SP}, which
+ * {@link android.graphics.ImageFormat#NV21}, which
* uses the NV21 encoding format.</p>
*
* @param pixel_format the desired preview picture format, defined
- * by one of the {@link android.graphics.PixelFormat} constants.
- * (E.g., <var>PixelFormat.YCbCr_420_SP</var> (default),
- * <var>PixelFormat.RGB_565</var>, or
- * <var>PixelFormat.JPEG</var>)
- * @see android.graphics.PixelFormat
+ * by one of the {@link android.graphics.ImageFormat} constants.
+ * (E.g., <var>ImageFormat.NV21</var> (default),
+ * <var>ImageFormat.RGB_565</var>, or
+ * <var>ImageFormat.JPEG</var>)
+ * @see android.graphics.ImageFormat
*/
public void setPreviewFormat(int pixel_format) {
String s = cameraFormatForPixelFormat(pixel_format);
@@ -1110,7 +1110,7 @@
* Returns the image format for preview pictures got from
* {@link PreviewCallback}.
*
- * @return the {@link android.graphics.PixelFormat} int representing
+ * @return the {@link android.graphics.ImageFormat} int representing
* the preview picture format.
*/
public int getPreviewFormat() {
@@ -1128,7 +1128,7 @@
ArrayList<Integer> formats = new ArrayList<Integer>();
for (String s : split(str)) {
int f = pixelFormatForCameraFormat(s);
- if (f == PixelFormat.UNKNOWN) continue;
+ if (f == ImageFormat.UNKNOWN) continue;
formats.add(f);
}
return formats;
@@ -1171,10 +1171,10 @@
* Sets the image format for pictures.
*
* @param pixel_format the desired picture format
- * (<var>PixelFormat.YCbCr_420_SP (NV21)</var>,
- * <var>PixelFormat.RGB_565</var>, or
- * <var>PixelFormat.JPEG</var>)
- * @see android.graphics.PixelFormat
+ * (<var>ImageFormat.NV21</var>,
+ * <var>ImageFormat.RGB_565</var>, or
+ * <var>ImageFormat.JPEG</var>)
+ * @see android.graphics.ImageFormat
*/
public void setPictureFormat(int pixel_format) {
String s = cameraFormatForPixelFormat(pixel_format);
@@ -1189,7 +1189,7 @@
/**
* Returns the image format for pictures.
*
- * @return the PixelFormat int representing the picture format
+ * @return the ImageFormat int representing the picture format
*/
public int getPictureFormat() {
return pixelFormatForCameraFormat(get(KEY_PICTURE_FORMAT));
@@ -1198,7 +1198,7 @@
/**
* Gets the supported picture formats.
*
- * @return a List of Integer objects (values are PixelFormat.XXX). This
+ * @return a List of Integer objects (values are ImageFormat.XXX). This
* method will always return a list with at least one element.
*/
public List<Integer> getSupportedPictureFormats() {
@@ -1206,7 +1206,7 @@
ArrayList<Integer> formats = new ArrayList<Integer>();
for (String s : split(str)) {
int f = pixelFormatForCameraFormat(s);
- if (f == PixelFormat.UNKNOWN) continue;
+ if (f == ImageFormat.UNKNOWN) continue;
formats.add(f);
}
return formats;
@@ -1214,35 +1214,35 @@
private String cameraFormatForPixelFormat(int pixel_format) {
switch(pixel_format) {
- case PixelFormat.YCbCr_422_SP: return PIXEL_FORMAT_YUV422SP;
- case PixelFormat.YCbCr_420_SP: return PIXEL_FORMAT_YUV420SP;
- case PixelFormat.YCbCr_422_I: return PIXEL_FORMAT_YUV422I;
- case PixelFormat.RGB_565: return PIXEL_FORMAT_RGB565;
- case PixelFormat.JPEG: return PIXEL_FORMAT_JPEG;
- default: return null;
+ case ImageFormat.NV16: return PIXEL_FORMAT_YUV422SP;
+ case ImageFormat.NV21: return PIXEL_FORMAT_YUV420SP;
+ case ImageFormat.YUY2: return PIXEL_FORMAT_YUV422I;
+ case ImageFormat.RGB_565: return PIXEL_FORMAT_RGB565;
+ case ImageFormat.JPEG: return PIXEL_FORMAT_JPEG;
+ default: return null;
}
}
private int pixelFormatForCameraFormat(String format) {
if (format == null)
- return PixelFormat.UNKNOWN;
+ return ImageFormat.UNKNOWN;
if (format.equals(PIXEL_FORMAT_YUV422SP))
- return PixelFormat.YCbCr_422_SP;
+ return ImageFormat.NV16;
if (format.equals(PIXEL_FORMAT_YUV420SP))
- return PixelFormat.YCbCr_420_SP;
+ return ImageFormat.NV21;
if (format.equals(PIXEL_FORMAT_YUV422I))
- return PixelFormat.YCbCr_422_I;
+ return ImageFormat.YUY2;
if (format.equals(PIXEL_FORMAT_RGB565))
- return PixelFormat.RGB_565;
+ return ImageFormat.RGB_565;
if (format.equals(PIXEL_FORMAT_JPEG))
- return PixelFormat.JPEG;
+ return ImageFormat.JPEG;
- return PixelFormat.UNKNOWN;
+ return ImageFormat.UNKNOWN;
}
/**
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
index 65301e4..911439a 100644
--- a/core/java/android/os/HandlerThread.java
+++ b/core/java/android/os/HandlerThread.java
@@ -53,9 +53,9 @@
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
- Process.setThreadPriority(mPriority);
notifyAll();
}
+ Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index f48f45f..92041d8 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -148,4 +148,18 @@
*/
void detachPppd(String tty);
+ /**
+ * Turn on USB RNDIS support - this will turn off thinks like adb/mass-storage
+ */
+ void startUsbRNDIS();
+
+ /**
+ * Turn off USB RNDIS support
+ */
+ void stopUsbRNDIS();
+
+ /**
+ * Check the status of USB RNDIS support
+ */
+ boolean isUsbRNDISStarted();
}
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 4130109..476da1d 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -40,20 +40,36 @@
*/
public int what;
- // Use these fields instead of using the class's Bundle if you can.
- /** arg1 and arg2 are lower-cost alternatives to using {@link #setData(Bundle) setData()}
- if you only need to store a few integer values. */
+ /**
+ * arg1 and arg2 are lower-cost alternatives to using
+ * {@link #setData(Bundle) setData()} if you only need to store a
+ * few integer values.
+ */
public int arg1;
- /** arg1 and arg2 are lower-cost alternatives to using {@link #setData(Bundle) setData()}
- if you only need to store a few integer values.*/
+ /**
+ * arg1 and arg2 are lower-cost alternatives to using
+ * {@link #setData(Bundle) setData()} if you only need to store a
+ * few integer values.
+ */
public int arg2;
- /** An arbitrary object to send to the recipient. This must be null when
- * sending messages across processes. */
+ /**
+ * An arbitrary object to send to the recipient. When using
+ * {@link Messenger} to send the message across processes this can only
+ * be non-null if it contains a Parcelable of a framework class (not one
+ * implemented by the application). For other data transfer use
+ * {@link #setData}.
+ *
+ * <p>Note that Parcelable objects here are not supported prior to
+ * the {@link android.os.Build.VERSION_CODES#FROYO} release.
+ */
public Object obj;
- /** Optional Messenger where replies to this message can be sent.
+ /**
+ * Optional Messenger where replies to this message can be sent. The
+ * semantics of exactly how this is used are up to the sender and
+ * receiver.
*/
public Messenger replyTo;
@@ -278,14 +294,22 @@
* the <em>target</em> {@link Handler} that is receiving this Message to
* dispatch it. If
* not set, the message will be dispatched to the receiving Handler's
- * {@link Handler#handleMessage(Message Handler.handleMessage())}. */
+ * {@link Handler#handleMessage(Message Handler.handleMessage())}.
+ */
public Runnable getCallback() {
return callback;
}
/**
* Obtains a Bundle of arbitrary data associated with this
- * event, lazily creating it if necessary. Set this value by calling {@link #setData(Bundle)}.
+ * event, lazily creating it if necessary. Set this value by calling
+ * {@link #setData(Bundle)}. Note that when transferring data across
+ * processes via {@link Messenger}, you will need to set your ClassLoader
+ * on the Bundle via {@link Bundle#setClassLoader(ClassLoader)
+ * Bundle.setClassLoader()} so that it can instantiate your objects when
+ * you retrieve them.
+ * @see #peekData()
+ * @see #setData(Bundle)
*/
public Bundle getData() {
if (data == null) {
@@ -297,14 +321,21 @@
/**
* Like getData(), but does not lazily create the Bundle. A null
- * is returned if the Bundle does not already exist.
+ * is returned if the Bundle does not already exist. See
+ * {@link #getData} for further information on this.
+ * @see #getData()
+ * @see #setData(Bundle)
*/
public Bundle peekData() {
return data;
}
- /** Sets a Bundle of arbitrary data values. Use arg1 and arg1 members
- * as a lower cost way to send a few simple integer values, if you can. */
+ /**
+ * Sets a Bundle of arbitrary data values. Use arg1 and arg1 members
+ * as a lower cost way to send a few simple integer values, if you can.
+ * @see #getData()
+ * @see #peekData()
+ */
public void setData(Bundle data) {
this.data = data;
}
@@ -381,13 +412,25 @@
}
public void writeToParcel(Parcel dest, int flags) {
- if (obj != null || callback != null) {
+ if (callback != null) {
throw new RuntimeException(
- "Can't marshal objects across processes.");
+ "Can't marshal callbacks across processes.");
}
dest.writeInt(what);
dest.writeInt(arg1);
dest.writeInt(arg2);
+ if (obj != null) {
+ try {
+ Parcelable p = (Parcelable)obj;
+ dest.writeInt(1);
+ dest.writeParcelable(p, flags);
+ } catch (ClassCastException e) {
+ throw new RuntimeException(
+ "Can't marshal non-Parcelable objects across processes.");
+ }
+ } else {
+ dest.writeInt(0);
+ }
dest.writeLong(when);
dest.writeBundle(data);
Messenger.writeMessengerOrNullToParcel(replyTo, dest);
@@ -397,6 +440,9 @@
what = source.readInt();
arg1 = source.readInt();
arg2 = source.readInt();
+ if (source.readInt() != 0) {
+ obj = source.readParcelable(getClass().getClassLoader());
+ }
when = source.readLong();
data = source.readBundle();
replyTo = Messenger.readMessengerOrNullFromParcel(source);
diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl
index 816baf3..79a6cfe 100644
--- a/core/java/android/os/storage/IMountService.aidl
+++ b/core/java/android/os/storage/IMountService.aidl
@@ -63,7 +63,7 @@
* Safely unmount external storage at given mount point.
* Returns an int consistent with MountServiceResultCode
*/
- int unmountVolume(String mountPoint);
+ int unmountVolume(String mountPoint, boolean force);
/**
* Format external storage given a mount point.
@@ -100,7 +100,7 @@
* NOTE: Ensure all references are released prior to deleting.
* Returns an int consistent with MountServiceResultCode
*/
- int destroySecureContainer(String id);
+ int destroySecureContainer(String id, boolean force);
/*
* Mount a secure container with the specified key and owner UID.
@@ -112,7 +112,7 @@
* Unount a secure container.
* Returns an int consistent with MountServiceResultCode
*/
- int unmountSecureContainer(String id);
+ int unmountSecureContainer(String id, boolean force);
/*
* Returns true if the specified container is mounted
diff --git a/core/java/android/os/storage/StorageResultCode.java b/core/java/android/os/storage/StorageResultCode.java
index 249bacf..07d95df 100644
--- a/core/java/android/os/storage/StorageResultCode.java
+++ b/core/java/android/os/storage/StorageResultCode.java
@@ -64,4 +64,10 @@
*/
public static final int OperationFailedStorageMounted = -6;
+ /**
+ * Operation failed: Storage is busy.
+ * @see android.os.storage.StorageManager
+ */
+ public static final int OperationFailedStorageBusy = -7;
+
}
diff --git a/core/java/android/pim/RecurrenceSet.java b/core/java/android/pim/RecurrenceSet.java
index bd7924a..5d09fb5 100644
--- a/core/java/android/pim/RecurrenceSet.java
+++ b/core/java/android/pim/RecurrenceSet.java
@@ -48,7 +48,8 @@
* events table in the CalendarProvider.
* @param values The values retrieved from the Events table.
*/
- public RecurrenceSet(ContentValues values) {
+ public RecurrenceSet(ContentValues values)
+ throws EventRecurrence.InvalidFormatException {
String rruleStr = values.getAsString(Calendar.Events.RRULE);
String rdateStr = values.getAsString(Calendar.Events.RDATE);
String exruleStr = values.getAsString(Calendar.Events.EXRULE);
@@ -65,7 +66,8 @@
* @param cursor The cursor containing the RRULE, RDATE, EXRULE, and EXDATE
* columns.
*/
- public RecurrenceSet(Cursor cursor) {
+ public RecurrenceSet(Cursor cursor)
+ throws EventRecurrence.InvalidFormatException {
int rruleColumn = cursor.getColumnIndex(Calendar.Events.RRULE);
int rdateColumn = cursor.getColumnIndex(Calendar.Events.RDATE);
int exruleColumn = cursor.getColumnIndex(Calendar.Events.EXRULE);
@@ -78,12 +80,14 @@
}
public RecurrenceSet(String rruleStr, String rdateStr,
- String exruleStr, String exdateStr) {
+ String exruleStr, String exdateStr)
+ throws EventRecurrence.InvalidFormatException {
init(rruleStr, rdateStr, exruleStr, exdateStr);
}
private void init(String rruleStr, String rdateStr,
- String exruleStr, String exdateStr) {
+ String exruleStr, String exdateStr)
+ throws EventRecurrence.InvalidFormatException {
if (!TextUtils.isEmpty(rruleStr) || !TextUtils.isEmpty(rdateStr)) {
if (!TextUtils.isEmpty(rruleStr)) {
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index eb48a0c..52de64c 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -28,6 +28,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
@@ -226,7 +227,7 @@
@Override
public void resized(int w, int h, Rect coveredInsets,
- Rect visibleInsets, boolean reportDraw) {
+ Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0);
mCaller.sendMessage(msg);
diff --git a/core/java/android/speech/RecognitionManager.java b/core/java/android/speech/RecognitionManager.java
index 7f55ad6..16b1f89 100644
--- a/core/java/android/speech/RecognitionManager.java
+++ b/core/java/android/speech/RecognitionManager.java
@@ -98,6 +98,9 @@
/** Context with which the manager was created */
private final Context mContext;
+
+ /** Component to direct service intent to */
+ private final ComponentName mServiceComponent;
/** Handler that will execute the main tasks */
private Handler mHandler = new Handler() {
@@ -133,8 +136,9 @@
* The right way to create a {@code RecognitionManager} is by using
* {@link #createRecognitionManager} static factory method
*/
- private RecognitionManager(final Context context) {
+ private RecognitionManager(final Context context, final ComponentName serviceComponent) {
mContext = context;
+ mServiceComponent = serviceComponent;
}
/**
@@ -184,11 +188,31 @@
* @return a new {@code RecognitionManager}
*/
public static RecognitionManager createRecognitionManager(final Context context) {
+ return createRecognitionManager(context, null);
+ }
+
+ /**
+ * Factory method to create a new {@code RecognitionManager}, please note that
+ * {@link #setRecognitionListener(RecognitionListener)} must be called before dispatching any
+ * command to the created {@code RecognitionManager}.
+ *
+ * Use this version of the method to specify a specific service to direct this
+ * {@link RecognitionManager} to. Normally you would not use this; use
+ * {@link #createRecognitionManager(Context)} instead to use the system default
+ * recognition service.
+ *
+ * @param context in which to create {@code RecognitionManager}
+ * @param serviceComponent the {@link ComponentName} of a specific service to direct this
+ * {@code RecognitionManager} to
+ * @return a new {@code RecognitionManager}
+ */
+ public static RecognitionManager createRecognitionManager(final Context context,
+ final ComponentName serviceComponent) {
if (context == null) {
throw new IllegalArgumentException("Context cannot be null)");
}
checkIsCalledFromMainThread();
- return new RecognitionManager(context);
+ return new RecognitionManager(context, serviceComponent);
}
/**
@@ -222,17 +246,22 @@
mConnection = new Connection();
Intent serviceIntent = new Intent(RecognitionService.SERVICE_INTERFACE);
- String serviceComponent = Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.VOICE_RECOGNITION_SERVICE);
- if (TextUtils.isEmpty(serviceComponent)) {
- Log.e(TAG, "no selected voice recognition service");
- mListener.onError(ERROR_CLIENT);
- return;
+ if (mServiceComponent == null) {
+ String serviceComponent = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.VOICE_RECOGNITION_SERVICE);
+
+ if (TextUtils.isEmpty(serviceComponent)) {
+ Log.e(TAG, "no selected voice recognition service");
+ mListener.onError(ERROR_CLIENT);
+ return;
+ }
+
+ serviceIntent.setComponent(ComponentName.unflattenFromString(serviceComponent));
+ } else {
+ serviceIntent.setComponent(mServiceComponent);
}
- serviceIntent.setComponent(ComponentName.unflattenFromString(serviceComponent));
-
if (!mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE)) {
Log.e(TAG, "bind to recognition service failed");
mConnection = null;
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index 5f651e1..7c15cec 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -16,9 +16,17 @@
package android.speech;
+import java.util.ArrayList;
+
import android.app.Activity;
import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
/**
* Constants for supporting speech recognition through starting an {@link Intent}
@@ -208,4 +216,92 @@
* an activity result. In a PendingIntent, the lack of this extra indicates failure.
*/
public static final String EXTRA_RESULTS = "android.speech.extra.RESULTS";
+
+ /**
+ * Returns the broadcast intent to fire with
+ * {@link Context#sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, int, String, Bundle)}
+ * to receive details from the package that implements voice search.
+ * <p>
+ * This is based on the value specified by the voice search {@link Activity} in
+ * {@link #DETAILS_META_DATA}, and if this is not specified, will return null. Also if there
+ * is no chosen default to resolve for {@link #ACTION_WEB_SEARCH}, this will return null.
+ * <p>
+ * If an intent is returned and is fired, a {@link Bundle} of extras will be returned to the
+ * provided result receiver, and should ideally contain values for
+ * {@link #EXTRA_LANGUAGE_PREFERENCE} and {@link #EXTRA_SUPPORTED_LANGUAGES}.
+ * <p>
+ * (Whether these are actually provided is up to the particular implementation. It is
+ * recommended that {@link Activity}s implementing {@link #ACTION_WEB_SEARCH} provide this
+ * information, but it is not required.)
+ *
+ * @param context a context object
+ * @return the broadcast intent to fire or null if not available
+ */
+ public static final Intent getVoiceDetailsIntent(Context context) {
+ Intent voiceSearchIntent = new Intent(ACTION_WEB_SEARCH);
+ ResolveInfo ri = context.getPackageManager().resolveActivity(
+ voiceSearchIntent, PackageManager.GET_META_DATA);
+ if (ri == null || ri.activityInfo == null || ri.activityInfo.metaData == null) return null;
+
+ String className = ri.activityInfo.metaData.getString(DETAILS_META_DATA);
+ if (className == null) return null;
+
+ Intent detailsIntent = new Intent(ACTION_GET_LANGUAGE_DETAILS);
+ detailsIntent.setComponent(new ComponentName(ri.activityInfo.packageName, className));
+ return detailsIntent;
+ }
+
+ /**
+ * Meta-data name under which an {@link Activity} implementing {@link #ACTION_WEB_SEARCH} can
+ * use to expose the class name of a {@link BroadcastReceiver} which can respond to request for
+ * more information, from any of the broadcast intents specified in this class.
+ * <p>
+ * Broadcast intents can be directed to the class name specified in the meta-data by creating
+ * an {@link Intent}, setting the component with
+ * {@link Intent#setComponent(android.content.ComponentName)}, and using
+ * {@link Context#sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle)}
+ * with another {@link BroadcastReceiver} which can receive the results.
+ * <p>
+ * The {@link #getVoiceDetailsIntent(Context)} method is provided as a convenience to create
+ * a broadcast intent based on the value of this meta-data, if available.
+ * <p>
+ * This is optional and not all {@link Activity}s which implement {@link #ACTION_WEB_SEARCH}
+ * are required to implement this. Thus retrieving this meta-data may be null.
+ */
+ public static final String DETAILS_META_DATA = "android.speech.DETAILS";
+
+ /**
+ * A broadcast intent which can be fired to the {@link BroadcastReceiver} component specified
+ * in the meta-data defined in the {@link #DETAILS_META_DATA} meta-data of an
+ * {@link Activity} satisfying {@link #ACTION_WEB_SEARCH}.
+ * <p>
+ * When fired with
+ * {@link Context#sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle)},
+ * a {@link Bundle} of extras will be returned to the provided result receiver, and should
+ * ideally contain values for {@link #EXTRA_LANGUAGE_PREFERENCE} and
+ * {@link #EXTRA_SUPPORTED_LANGUAGES}.
+ * <p>
+ * (Whether these are actually provided is up to the particular implementation. It is
+ * recommended that {@link Activity}s implementing {@link #ACTION_WEB_SEARCH} provide this
+ * information, but it is not required.)
+ */
+ public static final String ACTION_GET_LANGUAGE_DETAILS =
+ "android.speech.action.GET_LANGUAGE_DETAILS";
+
+ /**
+ * The key to the extra in the {@link Bundle} returned by {@link #ACTION_GET_LANGUAGE_DETAILS}
+ * which is a {@link String} that represents the current language preference this user has
+ * specified - a locale string like "en-US".
+ */
+ public static final String EXTRA_LANGUAGE_PREFERENCE =
+ "android.speech.extra.LANGUAGE_PREFERENCE";
+
+ /**
+ * The key to the extra in the {@link Bundle} returned by {@link #ACTION_GET_LANGUAGE_DETAILS}
+ * which is an {@link ArrayList} of {@link String}s that represents the languages supported by
+ * this implementation of voice recognition - a list of strings like "en-US", "cmn-Hans-CN",
+ * etc.
+ */
+ public static final String EXTRA_SUPPORTED_LANGUAGES =
+ "android.speech.extra.SUPPORTED_LANGUAGES";
}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 71302cb..3b09808 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -17,6 +17,7 @@
package android.view;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
@@ -44,7 +45,7 @@
void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor);
void resized(int w, int h, in Rect coveredInsets, in Rect visibleInsets,
- boolean reportDraw);
+ boolean reportDraw, in Configuration newConfig);
void dispatchKey(in KeyEvent event);
void dispatchPointer(in MotionEvent event, long eventTime, boolean callWhenDone);
void dispatchTrackball(in MotionEvent event, long eventTime, boolean callWhenDone);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 0ebe360..9b7b2f4 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -64,8 +64,6 @@
void addAppToken(int addPos, IApplicationToken token,
int groupId, int requestedOrientation, boolean fullscreen);
void setAppGroupId(IBinder token, int groupId);
- Configuration updateOrientationFromAppTokens(in Configuration currentConfig,
- IBinder freezeThisOneIfNeeded);
void setAppOrientation(IApplicationToken token, int requestedOrientation);
int getAppOrientation(IApplicationToken token);
void setFocusedApp(IBinder token, boolean moveFocusNow);
@@ -85,6 +83,13 @@
void moveAppTokensToTop(in List<IBinder> tokens);
void moveAppTokensToBottom(in List<IBinder> tokens);
+ // Re-evaluate the current orientation from the caller's state.
+ // If there is a change, the new Configuration is returned and the
+ // caller must call setNewConfiguration() sometime later.
+ Configuration updateOrientationFromAppTokens(in Configuration currentConfig,
+ IBinder freezeThisOneIfNeeded);
+ void setNewConfiguration(in Configuration config);
+
// these require DISABLE_KEYGUARD permission
void disableKeyguard(IBinder token, String tag);
void reenableKeyguard(IBinder token);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index ca5e1de..d7f2539 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -19,6 +19,7 @@
import com.android.internal.view.BaseIWindow;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.CompatibilityInfo.Translator;
import android.graphics.Canvas;
@@ -504,7 +505,7 @@
}
public void resized(int w, int h, Rect coveredInsets,
- Rect visibleInsets, boolean reportDraw) {
+ Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
SurfaceView surfaceView = mSurfaceView.get();
if (surfaceView != null) {
if (localLOGV) Log.v(
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index bc49439..2eb633f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -20,6 +20,7 @@
import com.android.internal.view.menu.MenuBuilder;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -3933,6 +3934,32 @@
}
/**
+ * Dispatch a notification about a resource configuration change down
+ * the view hierarchy.
+ * ViewGroups should override to route to their children.
+ *
+ * @param newConfig The new resource configuration.
+ *
+ * @see #onConfigurationChanged
+ */
+ public void dispatchConfigurationChanged(Configuration newConfig) {
+ onConfigurationChanged(newConfig);
+ }
+
+ /**
+ * Called when the current configuration of the resources being used
+ * by the application have changed. You can use this to decide when
+ * to reload resources that can changed based on orientation and other
+ * configuration characterstics. You only need to use this if you are
+ * not relying on the normal {@link android.app.Activity} mechanism of
+ * recreating the activity instance upon a configuration change.
+ *
+ * @param newConfig The new resource configuration.
+ */
+ protected void onConfigurationChanged(Configuration newConfig) {
+ }
+
+ /**
* Private function to aggregate all per-view attributes in to the view
* root.
*/
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 2ed623d..0663215 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -19,6 +19,7 @@
import com.android.internal.R;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -722,6 +723,19 @@
/**
* {@inheritDoc}
*/
+ @Override
+ public void dispatchConfigurationChanged(Configuration newConfig) {
+ super.dispatchConfigurationChanged(newConfig);
+ final int count = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = 0; i < count; i++) {
+ children[i].dispatchConfigurationChanged(newConfig);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public void recomputeViewAttributes(View child) {
ViewParent parent = mParent;
if (parent != null) parent.recomputeViewAttributes(this);
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 07b2d1c..264b8c9 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -41,7 +41,9 @@
import android.widget.Scroller;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.ComponentCallbacks;
import android.content.Context;
import android.app.ActivityManagerNative;
import android.Manifest;
@@ -101,6 +103,9 @@
static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
static boolean sFirstDrawComplete = false;
+ static final ArrayList<ComponentCallbacks> sConfigCallbacks
+ = new ArrayList<ComponentCallbacks>();
+
private static int sDrawTime;
long mLastTrackballTime = 0;
@@ -171,6 +176,12 @@
final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
= new ViewTreeObserver.InternalInsetsInfo();
+ class ResizedInfo {
+ Rect coveredInsets;
+ Rect visibleInsets;
+ Configuration newConfig;
+ }
+
boolean mScrollMayChange;
int mSoftInputMode;
View mLastScrolledFocus;
@@ -265,6 +276,12 @@
}
}
+ public static void addConfigCallback(ComponentCallbacks callback) {
+ synchronized (sConfigCallbacks) {
+ sConfigCallbacks.add(callback);
+ }
+ }
+
// FIXME for perf testing only
private boolean mProfile = false;
@@ -1782,23 +1799,33 @@
handleGetNewSurface();
break;
case RESIZED:
- Rect coveredInsets = ((Rect[])msg.obj)[0];
- Rect visibleInsets = ((Rect[])msg.obj)[1];
+ ResizedInfo ri = (ResizedInfo)msg.obj;
if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
- && mPendingContentInsets.equals(coveredInsets)
- && mPendingVisibleInsets.equals(visibleInsets)) {
+ && mPendingContentInsets.equals(ri.coveredInsets)
+ && mPendingVisibleInsets.equals(ri.visibleInsets)) {
break;
}
// fall through...
case RESIZED_REPORT:
if (mAdded) {
+ Configuration config = ((ResizedInfo)msg.obj).newConfig;
+ if (config != null) {
+ synchronized (sConfigCallbacks) {
+ for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
+ sConfigCallbacks.get(i).onConfigurationChanged(config);
+ }
+ }
+ if (mView != null) {
+ mView.dispatchConfigurationChanged(config);
+ }
+ }
mWinFrame.left = 0;
mWinFrame.right = msg.arg1;
mWinFrame.top = 0;
mWinFrame.bottom = msg.arg2;
- mPendingContentInsets.set(((Rect[])msg.obj)[0]);
- mPendingVisibleInsets.set(((Rect[])msg.obj)[1]);
+ mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets);
+ mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets);
if (msg.what == RESIZED_REPORT) {
mReportNextDraw = true;
}
@@ -2587,7 +2614,7 @@
}
public void dispatchResized(int w, int h, Rect coveredInsets,
- Rect visibleInsets, boolean reportDraw) {
+ Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": w=" + w
+ " h=" + h + " coveredInsets=" + coveredInsets.toShortString()
+ " visibleInsets=" + visibleInsets.toShortString()
@@ -2601,7 +2628,11 @@
}
msg.arg1 = w;
msg.arg2 = h;
- msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) };
+ ResizedInfo ri = new ResizedInfo();
+ ri.coveredInsets = new Rect(coveredInsets);
+ ri.visibleInsets = new Rect(visibleInsets);
+ ri.newConfig = newConfig;
+ msg.obj = ri;
sendMessage(msg);
}
@@ -2802,11 +2833,11 @@
}
public void resized(int w, int h, Rect coveredInsets,
- Rect visibleInsets, boolean reportDraw) {
+ Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
final ViewRoot viewRoot = mViewRoot.get();
if (viewRoot != null) {
viewRoot.dispatchResized(w, h, coveredInsets,
- visibleInsets, reportDraw);
+ visibleInsets, reportDraw, newConfig);
}
}
diff --git a/core/java/android/webkit/DateSorter.java b/core/java/android/webkit/DateSorter.java
index 16feaa9..bc135046 100644
--- a/core/java/android/webkit/DateSorter.java
+++ b/core/java/android/webkit/DateSorter.java
@@ -26,7 +26,7 @@
* Sorts dates into the following groups:
* Today
* Yesterday
- * five days ago
+ * seven days ago
* one month ago
* older than a month ago
*/
@@ -41,7 +41,7 @@
private long [] mBins = new long[DAY_COUNT-1];
private String [] mLabels = new String[DAY_COUNT];
- private static final int NUM_DAYS_AGO = 5;
+ private static final int NUM_DAYS_AGO = 7;
/**
* @param context Application context
diff --git a/core/java/android/webkit/GeolocationPermissions.java b/core/java/android/webkit/GeolocationPermissions.java
index d12d828..4565b756 100755
--- a/core/java/android/webkit/GeolocationPermissions.java
+++ b/core/java/android/webkit/GeolocationPermissions.java
@@ -23,6 +23,7 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.Vector;
/**
@@ -61,11 +62,8 @@
private Handler mHandler;
private Handler mUIHandler;
- // Members used to transfer the origins and permissions between threads.
- private Set<String> mOrigins;
- private boolean mAllowed;
- private Set<String> mOriginsToClear;
- private Set<String> mOriginsToAllow;
+ // A queue to store messages until the handler is ready.
+ private Vector<Message> mQueuedMessages;
// Message ids
static final int GET_ORIGINS = 0;
@@ -126,7 +124,7 @@
* Creates the message handler. Must be called on the WebKit thread.
* @hide
*/
- public void createHandler() {
+ public synchronized void createHandler() {
if (mHandler == null) {
mHandler = new Handler() {
@Override
@@ -134,21 +132,21 @@
// Runs on the WebKit thread.
switch (msg.what) {
case GET_ORIGINS: {
- getOriginsImpl();
+ Set origins = nativeGetOrigins();
ValueCallback callback = (ValueCallback) msg.obj;
Map values = new HashMap<String, Object>();
values.put(CALLBACK, callback);
- values.put(ORIGINS, mOrigins);
+ values.put(ORIGINS, origins);
postUIMessage(Message.obtain(null, RETURN_ORIGINS, values));
} break;
case GET_ALLOWED: {
Map values = (Map) msg.obj;
String origin = (String) values.get(ORIGIN);
ValueCallback callback = (ValueCallback) values.get(CALLBACK);
- getAllowedImpl(origin);
+ boolean allowed = nativeGetAllowed(origin);
Map retValues = new HashMap<String, Object>();
retValues.put(CALLBACK, callback);
- retValues.put(ALLOWED, new Boolean(mAllowed));
+ retValues.put(ALLOWED, new Boolean(allowed));
postUIMessage(Message.obtain(null, RETURN_ALLOWED, retValues));
} break;
case CLEAR:
@@ -164,15 +162,12 @@
}
};
- if (mOriginsToClear != null) {
- for (String origin : mOriginsToClear) {
- nativeClear(origin);
+ // Handle the queued messages
+ if (mQueuedMessages != null) {
+ while (!mQueuedMessages.isEmpty()) {
+ mHandler.sendMessage(mQueuedMessages.remove(0));
}
- }
- if (mOriginsToAllow != null) {
- for (String origin : mOriginsToAllow) {
- nativeAllow(origin);
- }
+ mQueuedMessages = null;
}
}
}
@@ -180,9 +175,15 @@
/**
* Utility function to send a message to our handler.
*/
- private void postMessage(Message msg) {
- assert(mHandler != null);
- mHandler.sendMessage(msg);
+ private synchronized void postMessage(Message msg) {
+ if (mHandler == null) {
+ if (mQueuedMessages == null) {
+ mQueuedMessages = new Vector<Message>();
+ }
+ mQueuedMessages.add(msg);
+ } else {
+ mHandler.sendMessage(msg);
+ }
}
/**
@@ -207,8 +208,8 @@
public void getOrigins(ValueCallback<Set<String> > callback) {
if (callback != null) {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
- getOriginsImpl();
- callback.onReceiveValue(mOrigins);
+ Set origins = nativeGetOrigins();
+ callback.onReceiveValue(origins);
} else {
postMessage(Message.obtain(null, GET_ORIGINS, callback));
}
@@ -216,14 +217,6 @@
}
/**
- * Helper method to get the set of origins.
- */
- private void getOriginsImpl() {
- // Called on the WebKit thread.
- mOrigins = nativeGetOrigins();
- }
-
- /**
* Gets the permission state for the specified origin.
*
* Callback is a ValueCallback object whose onReceiveValue method will be
@@ -238,8 +231,8 @@
return;
}
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
- getAllowedImpl(origin);
- callback.onReceiveValue(new Boolean(mAllowed));
+ boolean allowed = nativeGetAllowed(origin);
+ callback.onReceiveValue(new Boolean(allowed));
} else {
Map values = new HashMap<String, Object>();
values.put(ORIGIN, origin);
@@ -249,31 +242,13 @@
}
/**
- * Helper method to get the permission state for the specified origin.
- */
- private void getAllowedImpl(String origin) {
- // Called on the WebKit thread.
- mAllowed = nativeGetAllowed(origin);
- }
-
- /**
* Clears the permission state for the specified origin. This method may be
* called before the WebKit thread has intialized the message handler.
* Messages will be queued until this time.
*/
public void clear(String origin) {
// Called on the UI thread.
- if (mHandler == null) {
- if (mOriginsToClear == null) {
- mOriginsToClear = new HashSet<String>();
- }
- mOriginsToClear.add(origin);
- if (mOriginsToAllow != null) {
- mOriginsToAllow.remove(origin);
- }
- } else {
- postMessage(Message.obtain(null, CLEAR, origin));
- }
+ postMessage(Message.obtain(null, CLEAR, origin));
}
/**
@@ -283,17 +258,7 @@
*/
public void allow(String origin) {
// Called on the UI thread.
- if (mHandler == null) {
- if (mOriginsToAllow == null) {
- mOriginsToAllow = new HashSet<String>();
- }
- mOriginsToAllow.add(origin);
- if (mOriginsToClear != null) {
- mOriginsToClear.remove(origin);
- }
- } else {
- postMessage(Message.obtain(null, ALLOW, origin));
- }
+ postMessage(Message.obtain(null, ALLOW, origin));
}
/**
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 39e5275..662be95 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -916,9 +916,12 @@
}
/**
- * Tell the WebView to block network image. This is only checked when
- * getLoadsImagesAutomatically() is true.
- * @param flag True if the WebView should block network image
+ * Tell the WebView to block network images. This is only checked when
+ * {@link #getLoadsImagesAutomatically} is true. If you set the value to
+ * false, images will automatically be loaded. Use this api to reduce
+ * bandwidth only. Use {@link #setBlockNetworkLoads} if possible.
+ * @param flag True if the WebView should block network images.
+ * @see #setBlockNetworkLoads
*/
public synchronized void setBlockNetworkImage(boolean flag) {
if (mBlockNetworkImage != flag) {
@@ -928,17 +931,21 @@
}
/**
- * Return true if the WebView will block network image. The default is false.
- * @return True if the WebView blocks network image.
+ * Return true if the WebView will block network images. The default is
+ * false.
+ * @return True if the WebView blocks network images.
*/
public synchronized boolean getBlockNetworkImage() {
return mBlockNetworkImage;
}
/**
- * @hide
- * Tell the WebView to block all network load requests.
- * @param flag True if the WebView should block all network loads
+ * Tell the WebView to block all network load requests. If you set the
+ * value to false, you must call {@link android.webkit.WebView#reload} to
+ * fetch remote resources. This flag supercedes the value passed to
+ * {@link #setBlockNetworkImage}.
+ * @param flag True if the WebView should block all network loads.
+ * @see android.webkit.WebView#reload
*/
public synchronized void setBlockNetworkLoads(boolean flag) {
if (mBlockNetworkLoads != flag) {
@@ -948,9 +955,8 @@
}
/**
- * @hide
- * Return true if the WebView will block all network loads.
- * The default is false.
+ * Return true if the WebView will block all network loads. The default is
+ * false.
* @return True if the WebView blocks all network loads.
*/
public synchronized boolean getBlockNetworkLoads() {
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index cf71a84..9314d7b 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -146,7 +146,7 @@
* @hide
* Message handler, webcore side
*/
- public void createHandler() {
+ public synchronized void createHandler() {
if (mHandler == null) {
mHandler = new Handler() {
@Override
@@ -342,7 +342,7 @@
/**
* Utility function to send a message to our handler
*/
- private void postMessage(Message msg) {
+ private synchronized void postMessage(Message msg) {
if (mHandler != null) {
mHandler.sendMessage(msg);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 5f5df56..adae0cb 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4436,6 +4436,7 @@
ted.mX = viewToContentX((int) x + mScrollX);
ted.mY = viewToContentY((int) y + mScrollY);
ted.mEventTime = eventTime;
+ ted.mMetaState = ev.getMetaState();
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
mLastSentTouchTime = eventTime;
}
@@ -4699,6 +4700,7 @@
ted.mX = viewToContentX((int) x + mScrollX);
ted.mY = viewToContentY((int) y + mScrollY);
ted.mEventTime = eventTime;
+ ted.mMetaState = ev.getMetaState();
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
} else if (mFullScreenHolder == null) {
doDoubleTap();
@@ -5735,6 +5737,11 @@
ted.mX = viewToContentX((int) mLastTouchX + mScrollX);
ted.mY = viewToContentY((int) mLastTouchY + mScrollY);
ted.mEventTime = SystemClock.uptimeMillis();
+ // metaState for long press is tricky. Should it be the state
+ // when the press started or when the press was released? Or
+ // some intermediary key state? For simplicity for now, we
+ // don't set it.
+ ted.mMetaState = 0;
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
} else if (mPreventDrag == PREVENT_DRAG_NO) {
mTouchMode = TOUCH_DONE_MODE;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 3a3e445..361ec56 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -515,7 +515,7 @@
private native void nativeTouchUp(int touchGeneration,
int framePtr, int nodePtr, int x, int y);
- private native int nativeHandleTouchEvent(int action, int x, int y, long time);
+ private native int nativeHandleTouchEvent(int action, int x, int y, long time, int metaState);
private native void nativeUpdateFrameCache();
@@ -735,6 +735,7 @@
int mX;
int mY;
long mEventTime;
+ int mMetaState;
}
static class GeolocationPermissionsData {
@@ -1198,7 +1199,7 @@
mWebView.mPrivateHandler,
WebView.PREVENT_TOUCH_ID, ted.mAction,
nativeHandleTouchEvent(ted.mAction, ted.mX,
- ted.mY, ted.mEventTime)).sendToTarget();
+ ted.mY, ted.mEventTime, ted.mMetaState)).sendToTarget();
break;
}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 5308725c..2feed03 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3092,9 +3092,9 @@
previouslyFocusedRect.offset(mScrollX, mScrollY);
final ListAdapter adapter = mAdapter;
- final int firstPosition = mFirstPosition;
- // Don't cache the result of getChildCount here, it could change in layoutChildren.
- if (adapter.getCount() < getChildCount() + firstPosition) {
+ // Don't cache the result of getChildCount or mFirstPosition here,
+ // it could change in layoutChildren.
+ if (adapter.getCount() < getChildCount() + mFirstPosition) {
mLayoutMode = LAYOUT_NORMAL;
layoutChildren();
}
@@ -3104,6 +3104,7 @@
Rect otherRect = mTempRect;
int minDistance = Integer.MAX_VALUE;
final int childCount = getChildCount();
+ final int firstPosition = mFirstPosition;
for (int i = 0; i < childCount; i++) {
// only consider selectable views
diff --git a/core/java/com/android/internal/app/DisableCarModeActivity.java b/core/java/com/android/internal/app/DisableCarModeActivity.java
new file mode 100644
index 0000000..95dc1f9
--- /dev/null
+++ b/core/java/com/android/internal/app/DisableCarModeActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.app.Activity;
+import android.app.IUiModeManager;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+public class DisableCarModeActivity extends Activity {
+ private static final String TAG = "DisableCarModeActivity";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ try {
+ IUiModeManager uiModeManager = IUiModeManager.Stub.asInterface(
+ ServiceManager.getService("uimode"));
+ uiModeManager.disableCarMode();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to disable car mode", e);
+ }
+ finish();
+ }
+
+}
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index c5b869b..bc7dbf4 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -93,7 +93,7 @@
public static boolean unMountSdDir(String cid) {
try {
- int rc = getMountService().unmountSecureContainer(cid);
+ int rc = getMountService().unmountSecureContainer(cid, false);
if (rc != StorageResultCode.OperationSucceeded) {
Log.e(TAG, "Failed to unmount " + cid + " with rc " + rc);
return false;
@@ -148,7 +148,7 @@
public static boolean destroySdDir(String cid) {
try {
- int rc = getMountService().destroySecureContainer(cid);
+ int rc = getMountService().destroySecureContainer(cid, false);
if (rc != StorageResultCode.OperationSucceeded) {
Log.i(TAG, "Failed to destroy container " + cid);
return false;
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 15dcbd6..22c6e79 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -1,5 +1,6 @@
package com.android.internal.view;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
@@ -17,7 +18,7 @@
}
public void resized(int w, int h, Rect coveredInsets,
- Rect visibleInsets, boolean reportDraw) {
+ Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
if (reportDraw) {
try {
mSession.finishDrawing(this);
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
index e6a1872..819cce8 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -7,9 +7,9 @@
#include <jni.h>
YuvToJpegEncoder* YuvToJpegEncoder::create(int format, int* strides) {
- // Only PIXEL_FORMAT_YCbCr_420_SP and PIXEl_FOMAT_YCbCr_422_I are supported
+ // Only ImageFormat.NV21 and ImageFormat.YUY2 are supported
// for now.
- if (format == HAL_PIXEL_FORMAT_YCbCr_420_SP) {
+ if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
return new Yuv420SpToJpegEncoder(strides);
} else if (format == HAL_PIXEL_FORMAT_YCbCr_422_I) {
return new Yuv422IToJpegEncoder(strides);
diff --git a/core/jni/android_graphics_PixelFormat.cpp b/core/jni/android_graphics_PixelFormat.cpp
index 0643622..5b8363c 100644
--- a/core/jni/android_graphics_PixelFormat.cpp
+++ b/core/jni/android_graphics_PixelFormat.cpp
@@ -48,11 +48,35 @@
JNIEnv* env, jobject clazz, jint format, jobject pixelFormatObject)
{
PixelFormatInfo info;
- status_t err = getPixelFormatInfo(format, &info);
+ status_t err;
+
+ // we need this for backward compatibility with PixelFormat's
+ // deprecated constants
+ switch (format) {
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ // defined as the bytes per pixel of the Y plane
+ info.bytesPerPixel = 1;
+ info.bitsPerPixel = 16;
+ goto done;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ // defined as the bytes per pixel of the Y plane
+ info.bytesPerPixel = 1;
+ info.bitsPerPixel = 12;
+ goto done;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ // defined as the bytes per pixel of the Y plane
+ info.bytesPerPixel = 1;
+ info.bitsPerPixel = 16;
+ goto done;
+ }
+
+ err = getPixelFormatInfo(format, &info);
if (err < 0) {
doThrow(env, "java/lang/IllegalArgumentException");
return;
}
+
+done:
env->SetIntField(pixelFormatObject, offsets.bytesPerPixel, info.bytesPerPixel);
env->SetIntField(pixelFormatObject, offsets.bitsPerPixel, info.bitsPerPixel);
}
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 4e1ae62..5432efb 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -1122,9 +1122,10 @@
if (dbus_set_error_from_message(&err, msg)) {
if (dbus_error_has_name(&err, "org.bluez.Error.AlreadyExists")) {
result = CREATE_DEVICE_ALREADY_EXISTS;
+ } else {
+ result = CREATE_DEVICE_FAILED;
}
LOG_AND_FREE_DBUS_ERROR(&err);
- result = CREATE_DEVICE_FAILED;
}
env->CallVoidMethod(nat->me,
method_onCreateDeviceResult,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a27d28f..333db05 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1252,6 +1252,10 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
+ <activity android:name="com.android.internal.app.DisableCarModeActivity"
+ android:theme="@style/Theme.NoDisplay"
+ android:excludeFromRecents="true">
+ </activity>
<activity android:name="com.android.internal.app.RingtonePickerActivity"
android:theme="@style/Theme.Dialog.Alert"
android:excludeFromRecents="true"
diff --git a/core/res/res/drawable-hdpi/stat_notify_car_mode.png b/core/res/res/drawable-hdpi/stat_notify_car_mode.png
new file mode 100644
index 0000000..6c51b32
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_car_mode.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_car_mode.png b/core/res/res/drawable-mdpi/stat_notify_car_mode.png
new file mode 100644
index 0000000..c664244
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_notify_car_mode.png
Binary files differ
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6f34b4f..cdf38b9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2261,4 +2261,9 @@
<!-- See TETHER_STOP_DIALOG. If there was an error disconnect, this is the text. -->
<string name="tether_stop_error_message">We\'ve encountered a problem turning off Tethering. Please try again.</string>
+ <!-- Strings for car mode notification -->
+ <!-- Shown when car mode is enabled -->
+ <string name="car_mode_disable_notification_title">Car mode enabled</string>
+ <string name="car_mode_disable_notification_message">Select to disable car mode.</string>
+
</resources>
diff --git a/core/res/res/xml-mdpi/password_kbd_qwerty.xml b/core/res/res/xml-mdpi/password_kbd_qwerty.xml
index a3d4e88..bae1b42 100755
--- a/core/res/res/xml-mdpi/password_kbd_qwerty.xml
+++ b/core/res/res/xml-mdpi/password_kbd_qwerty.xml
@@ -80,8 +80,8 @@
<Key android:keyLabel="=" />
<Key android:codes="46" android:keyLabel="."
android:keyWidth="10%p"/>
- <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
- android:iconPreview="@drawable/sym_keyboard_feedback_return"
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_ok"
+ android:iconPreview="@drawable/sym_keyboard_feedback_ok"
android:keyWidth="20%p" android:keyEdgeFlags="right"/>
</Row>
diff --git a/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml b/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml
index 2285d91..612df9c 100755
--- a/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml
+++ b/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml
@@ -79,8 +79,8 @@
android:keyWidth="20%p" android:isRepeatable="true"/>
<Key android:keyLabel="+" />
<Key android:codes="46" android:keyLabel="."/>
- <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
- android:iconPreview="@drawable/sym_keyboard_feedback_return"
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_ok"
+ android:iconPreview="@drawable/sym_keyboard_feedback_ok"
android:keyWidth="20%p" android:keyEdgeFlags="right"/>
</Row>
diff --git a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
index ca650e0..e43031c 100644
--- a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
@@ -944,6 +944,7 @@
Assert.assertNull(cur.getString(3));
Assert.assertEquals(1234, cur.getLong(4));
Assert.assertNull(cur.getString(5));
+ cur.close();
cv = new ContentValues();
cv.put("s", "two");
@@ -956,6 +957,7 @@
Assert.assertNull(cur.getString(3));
Assert.assertEquals(1234, cur.getLong(4));
Assert.assertNull(cur.getString(5));
+ cur.close();
cv = new ContentValues();
cv.put("t", "goodbye world");
@@ -975,6 +977,7 @@
Assert.assertEquals(2345, cur.getLong(3));
Assert.assertEquals(3456, cur.getLong(4));
Assert.assertEquals("tricky", cur.getString(5));
+ cur.close();
cv = new ContentValues();
cv.put("s", "three");
@@ -987,6 +990,7 @@
Assert.assertEquals("three", cur.getString(1));
Assert.assertEquals("hello world", cur.getString(2));
Assert.assertEquals(6789, cur.getLong(3));
+ cur.close();
ih.close();
}
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteGeneralTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteGeneralTest.java
new file mode 100644
index 0000000..af7ccce
--- /dev/null
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteGeneralTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2006 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 android.database.sqlite;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.FlakyTest;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import java.io.File;
+
+public class SQLiteGeneralTest extends AndroidTestCase {
+
+ private SQLiteDatabase mDatabase;
+ private File mDatabaseFile;
+ Boolean exceptionRecvd = false;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ exceptionRecvd = false;
+ File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
+ mDatabaseFile = new File(dbDir, "database_test.db");
+ if (mDatabaseFile.exists()) {
+ mDatabaseFile.delete();
+ }
+ mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
+ assertNotNull(mDatabase);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mDatabase.close();
+ mDatabaseFile.delete();
+ super.tearDown();
+ }
+
+ @LargeTest
+ public void testUseOfSameSqlStatementBy2Threads() throws Exception {
+ mDatabase.execSQL("CREATE TABLE test_pstmt (i INTEGER PRIMARY KEY, j text);");
+
+ // thread 1 creates a prepared statement
+ final String stmt = "SELECT * FROM test_pstmt WHERE i = ?";
+
+ // start 2 threads to do repeatedly execute "stmt"
+ // since these 2 threads are executing the same sql, they each should get
+ // their own copy and
+ // there SHOULD NOT be an error from sqlite: "prepared statement is busy"
+ class RunStmtThread extends Thread {
+ private static final int N = 1000;
+ @Override public void run() {
+ int i = 0;
+ try {
+ // execute many times
+ for (i = 0; i < N; i++) {
+ SQLiteStatement s1 = mDatabase.compileStatement(stmt);
+ s1.bindLong(1, i);
+ s1.execute();
+ s1.close();
+ }
+ } catch (SQLiteException e) {
+ fail("SQLiteException: " + e.getMessage());
+ return;
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("random unexpected exception: " + e.getMessage());
+ return;
+ }
+ }
+ }
+ RunStmtThread t1 = new RunStmtThread();
+ t1.start();
+ RunStmtThread t2 = new RunStmtThread();
+ t2.start();
+ while (t1.isAlive() || t2.isAlive()) {
+ Thread.sleep(1000);
+ }
+ }
+
+ @FlakyTest
+ public void testUseOfSamePreparedStatementBy2Threads() throws Exception {
+ mDatabase.execSQL("CREATE TABLE test_pstmt (i INTEGER PRIMARY KEY, j text);");
+
+ // thread 1 creates a prepared statement
+ final String stmt = "SELECT * FROM test_pstmt WHERE i = ?";
+ final SQLiteStatement s1 = mDatabase.compileStatement(stmt);
+
+ // start 2 threads to do repeatedly execute "stmt"
+ // since these 2 threads are executing the same prepared statement,
+ // should see an error from sqlite: "prepared statement is busy"
+ class RunStmtThread extends Thread {
+ private static final int N = 1000;
+ @Override public void run() {
+ int i = 0;
+ try {
+ // execute many times
+ for (i = 0; i < N; i++) {
+ s1.bindLong(1, i);
+ s1.execute();
+ }
+ } catch (SQLiteException e) {
+ // expect it
+ assertTrue(e.getMessage().contains("library routine called out of sequence:"));
+ exceptionRecvd = true;
+ return;
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("random unexpected exception: " + e.getMessage());
+ return;
+ }
+ }
+ }
+ RunStmtThread t1 = new RunStmtThread();
+ t1.start();
+ RunStmtThread t2 = new RunStmtThread();
+ t2.start();
+ while (t1.isAlive() || t2.isAlive()) {
+ Thread.sleep(1000);
+ }
+ assertTrue(exceptionRecvd);
+ }
+}
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
new file mode 100644
index 0000000..f126374
--- /dev/null
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+public class ImageFormat
+{
+ /* these constants are chosen to be binary compatible with
+ * their previous location in PixelFormat.java */
+
+ public static final int UNKNOWN = 0;
+
+ /** RGB format used for pictures encoded as RGB_565
+ * see {@link android.hardware.Camera.Parameters#setPictureFormat(int)}.
+ */
+ public static final int RGB_565 = 4;
+
+ /**
+ * YCbCr formats, used for video. These are not necessarily supported
+ * by the hardware.
+ */
+ public static final int NV16 = 0x10;
+
+
+ /** YCrCb format used for images, which uses the NV21 encoding format.
+ * This is the default format for camera preview images, when not
+ * otherwise set with
+ * {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}.
+ */
+ public static final int NV21 = 0x11;
+
+
+ /** YCbCr format used for images, which uses YUYV (YUY2) encoding format.
+ * This is an alternative format for camera preview images. Whether this
+ * format is supported by the camera hardware can be determined by
+ * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}.
+ */
+ public static final int YUY2 = 0x14;
+
+
+ /**
+ * Encoded formats. These are not necessarily supported by the hardware.
+ */
+ public static final int JPEG = 0x100;
+
+
+ /**
+ * Use this function to retrieve the number of bits per pixel of
+ * an ImageFormat.
+ * @param format
+ * @return the number of bits per pixel of the given format or -1 if the
+ * format doesn't exist or is not supported.
+ */
+ public static int getBitsPerPixel(int format) {
+ switch (format) {
+ case RGB_565: return 16;
+ case NV16: return 16;
+ case NV21: return 12;
+ case YUY2: return 16;
+ }
+ return -1;
+ }
+}
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
index c76cee7..182f14d 100644
--- a/graphics/java/android/graphics/PixelFormat.java
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -18,8 +18,7 @@
public class PixelFormat
{
- /* these constants need to match those
- in ui/PixelFormat.h & pixelflinger/format.h */
+ /* these constants need to match those in hardware/hardware.h */
public static final int UNKNOWN = 0;
@@ -46,30 +45,34 @@
public static final int L_8 = 9;
public static final int LA_88 = 0xA;
public static final int RGB_332 = 0xB;
-
+
+
/**
- * YCbCr formats, used for video. These are not necessarily supported
- * by the hardware.
+ * @deprecated use {@link android.graphics.ImageFormat#NV16
+ * ImageFormat.NV16} instead.
*/
+ @Deprecated
public static final int YCbCr_422_SP= 0x10;
- /** YCbCr format used for images, which uses the NV21 encoding format.
- * This is the default format for camera preview images, when not
- * otherwise set with
- * {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}.
+ /**
+ * @deprecated use {@link android.graphics.ImageFormat#NV21
+ * ImageFormat.NV21} instead.
*/
+ @Deprecated
public static final int YCbCr_420_SP= 0x11;
- /** YCbCr format used for images, which uses YUYV (YUY2) encoding format.
- * This is an alternative format for camera preview images. Whether this
- * format is supported by the camera hardware can be determined by
- * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}.
+ /**
+ * @deprecated use {@link android.graphics.ImageFormat#YUY2
+ * ImageFormat.YUY2} instead.
*/
+ @Deprecated
public static final int YCbCr_422_I = 0x14;
/**
- * Encoded formats. These are not necessarily supported by the hardware.
+ * @deprecated use {@link android.graphics.ImageFormat#JPEG
+ * ImageFormat.JPEG} instead.
*/
+ @Deprecated
public static final int JPEG = 0x100;
/*
diff --git a/graphics/java/android/graphics/YuvImage.java b/graphics/java/android/graphics/YuvImage.java
index 5a4531b..9368da6 100644
--- a/graphics/java/android/graphics/YuvImage.java
+++ b/graphics/java/android/graphics/YuvImage.java
@@ -22,7 +22,7 @@
* YuvImage contains YUV data and provides a method that compresses a region of
* the YUV data to a Jpeg. The YUV data should be provided as a single byte
* array irrespective of the number of image planes in it.
- * Currently only PixelFormat.YCbCr_420_SP and PixelFormat.YCbCr_422_I are supported.
+ * Currently only ImageFormat.NV21 and ImageFormat.YUY2 are supported.
*
* To compress a rectangle region in the YUV data, users have to specify the
* region by left, top, width and height.
@@ -77,11 +77,11 @@
* null.
*/
public YuvImage(byte[] yuv, int format, int width, int height, int[] strides) {
- if (format != PixelFormat.YCbCr_420_SP &&
- format != PixelFormat.YCbCr_422_I) {
+ if (format != ImageFormat.NV21 &&
+ format != ImageFormat.YUY2) {
throw new IllegalArgumentException(
- "only support PixelFormat.YCbCr_420_SP " +
- "and PixelFormat.YCbCr_422_I for now");
+ "only support ImageFormat.NV21 " +
+ "and ImageFormat.YUY2 for now");
}
if (width <= 0 || height <= 0) {
@@ -107,7 +107,7 @@
/**
* Compress a rectangle region in the YuvImage to a jpeg.
- * Only PixelFormat.YCbCr_420_SP and PixelFormat.YCbCr_422_I
+ * Only ImageFormat.NV21 and ImageFormat.YUY2
* are supported for now.
*
* @param rectangle The rectangle region to be compressed. The medthod checks if rectangle is
@@ -181,14 +181,14 @@
int[] calculateOffsets(int left, int top) {
int[] offsets = null;
- if (mFormat == PixelFormat.YCbCr_420_SP) {
+ if (mFormat == ImageFormat.NV21) {
offsets = new int[] {top * mStrides[0] + left,
mHeight * mStrides[0] + top / 2 * mStrides[1]
+ left / 2 * 2 };
return offsets;
}
- if (mFormat == PixelFormat.YCbCr_422_I) {
+ if (mFormat == ImageFormat.YUY2) {
offsets = new int[] {top * mStrides[0] + left / 2 * 4};
return offsets;
}
@@ -198,12 +198,12 @@
private int[] calculateStrides(int width, int format) {
int[] strides = null;
- if (format == PixelFormat.YCbCr_420_SP) {
+ if (format == ImageFormat.NV21) {
strides = new int[] {width, width};
return strides;
}
- if (format == PixelFormat.YCbCr_422_I) {
+ if (format == ImageFormat.YUY2) {
strides = new int[] {width * 2};
return strides;
}
@@ -214,7 +214,7 @@
private void adjustRectangle(Rect rect) {
int width = rect.width();
int height = rect.height();
- if (mFormat == PixelFormat.YCbCr_420_SP) {
+ if (mFormat == ImageFormat.NV21) {
// Make sure left, top, width and height are all even.
width &= ~1;
height &= ~1;
@@ -224,7 +224,7 @@
rect.bottom = rect.top + height;
}
- if (mFormat == PixelFormat.YCbCr_422_I) {
+ if (mFormat == ImageFormat.YUY2) {
// Make sure left and width are both even.
width &= ~1;
rect.left &= ~1;
diff --git a/libs/rs/java/Fountain/AndroidManifest.xml b/libs/rs/java/Fountain/AndroidManifest.xml
index 1185930..951c451 100644
--- a/libs/rs/java/Fountain/AndroidManifest.xml
+++ b/libs/rs/java/Fountain/AndroidManifest.xml
@@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.fountain">
- <application android:label="Fountain">
+ <application
+ android:label="Fountain"
+ android:icon="@drawable/test_pattern">
<activity android:name="Fountain">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/libs/rs/java/Fountain/res/drawable/test_pattern.png b/libs/rs/java/Fountain/res/drawable/test_pattern.png
new file mode 100644
index 0000000..e7d1455
--- /dev/null
+++ b/libs/rs/java/Fountain/res/drawable/test_pattern.png
Binary files differ
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 34252ab..1f02608 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -500,22 +500,6 @@
doScanFile(path, mimeType, lastModified, fileSize, false);
}
- private boolean isMetadataSupported(int fileType) {
- if (mFileType == MediaFile.FILE_TYPE_MP3 ||
- mFileType == MediaFile.FILE_TYPE_MP4 ||
- mFileType == MediaFile.FILE_TYPE_M4A ||
- mFileType == MediaFile.FILE_TYPE_3GPP ||
- mFileType == MediaFile.FILE_TYPE_3GPP2 ||
- mFileType == MediaFile.FILE_TYPE_OGG ||
- mFileType == MediaFile.FILE_TYPE_AAC ||
- mFileType == MediaFile.FILE_TYPE_MID ||
- mFileType == MediaFile.FILE_TYPE_WMA) {
- // we only extract metadata from MP3, M4A, OGG, MID, AAC and WMA files.
- // check MP4 files, to determine if they contain only audio.
- return true;
- }
- return false;
- }
public Uri doScanFile(String path, String mimeType, long lastModified, long fileSize, boolean scanAlways) {
Uri result = null;
// long t1 = System.currentTimeMillis();
@@ -531,10 +515,8 @@
boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) ||
(!ringtones && !notifications && !alarms && !podcasts);
- if( isMetadataSupported(mFileType) ) {
+ if (!MediaFile.isImageFileType(mFileType)) {
processFile(path, mimeType, this);
- } else if (MediaFile.isImageFileType(mFileType)) {
- // we used to compute the width and height but it's not worth it
}
result = endFile(entry, ringtones, notifications, alarms, music, podcasts);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index b4fc035..50dad33 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1614,6 +1614,8 @@
size_t actualSize = (*me->mCallback)(
me, buffer->raw, buffer->size, me->mCallbackCookie);
+ buffer->size = actualSize;
+
if (actualSize > 0) {
me->snoopWrite(buffer->raw, actualSize);
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 59a5f9d..b3a73b0 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -178,7 +178,8 @@
}
AwesomePlayer::AwesomePlayer()
- : mTimeSource(NULL),
+ : mQueueStarted(false),
+ mTimeSource(NULL),
mVideoRendererIsPreview(false),
mAudioPlayer(NULL),
mFlags(0),
@@ -201,13 +202,13 @@
mAudioStatusEventPending = false;
- mQueue.start();
-
reset();
}
AwesomePlayer::~AwesomePlayer() {
- mQueue.stop();
+ if (mQueueStarted) {
+ mQueue.stop();
+ }
reset();
@@ -443,6 +444,8 @@
notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
pause_l();
+
+ mFlags |= AT_EOS;
}
}
@@ -517,6 +520,12 @@
postBufferingEvent_l();
+ if (mFlags & AT_EOS) {
+ // Legacy behaviour, if a stream finishes playing and then
+ // is started again, we play from the start...
+ seekTo_l(0);
+ }
+
return OK;
}
@@ -651,6 +660,7 @@
status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
mSeeking = true;
mSeekTimeUs = timeUs;
+ mFlags &= ~AT_EOS;
seekAudioIfNecessary_l();
@@ -989,6 +999,11 @@
return UNKNOWN_ERROR; // async prepare already pending
}
+ if (!mQueueStarted) {
+ mQueue.start();
+ mQueueStarted = true;
+ }
+
mFlags |= PREPARING;
mAsyncPrepareEvent = new AwesomeEvent(
this, &AwesomePlayer::onPrepareAsyncEvent);
@@ -1089,7 +1104,7 @@
state->mUriHeaders = mUriHeaders;
state->mFileSource = mFileSource;
- state->mFlags = mFlags & (PLAYING | LOOPING);
+ state->mFlags = mFlags & (PLAYING | LOOPING | AT_EOS);
getPosition_l(&state->mPositionUs);
if (mLastVideoBuffer) {
@@ -1150,7 +1165,7 @@
seekTo_l(state->mPositionUs);
- mFlags = state->mFlags & LOOPING;
+ mFlags = state->mFlags & (LOOPING | AT_EOS);
if (state->mLastVideoFrame && mISurface != NULL) {
mVideoRenderer =
diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp
index 76ca77b..363e121 100644
--- a/media/libstagefright/Prefetcher.cpp
+++ b/media/libstagefright/Prefetcher.cpp
@@ -337,24 +337,20 @@
void PrefetchedSource::cacheMore() {
MediaSource::ReadOptions options;
- {
- Mutex::Autolock autoLock(mLock);
+ Mutex::Autolock autoLock(mLock);
- if (!mStarted) {
- return;
- }
+ if (!mStarted) {
+ return;
+ }
- if (mSeekTimeUs >= 0) {
- options.setSeekTo(mSeekTimeUs);
- mSeekTimeUs = -1;
- }
+ if (mSeekTimeUs >= 0) {
+ options.setSeekTo(mSeekTimeUs);
+ mSeekTimeUs = -1;
}
MediaBuffer *buffer;
status_t err = mSource->read(&buffer, &options);
- Mutex::Autolock autoLock(mLock);
-
if (err != OK) {
mReachedEOS = true;
mCondition.signal();
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 114d4c6..ce8eeae 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -92,12 +92,14 @@
FIRST_FRAME = 4,
PREPARING = 8,
PREPARED = 16,
+ AT_EOS = 32,
};
mutable Mutex mLock;
OMXClient mClient;
TimedEventQueue mQueue;
+ bool mQueueStarted;
wp<MediaPlayerBase> mListener;
sp<ISurface> mISurface;
diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java
index 407983d..477ea0c 100644
--- a/services/java/com/android/server/AccessibilityManagerService.java
+++ b/services/java/com/android/server/AccessibilityManagerService.java
@@ -16,8 +16,6 @@
package com.android.server;
-import static android.util.Config.LOGV;
-
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.HandlerCaller.SomeArgs;
@@ -47,6 +45,7 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
+import android.util.Config;
import android.util.Log;
import android.util.SparseArray;
import android.view.accessibility.AccessibilityEvent;
@@ -137,10 +136,6 @@
registerPackageChangeAndBootCompletedBroadcastReceiver();
registerSettingsContentObservers();
-
- synchronized (mLock) {
- populateAccessibilityServiceListLocked();
- }
}
/**
@@ -155,13 +150,19 @@
public void onReceive(Context context, Intent intent) {
synchronized (mLock) {
populateAccessibilityServiceListLocked();
- manageServicesLocked();
if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
+ // get the accessibility enabled setting on boot
mIsEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
- updateClientsLocked();
+
+ // if accessibility is enabled inform our clients we are on
+ if (mIsEnabled) {
+ updateClientsLocked();
+ }
}
+
+ manageServicesLocked();
}
}
};
@@ -169,7 +170,6 @@
// package changes
IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
packageFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
packageFilter.addDataScheme("package");
@@ -409,7 +409,7 @@
try {
listener.onAccessibilityEvent(event);
- if (LOGV) {
+ if (Config.DEBUG) {
Log.i(LOG_TAG, "Event " + event + " sent to " + listener);
}
} catch (RemoteException re) {
@@ -434,7 +434,7 @@
mServices.remove(service);
mHandler.removeMessages(service.mId);
- if (LOGV) {
+ if (Config.DEBUG) {
Log.i(LOG_TAG, "Dead service " + service.mService + " removed");
}
@@ -547,6 +547,7 @@
Map<ComponentName, Service> componentNameToServiceMap = mComponentNameToServiceMap;
List<Service> services = mServices;
+ boolean isEnabled = mIsEnabled;
for (int i = 0, count = installedServices.size(); i < count; i++) {
ServiceInfo intalledService = installedServices.get(i);
@@ -554,7 +555,7 @@
intalledService.name);
Service service = componentNameToServiceMap.get(componentName);
- if (enabledServices.contains(componentName)) {
+ if (isEnabled && enabledServices.contains(componentName)) {
if (service == null) {
new Service(componentName).bind();
}
@@ -578,6 +579,7 @@
} catch (RemoteException re) {
mClients.remove(i);
count--;
+ i--;
}
}
}
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index b566fb7e..4791718 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -22,8 +22,10 @@
import android.app.IActivityManager;
import android.app.IUiModeManager;
import android.app.KeyguardManager;
-import android.app.StatusBarManager;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.StatusBarManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.ActivityNotFoundException;
@@ -55,6 +57,8 @@
import android.text.format.Time;
import android.util.Log;
+import com.android.internal.R;
+import com.android.internal.app.DisableCarModeActivity;
import com.android.internal.widget.LockPatternUtils;
import java.io.FileNotFoundException;
@@ -101,6 +105,7 @@
private final Context mContext;
private PowerManagerService mPowerManager;
+ private NotificationManager mNotificationManager;
private KeyguardManager.KeyguardLock mKeyguardLock;
private boolean mKeyguardDisabled;
@@ -125,7 +130,8 @@
// Launch a dock activity
String category;
- if (mCarModeEnabled || mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
+ if (mCarModeEnabled) {
+ // Only launch car home when car mode is enabled.
category = Intent.CATEGORY_CAR_DOCK;
} else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
category = Intent.CATEGORY_DESK_DOCK;
@@ -332,9 +338,13 @@
if (mCarModeEnabled && mDockState != Intent.EXTRA_DOCK_STATE_CAR) {
// Pretend to be in DOCK_STATE_CAR.
intent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_CAR);
+ } else if (!mCarModeEnabled && mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
+ // Pretend to be in DOCK_STATE_UNDOCKED.
+ intent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED);
} else {
intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
}
+ intent.putExtra(Intent.EXTRA_PHYSICAL_DOCK_STATE, mDockState);
intent.putExtra(Intent.EXTRA_CAR_MODE_ENABLED, mCarModeEnabled);
// Check if this is Bluetooth Dock
@@ -462,6 +472,52 @@
}
};
+ private void adjustStatusBarCarMode() {
+ if (mStatusBarManager == null) {
+ mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
+ }
+
+ // Fear not: StatusBarService manages a list of requests to disable
+ // features of the status bar; these are ORed together to form the
+ // active disabled list. So if (for example) the device is locked and
+ // the status bar should be totally disabled, the calls below will
+ // have no effect until the device is unlocked.
+ if (mStatusBarManager != null) {
+ long ident = Binder.clearCallingIdentity();
+ mStatusBarManager.disable(mCarModeEnabled
+ ? StatusBarManager.DISABLE_NOTIFICATION_TICKER
+ : StatusBarManager.DISABLE_NONE);
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ if (mNotificationManager == null) {
+ mNotificationManager = (NotificationManager)
+ mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+
+ if (mNotificationManager != null) {
+ long ident = Binder.clearCallingIdentity();
+ if (mCarModeEnabled) {
+ Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class);
+
+ Notification n = new Notification();
+ n.icon = R.drawable.stat_notify_car_mode;
+ n.defaults = Notification.DEFAULT_LIGHTS;
+ n.flags = Notification.FLAG_ONGOING_EVENT;
+ n.when = 0;
+ n.setLatestEventInfo(
+ mContext,
+ mContext.getString(R.string.car_mode_disable_notification_title),
+ mContext.getString(R.string.car_mode_disable_notification_message),
+ PendingIntent.getActivity(mContext, 0, carModeOffIntent, 0));
+ mNotificationManager.notify(0, n);
+ } else {
+ mNotificationManager.cancel(0);
+ }
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
private void setCarMode(boolean enabled) throws RemoteException {
mCarModeEnabled = enabled;
if (enabled) {
@@ -475,23 +531,7 @@
setMode(Configuration.UI_MODE_TYPE_NORMAL,
Configuration.UI_MODE_NIGHT_UNDEFINED);
}
-
- if (mStatusBarManager == null) {
- mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
- }
-
- // Fear not: StatusBarService manages a list of requests to disable
- // features of the status bar; these are ORed together to form the
- // active disabled list. So if (for example) the device is locked and
- // the status bar should be totally disabled, the calls below will
- // have no effect until the device is unlocked.
- if (mStatusBarManager != null) {
- long ident = Binder.clearCallingIdentity();
- mStatusBarManager.disable(enabled
- ? StatusBarManager.DISABLE_NOTIFICATION_TICKER
- : StatusBarManager.DISABLE_NONE);
- Binder.restoreCallingIdentity(ident);
- }
+ adjustStatusBarCarMode();
}
private void setMode(int modeType, int modeNight) throws RemoteException {
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 4e2ffa4..2a78806 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -97,7 +97,7 @@
public static final int OpFailedMediaBlank = 402;
public static final int OpFailedMediaCorrupt = 403;
public static final int OpFailedVolNotMounted = 404;
- public static final int OpFailedVolBusy = 405;
+ public static final int OpFailedStorageBusy = 405;
/*
* 600 series - Unsolicited broadcasts.
@@ -142,13 +142,31 @@
if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
mBooted = true;
- String path = Environment.getExternalStorageDirectory().getPath();
- if (getVolumeState(path).equals(Environment.MEDIA_UNMOUNTED)) {
- int rc = doMountVolume(path);
- if (rc != StorageResultCode.OperationSucceeded) {
- Log.e(TAG, String.format("Boot-time mount failed (%d)", rc));
- }
+ /*
+ * In the simulator, we need to broadcast a volume mounted event
+ * to make the media scanner run.
+ */
+ if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
+ notifyVolumeStateChange(null, "/sdcard", VolumeState.NoMedia, VolumeState.Mounted);
+ return;
}
+ new Thread() {
+ public void run() {
+ try {
+ String path = Environment.getExternalStorageDirectory().getPath();
+ if (getVolumeState(
+ Environment.getExternalStorageDirectory().getPath()).equals(
+ Environment.MEDIA_UNMOUNTED)) {
+ int rc = doMountVolume(path);
+ if (rc != StorageResultCode.OperationSucceeded) {
+ Log.e(TAG, String.format("Boot-time mount failed (%d)", rc));
+ }
+ }
+ } catch (Exception ex) {
+ Log.e(TAG, "Boot-time mount exception", ex);
+ }
+ }
+ }.start();
}
}
};
@@ -184,7 +202,7 @@
String vs = getVolumeState(path);
if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
mUmsEnabling = enable; // Override for isUsbMassStorageEnabled()
- int rc = doUnmountVolume(path);
+ int rc = doUnmountVolume(path, false);
mUmsEnabling = false; // Clear override
if (rc != StorageResultCode.OperationSucceeded) {
Log.e(TAG, String.format("Failed to unmount before enabling UMS (%d)", rc));
@@ -527,7 +545,7 @@
return rc;
}
- private int doUnmountVolume(String path) {
+ private int doUnmountVolume(String path, boolean force) {
if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
return VoldResponseCode.OpFailedVolNotMounted;
}
@@ -537,7 +555,8 @@
// notified that the applications installed on the media will be killed.
mPms.updateExternalMediaStatus(false);
try {
- mConnector.doCommand(String.format("volume unmount %s", path));
+ mConnector.doCommand(String.format(
+ "volume unmount %s%s", path, (force ? " force" : "")));
return StorageResultCode.OperationSucceeded;
} catch (NativeDaemonConnectorException e) {
// Don't worry about mismatch in PackageManager since the
@@ -545,6 +564,8 @@
int code = e.getCode();
if (code == VoldResponseCode.OpFailedVolNotMounted) {
return StorageResultCode.OperationFailedStorageNotMounted;
+ } else if (code == VoldResponseCode.OpFailedStorageBusy) {
+ return StorageResultCode.OperationFailedStorageBusy;
} else {
return StorageResultCode.OperationFailedInternalError;
}
@@ -639,15 +660,6 @@
public MountService(Context context) {
mContext = context;
- /*
- * Vold does not run in the simulator, so fake out a mounted
- * event to trigger MediaScanner
- */
- if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
- updatePublicVolumeState("/sdcard", Environment.MEDIA_MOUNTED);
- return;
- }
-
// XXX: This will go away soon in favor of IMountServiceObserver
mPms = (PackageManagerService) ServiceManager.getService("package");
@@ -656,6 +668,16 @@
mListeners = new ArrayList<MountServiceBinderListener>();
+ /*
+ * Vold does not run in the simulator, so pretend the connector thread
+ * ran and did its thing.
+ */
+ if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
+ mReady = true;
+ mUmsEnabling = true;
+ return;
+ }
+
mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
mReady = false;
Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
@@ -733,7 +755,7 @@
/*
* If the media is mounted, then gracefully unmount it.
*/
- if (doUnmountVolume(path) != StorageResultCode.OperationSucceeded) {
+ if (doUnmountVolume(path, true) != StorageResultCode.OperationSucceeded) {
Log.e(TAG, "Failed to unmount media for shutdown");
}
}
@@ -782,11 +804,11 @@
return doMountVolume(path);
}
- public int unmountVolume(String path) {
+ public int unmountVolume(String path, boolean force) {
validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();
- return doUnmountVolume(path);
+ return doUnmountVolume(path, force);
}
public int formatVolume(String path) {
@@ -878,16 +900,21 @@
return rc;
}
- public int destroySecureContainer(String id) {
+ public int destroySecureContainer(String id, boolean force) {
validatePermission(android.Manifest.permission.ASEC_DESTROY);
waitForReady();
warnOnNotMounted();
int rc = StorageResultCode.OperationSucceeded;
try {
- mConnector.doCommand(String.format("asec destroy %s", id));
+ mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : "")));
} catch (NativeDaemonConnectorException e) {
- rc = StorageResultCode.OperationFailedInternalError;
+ int code = e.getCode();
+ if (code == VoldResponseCode.OpFailedStorageBusy) {
+ rc = StorageResultCode.OperationFailedStorageBusy;
+ } else {
+ rc = StorageResultCode.OperationFailedInternalError;
+ }
}
if (rc == StorageResultCode.OperationSucceeded) {
@@ -928,7 +955,7 @@
return rc;
}
- public int unmountSecureContainer(String id) {
+ public int unmountSecureContainer(String id, boolean force) {
validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
waitForReady();
warnOnNotMounted();
@@ -940,11 +967,16 @@
}
int rc = StorageResultCode.OperationSucceeded;
- String cmd = String.format("asec unmount %s", id);
+ String cmd = String.format("asec unmount %s%s", id, (force ? " force" : ""));
try {
mConnector.doCommand(cmd);
} catch (NativeDaemonConnectorException e) {
- rc = StorageResultCode.OperationFailedInternalError;
+ int code = e.getCode();
+ if (code == VoldResponseCode.OpFailedStorageBusy) {
+ rc = StorageResultCode.OperationFailedStorageBusy;
+ } else {
+ rc = StorageResultCode.OperationFailedInternalError;
+ }
}
if (rc == StorageResultCode.OperationSucceeded) {
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index b9bb16f1..958d089 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -28,6 +28,7 @@
import android.net.INetworkManagementEventObserver;
import android.os.INetworkManagementService;
import android.os.Handler;
+import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
@@ -87,6 +88,10 @@
mObservers = new ArrayList<INetworkManagementEventObserver>();
+ if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
+ return;
+ }
+
mConnector = new NativeDaemonConnector(
new NetdCallbackReceiver(), "netd", 10, "NetdConnector");
Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
@@ -420,4 +425,35 @@
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
mConnector.doCommand(String.format("pppd detach %s", tty));
}
+
+ public void startUsbRNDIS() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand("usb startrndis");
+ }
+
+ public void stopUsbRNDIS() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand("usb stoprndis");
+ }
+
+ public boolean isUsbRNDISStarted() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+ ArrayList<String> rsp = mConnector.doCommand("usb rndisstatus");
+
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == NetdResponseCode.UsbRNDISStatusResult) {
+ if (tok[2].equals("started"))
+ return true;
+ return false;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ throw new IllegalStateException("Got an empty response");
+ }
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 7fcf900..a481036 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -373,10 +373,15 @@
boolean mLayoutNeeded = true;
boolean mAnimationPending = false;
boolean mDisplayFrozen = false;
+ boolean mWaitingForConfig = false;
boolean mWindowsFreezingScreen = false;
long mFreezeGcPending = 0;
int mAppsFreezingScreen = 0;
+ int mLayoutSeq = 0;
+
+ Configuration mCurConfiguration = new Configuration();
+
// This is held as long as we have the screen frozen, to give us time to
// perform a rotation animation when turning off shows the lock screen which
// changes the orientation.
@@ -1828,7 +1833,7 @@
}
if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
- attachedWindow = windowForClientLocked(null, attrs.token);
+ attachedWindow = windowForClientLocked(null, attrs.token, false);
if (attachedWindow == null) {
Log.w(TAG, "Attempted to add window with token that is not a window: "
+ attrs.token + ". Aborting.");
@@ -1988,6 +1993,10 @@
if (localLOGV) Log.v(
TAG, "New client " + client.asBinder()
+ ": window=" + win);
+
+ if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked()) {
+ reportNewConfig = true;
+ }
}
// sendNewConfiguration() checks caller permissions so we must call it with
@@ -1997,14 +2006,6 @@
final long origId = Binder.clearCallingIdentity();
if (reportNewConfig) {
sendNewConfiguration();
- } else {
- // Update Orientation after adding a window, only if the window needs to be
- // displayed right away
- if (win.isVisibleOrAdding()) {
- if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
- sendNewConfiguration();
- }
- }
}
Binder.restoreCallingIdentity(origId);
@@ -2013,7 +2014,7 @@
public void removeWindow(Session session, IWindow client) {
synchronized(mWindowMap) {
- WindowState win = windowForClientLocked(session, client);
+ WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
return;
}
@@ -2081,8 +2082,9 @@
// Removing a visible window will effect the computed orientation
// So just update orientation if needed.
if (wasVisible && computeForcedAppOrientationLocked()
- != mForcedAppOrientation) {
- mH.sendMessage(mH.obtainMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION));
+ != mForcedAppOrientation
+ && updateOrientationFromAppTokensLocked()) {
+ mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
}
updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
Binder.restoreCallingIdentity(origId);
@@ -2177,7 +2179,7 @@
long origId = Binder.clearCallingIdentity();
try {
synchronized (mWindowMap) {
- WindowState w = windowForClientLocked(session, client);
+ WindowState w = windowForClientLocked(session, client, false);
if ((w != null) && (w.mSurface != null)) {
if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION");
Surface.openTransaction();
@@ -2203,7 +2205,7 @@
long origId = Binder.clearCallingIdentity();
try {
synchronized (mWindowMap) {
- WindowState w = windowForClientLocked(session, client);
+ WindowState w = windowForClientLocked(session, client, false);
if (w != null) {
w.mGivenInsetsPending = false;
w.mGivenContentInsets.set(contentInsets);
@@ -2221,7 +2223,7 @@
public void getWindowDisplayFrame(Session session, IWindow client,
Rect outDisplayFrame) {
synchronized(mWindowMap) {
- WindowState win = windowForClientLocked(session, client);
+ WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
outDisplayFrame.setEmpty();
return;
@@ -2291,11 +2293,11 @@
Surface outSurface) {
boolean displayed = false;
boolean inTouchMode;
- Configuration newConfig = null;
+ boolean configChanged;
long origId = Binder.clearCallingIdentity();
synchronized(mWindowMap) {
- WindowState win = windowForClientLocked(session, client);
+ WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
return 0;
}
@@ -2507,7 +2509,7 @@
if (assignLayers) {
assignLayersLocked();
}
- newConfig = updateOrientationFromAppTokensLocked(null, null);
+ configChanged = updateOrientationFromAppTokensLocked();
performLayoutAndPlaceSurfacesLocked();
if (displayed && win.mIsWallpaper) {
updateWallpaperOffsetLocked(win, mDisplay.getWidth(),
@@ -2533,7 +2535,7 @@
inTouchMode = mInTouchMode;
}
- if (newConfig != null) {
+ if (configChanged) {
sendNewConfiguration();
}
@@ -2546,7 +2548,7 @@
public void finishDrawingWindow(Session session, IWindow client) {
final long origId = Binder.clearCallingIdentity();
synchronized(mWindowMap) {
- WindowState win = windowForClientLocked(session, client);
+ WindowState win = windowForClientLocked(session, client, false);
if (win != null && win.finishDrawingLocked()) {
if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
adjustWallpaperWindowsLocked();
@@ -2988,62 +2990,62 @@
}
public int getOrientationFromAppTokensLocked() {
- int pos = mAppTokens.size() - 1;
- int curGroup = 0;
- int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
- boolean findingBehind = false;
- boolean haveGroup = false;
- boolean lastFullscreen = false;
- while (pos >= 0) {
- AppWindowToken wtoken = mAppTokens.get(pos);
- pos--;
- // if we're about to tear down this window and not seek for
- // the behind activity, don't use it for orientation
- if (!findingBehind
- && (!wtoken.hidden && wtoken.hiddenRequested)) {
+ int pos = mAppTokens.size() - 1;
+ int curGroup = 0;
+ int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ boolean findingBehind = false;
+ boolean haveGroup = false;
+ boolean lastFullscreen = false;
+ while (pos >= 0) {
+ AppWindowToken wtoken = mAppTokens.get(pos);
+ pos--;
+ // if we're about to tear down this window and not seek for
+ // the behind activity, don't use it for orientation
+ if (!findingBehind
+ && (!wtoken.hidden && wtoken.hiddenRequested)) {
+ continue;
+ }
+
+ if (!haveGroup) {
+ // We ignore any hidden applications on the top.
+ if (wtoken.hiddenRequested || wtoken.willBeHidden) {
continue;
}
-
- if (!haveGroup) {
- // We ignore any hidden applications on the top.
- if (wtoken.hiddenRequested || wtoken.willBeHidden) {
- continue;
- }
- haveGroup = true;
- curGroup = wtoken.groupId;
- lastOrientation = wtoken.requestedOrientation;
- } else if (curGroup != wtoken.groupId) {
- // If we have hit a new application group, and the bottom
- // of the previous group didn't explicitly say to use
- // the orientation behind it, and the last app was
- // full screen, then we'll stick with the
- // user's orientation.
- if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
- && lastFullscreen) {
- return lastOrientation;
- }
+ haveGroup = true;
+ curGroup = wtoken.groupId;
+ lastOrientation = wtoken.requestedOrientation;
+ } else if (curGroup != wtoken.groupId) {
+ // If we have hit a new application group, and the bottom
+ // of the previous group didn't explicitly say to use
+ // the orientation behind it, and the last app was
+ // full screen, then we'll stick with the
+ // user's orientation.
+ if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
+ && lastFullscreen) {
+ return lastOrientation;
}
- int or = wtoken.requestedOrientation;
- // If this application is fullscreen, and didn't explicitly say
- // to use the orientation behind it, then just take whatever
- // orientation it has and ignores whatever is under it.
- lastFullscreen = wtoken.appFullscreen;
- if (lastFullscreen
- && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
- return or;
- }
- // If this application has requested an explicit orientation,
- // then use it.
- if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
- or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ||
- or == ActivityInfo.SCREEN_ORIENTATION_SENSOR ||
- or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR ||
- or == ActivityInfo.SCREEN_ORIENTATION_USER) {
- return or;
- }
- findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
}
- return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ int or = wtoken.requestedOrientation;
+ // If this application is fullscreen, and didn't explicitly say
+ // to use the orientation behind it, then just take whatever
+ // orientation it has and ignores whatever is under it.
+ lastFullscreen = wtoken.appFullscreen;
+ if (lastFullscreen
+ && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+ return or;
+ }
+ // If this application has requested an explicit orientation,
+ // then use it.
+ if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
+ or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ||
+ or == ActivityInfo.SCREEN_ORIENTATION_SENSOR ||
+ or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR ||
+ or == ActivityInfo.SCREEN_ORIENTATION_USER) {
+ return or;
+ }
+ findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
+ }
+ return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
public Configuration updateOrientationFromAppTokens(
@@ -3053,81 +3055,75 @@
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
- Configuration config;
+ Configuration config = null;
long ident = Binder.clearCallingIdentity();
- config = updateOrientationFromAppTokensUnchecked(currentConfig,
- freezeThisOneIfNeeded);
+
+ synchronized(mWindowMap) {
+ if (updateOrientationFromAppTokensLocked()) {
+ if (freezeThisOneIfNeeded != null) {
+ AppWindowToken wtoken = findAppWindowToken(
+ freezeThisOneIfNeeded);
+ if (wtoken != null) {
+ startAppFreezingScreenLocked(wtoken,
+ ActivityInfo.CONFIG_ORIENTATION);
+ }
+ }
+ config = computeNewConfigurationLocked();
+
+ } else if (currentConfig != null) {
+ // No obvious action we need to take, but if our current
+ // state mismatches the activity maanager's, update it
+ mTempConfiguration.setToDefaults();
+ if (computeNewConfigurationLocked(mTempConfiguration)) {
+ if (currentConfig.diff(mTempConfiguration) != 0) {
+ mWaitingForConfig = true;
+ mLayoutNeeded = true;
+ startFreezingDisplayLocked();
+ config = new Configuration(mTempConfiguration);
+ }
+ }
+ }
+ }
+
Binder.restoreCallingIdentity(ident);
return config;
}
- Configuration updateOrientationFromAppTokensUnchecked(
- Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
- Configuration config;
- synchronized(mWindowMap) {
- config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded);
- if (config != null) {
- mLayoutNeeded = true;
- performLayoutAndPlaceSurfacesLocked();
- }
- }
- return config;
- }
-
/*
+ * Determine the new desired orientation of the display, returning
+ * a non-null new Configuration if it has changed from the current
+ * orientation. IF TRUE IS RETURNED SOMEONE MUST CALL
+ * setNewConfiguration() TO TELL THE WINDOW MANAGER IT CAN UNFREEZE THE
+ * SCREEN. This will typically be done for you if you call
+ * sendNewConfiguration().
+ *
* The orientation is computed from non-application windows first. If none of
* the non-application windows specify orientation, the orientation is computed from
* application tokens.
* @see android.view.IWindowManager#updateOrientationFromAppTokens(
* android.os.IBinder)
*/
- Configuration updateOrientationFromAppTokensLocked(
- Configuration appConfig, IBinder freezeThisOneIfNeeded) {
+ boolean updateOrientationFromAppTokensLocked() {
boolean changed = false;
long ident = Binder.clearCallingIdentity();
try {
int req = computeForcedAppOrientationLocked();
if (req != mForcedAppOrientation) {
- changed = true;
mForcedAppOrientation = req;
//send a message to Policy indicating orientation change to take
//action like disabling/enabling sensors etc.,
mPolicy.setCurrentOrientationLw(req);
- }
-
- if (changed) {
- changed = setRotationUncheckedLocked(
- WindowManagerPolicy.USE_LAST_ROTATION,
- mLastRotationFlags & (~Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE));
- if (changed) {
- if (freezeThisOneIfNeeded != null) {
- AppWindowToken wtoken = findAppWindowToken(
- freezeThisOneIfNeeded);
- if (wtoken != null) {
- startAppFreezingScreenLocked(wtoken,
- ActivityInfo.CONFIG_ORIENTATION);
- }
- }
- return computeNewConfigurationLocked();
+ if (setRotationUncheckedLocked(WindowManagerPolicy.USE_LAST_ROTATION,
+ mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE)) {
+ changed = true;
}
}
- // No obvious action we need to take, but if our current
- // state mismatches the activity maanager's, update it
- if (appConfig != null) {
- mTempConfiguration.setToDefaults();
- if (computeNewConfigurationLocked(mTempConfiguration)) {
- if (appConfig.diff(mTempConfiguration) != 0) {
- return new Configuration(mTempConfiguration);
- }
- }
- }
+ return changed;
} finally {
Binder.restoreCallingIdentity(ident);
}
-
- return null;
}
int computeForcedAppOrientationLocked() {
@@ -3138,6 +3134,19 @@
return req;
}
+ public void setNewConfiguration(Configuration config) {
+ if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
+ "setNewConfiguration()")) {
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
+ }
+
+ synchronized(mWindowMap) {
+ mCurConfiguration = new Configuration(config);
+ mWaitingForConfig = false;
+ performLayoutAndPlaceSurfacesLocked();
+ }
+ }
+
public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppOrientation()")) {
@@ -3648,9 +3657,7 @@
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
}
- if (mAppsFreezingScreen == 0 && !mWindowsFreezingScreen) {
- stopFreezingDisplayLocked();
- }
+ stopFreezingDisplayLocked();
}
}
}
@@ -4403,20 +4410,21 @@
changed = setRotationUncheckedLocked(rotation, animFlags);
}
- if (changed) {
- sendNewConfiguration();
- synchronized(mWindowMap) {
- mLayoutNeeded = true;
- performLayoutAndPlaceSurfacesLocked();
- }
- } else if (alwaysSendConfiguration) {
- //update configuration ignoring orientation change
+ if (changed || alwaysSendConfiguration) {
sendNewConfiguration();
}
Binder.restoreCallingIdentity(origId);
}
+ /**
+ * Apply a new rotation to the screen, respecting the requests of
+ * applications. Use WindowManagerPolicy.USE_LAST_ROTATION to simply
+ * re-evaluate the desired rotation.
+ *
+ * Returns null if the rotation has been changed. In this case YOU
+ * MUST CALL setNewConfiguration() TO UNFREEZE THE SCREEN.
+ */
public boolean setRotationUncheckedLocked(int rotation, int animFlags) {
boolean changed;
if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) {
@@ -4442,6 +4450,8 @@
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
2000);
+ mWaitingForConfig = true;
+ mLayoutNeeded = true;
startFreezingDisplayLocked();
Log.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
mQueue.setOrientation(rotation);
@@ -6707,7 +6717,8 @@
long ident = Binder.clearCallingIdentity();
try {
return mPolicy.performHapticFeedbackLw(
- windowForClientLocked(this, window), effectId, always);
+ windowForClientLocked(this, window, true),
+ effectId, always);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -6718,7 +6729,8 @@
synchronized(mWindowMap) {
long ident = Binder.clearCallingIdentity();
try {
- setWindowWallpaperPositionLocked(windowForClientLocked(this, window),
+ setWindowWallpaperPositionLocked(
+ windowForClientLocked(this, window, true),
x, y, xStep, yStep);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -6736,7 +6748,7 @@
long ident = Binder.clearCallingIdentity();
try {
return sendWindowWallpaperCommandLocked(
- windowForClientLocked(this, window),
+ windowForClientLocked(this, window, true),
action, x, y, z, extras, sync);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -6852,6 +6864,10 @@
WindowState mNextOutsideTouch;
+ int mLayoutSeq = -1;
+
+ Configuration mConfiguration = null;
+
// Actual frame shown on-screen (may be modified by animation)
final Rect mShownFrame = new Rect();
final Rect mLastShownFrame = new Rect();
@@ -7980,7 +7996,7 @@
public void binderDied() {
try {
synchronized(mWindowMap) {
- WindowState win = windowForClientLocked(mSession, mClient);
+ WindowState win = windowForClientLocked(mSession, mClient, false);
Log.i(TAG, "WIN DEATH: " + win);
if (win != null) {
removeWindowLocked(mSession, win);
@@ -8056,8 +8072,6 @@
}
void dump(PrintWriter pw, String prefix) {
- StringBuilder sb = new StringBuilder(64);
-
pw.print(prefix); pw.print("mSession="); pw.print(mSession);
pw.print(" mClient="); pw.println(mClient.asBinder());
pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs);
@@ -8105,7 +8119,8 @@
pw.print(prefix); pw.print("mRelayoutCalled="); pw.println(mRelayoutCalled);
}
pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
- pw.print(" h="); pw.println(mRequestedHeight);
+ pw.print(" h="); pw.print(mRequestedHeight);
+ pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
if (mXOffset != 0 || mYOffset != 0) {
pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
pw.print(" y="); pw.println(mYOffset);
@@ -8119,6 +8134,7 @@
pw.print(prefix); pw.print("mTouchableInsets="); pw.print(mTouchableInsets);
pw.print(" mGivenInsetsPending="); pw.println(mGivenInsetsPending);
}
+ pw.print(prefix); pw.print("mConfiguration="); pw.println(mConfiguration);
pw.print(prefix); pw.print("mShownFrame=");
mShownFrame.printShortString(pw);
pw.print(" last="); mLastShownFrame.printShortString(pw);
@@ -8693,7 +8709,7 @@
public static final int FORCE_GC = 15;
public static final int ENABLE_SCREEN = 16;
public static final int APP_FREEZE_TIMEOUT = 17;
- public static final int COMPUTE_AND_SEND_NEW_CONFIGURATION = 18;
+ public static final int SEND_NEW_CONFIGURATION = 18;
private Session mLastReportedHold;
@@ -9019,10 +9035,9 @@
break;
}
- case COMPUTE_AND_SEND_NEW_CONFIGURATION: {
- if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
- sendNewConfiguration();
- }
+ case SEND_NEW_CONFIGURATION: {
+ removeMessages(SEND_NEW_CONFIGURATION);
+ sendNewConfiguration();
break;
}
@@ -9064,23 +9079,33 @@
// Internals
// -------------------------------------------------------------
- final WindowState windowForClientLocked(Session session, IWindow client) {
- return windowForClientLocked(session, client.asBinder());
+ final WindowState windowForClientLocked(Session session, IWindow client,
+ boolean throwOnError) {
+ return windowForClientLocked(session, client.asBinder(), throwOnError);
}
- final WindowState windowForClientLocked(Session session, IBinder client) {
+ final WindowState windowForClientLocked(Session session, IBinder client,
+ boolean throwOnError) {
WindowState win = mWindowMap.get(client);
if (localLOGV) Log.v(
TAG, "Looking up client " + client + ": " + win);
if (win == null) {
- RuntimeException ex = new RuntimeException();
- Log.w(TAG, "Requested window " + client + " does not exist", ex);
+ RuntimeException ex = new IllegalArgumentException(
+ "Requested window " + client + " does not exist");
+ if (throwOnError) {
+ throw ex;
+ }
+ Log.w(TAG, "Failed looking up window", ex);
return null;
}
if (session != null && win.mSession != session) {
- RuntimeException ex = new RuntimeException();
- Log.w(TAG, "Requested window " + client + " is in session " +
- win.mSession + ", not " + session, ex);
+ RuntimeException ex = new IllegalArgumentException(
+ "Requested window " + client + " is in session " +
+ win.mSession + ", not " + session);
+ if (throwOnError) {
+ throw ex;
+ }
+ Log.w(TAG, "Failed looking up window", ex);
return null;
}
@@ -9183,6 +9208,13 @@
return;
}
+ if (mWaitingForConfig) {
+ // Our configuration has changed (most likely rotation), but we
+ // don't yet have the complete configuration to report to
+ // applications. Don't do any window layout until we have it.
+ return;
+ }
+
boolean recoveringMemory = false;
if (mForceRemoves != null) {
recoveringMemory = true;
@@ -9249,6 +9281,10 @@
while (mLayoutNeeded) {
mPolicy.beginLayoutLw(dw, dh);
+ int seq = mLayoutSeq+1;
+ if (seq < 0) seq = 0;
+ mLayoutSeq = seq;
+
// First perform layout of any root windows (not attached
// to another window).
int topAttached = -1;
@@ -9266,7 +9302,7 @@
|| win.mAttachedHidden
|| win.mExiting || win.mDestroying;
- if (win.mLayoutAttached) {
+ if (!win.mLayoutAttached) {
if (DEBUG_LAYOUT) Log.v(TAG, "First pass " + win
+ ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
+ " mLayoutAttached=" + win.mLayoutAttached);
@@ -9286,6 +9322,7 @@
if (!gone || !win.mHaveFrame) {
if (!win.mLayoutAttached) {
mPolicy.layoutWindowLw(win, win.mAttrs, null);
+ win.mLayoutSeq = seq;
if (DEBUG_LAYOUT) Log.v(TAG, "-> mFrame="
+ win.mFrame + " mContainingFrame="
+ win.mContainingFrame + " mDisplayFrame="
@@ -9316,6 +9353,7 @@
if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
|| !win.mHaveFrame) {
mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
+ win.mLayoutSeq = seq;
if (DEBUG_LAYOUT) Log.v(TAG, "-> mFrame="
+ win.mFrame + " mContainingFrame="
+ win.mContainingFrame + " mDisplayFrame="
@@ -9336,11 +9374,8 @@
Log.w(TAG, "Layout repeat aborted after too many iterations");
mLayoutNeeded = false;
if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
- Configuration newConfig = updateOrientationFromAppTokensLocked(
- null, null);
- if (newConfig != null) {
- mLayoutNeeded = true;
- mH.sendEmptyMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION);
+ if (updateOrientationFromAppTokensLocked()) {
+ mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
}
}
} else {
@@ -9349,10 +9384,8 @@
repeats++;
if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
if (DEBUG_LAYOUT) Log.v(TAG, "Computing new config from layout");
- Configuration newConfig = updateOrientationFromAppTokensLocked(
- null, null);
- if (newConfig != null) {
- mH.sendEmptyMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION);
+ if (updateOrientationFromAppTokensLocked()) {
+ mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
}
}
}
@@ -9996,14 +10029,22 @@
}
}
}
- if (!w.mAppFreezing) {
+ if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
w.mContentInsetsChanged =
!w.mLastContentInsets.equals(w.mContentInsets);
w.mVisibleInsetsChanged =
!w.mLastVisibleInsets.equals(w.mVisibleInsets);
+ boolean configChanged =
+ w.mConfiguration != mCurConfiguration
+ && (w.mConfiguration == null
+ || mCurConfiguration.diff(w.mConfiguration) != 0);
+ if (localLOGV) Log.v(TAG, "Resizing " + w
+ + ": configChanged=" + configChanged
+ + " last=" + w.mLastFrame + " frame=" + w.mFrame);
if (!w.mLastFrame.equals(w.mFrame)
|| w.mContentInsetsChanged
- || w.mVisibleInsetsChanged) {
+ || w.mVisibleInsetsChanged
+ || configChanged) {
w.mLastFrame.set(w.mFrame);
w.mLastContentInsets.set(w.mContentInsets);
w.mLastVisibleInsets.set(w.mVisibleInsets);
@@ -10014,7 +10055,7 @@
if (DEBUG_ORIENTATION) Log.v(TAG,
"Resizing while display frozen: " + w);
w.mOrientationChanging = true;
- if (mWindowsFreezingScreen) {
+ if (!mWindowsFreezingScreen) {
mWindowsFreezingScreen = true;
// XXX should probably keep timeout from
// when we first froze the display.
@@ -10327,9 +10368,7 @@
mWindowsFreezingScreen = false;
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
}
- if (mAppsFreezingScreen == 0) {
- stopFreezingDisplayLocked();
- }
+ stopFreezingDisplayLocked();
}
i = mResizingWindows.size();
@@ -10340,9 +10379,20 @@
try {
if (DEBUG_ORIENTATION) Log.v(TAG, "Reporting new frame to "
+ win + ": " + win.mFrame);
+ boolean configChanged =
+ win.mConfiguration != mCurConfiguration
+ && (win.mConfiguration == null
+ || mCurConfiguration.diff(win.mConfiguration) != 0);
+ win.mConfiguration = mCurConfiguration;
+ if (DEBUG_ORIENTATION && configChanged) {
+ Log.i(TAG, "Sending new config to window " + win + ": "
+ + win.mFrame.width() + "x" + win.mFrame.height()
+ + " / " + win.mConfiguration);
+ }
win.mClient.resized(win.mFrame.width(),
win.mFrame.height(), win.mLastContentInsets,
- win.mLastVisibleInsets, win.mDrawPending);
+ win.mLastVisibleInsets, win.mDrawPending,
+ configChanged ? win.mConfiguration : null);
win.mContentInsetsChanged = false;
win.mVisibleInsetsChanged = false;
} catch (RemoteException e) {
@@ -10732,6 +10782,10 @@
return;
}
+ if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) {
+ return;
+ }
+
mDisplayFrozen = false;
mH.removeMessages(H.APP_FREEZE_TIMEOUT);
if (PROFILE_ORIENTATION) {
@@ -10921,7 +10975,9 @@
pw.print(" mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
pw.print(" mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
}
- pw.print(" mInTouchMode="); pw.println(mInTouchMode);
+ pw.print(" mCurConfiguration="); pw.println(this.mCurConfiguration);
+ pw.print(" mInTouchMode="); pw.print(mInTouchMode);
+ pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
pw.print(" mSystemBooted="); pw.print(mSystemBooted);
pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded);
@@ -10939,7 +10995,8 @@
pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen);
pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
- pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen);
+ pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
+ pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
pw.print(" mRotation="); pw.print(mRotation);
pw.print(", mForcedAppOrientation="); pw.print(mForcedAppOrientation);
pw.print(", mRequestedRotation="); pw.println(mRequestedRotation);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 47a58cf..45c3f00 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -766,6 +766,12 @@
Configuration mConfiguration = new Configuration();
/**
+ * Current sequencing integer of the configuration, for skipping old
+ * configurations.
+ */
+ int mConfigurationSeq = 0;
+
+ /**
* Hardware-reported OpenGLES version.
*/
final int GL_ES_VERSION;
@@ -2662,20 +2668,6 @@
mConfiguration,
next.mayFreezeScreenLocked(next.app) ? next : null);
if (config != null) {
- /*
- * Explicitly restore the locale to the one from the
- * old configuration, since the one that comes back from
- * the window manager has the default (boot) locale.
- *
- * It looks like previously the locale picker only worked
- * by coincidence: usually it would do its setting of
- * the locale after the activity transition, so it didn't
- * matter that this lost it. With the synchronized
- * block now keeping them from happening at the same time,
- * this one always would happen second and undo what the
- * locale picker had just done.
- */
- config.locale = mConfiguration.locale;
next.frozenBeforeDestroy = true;
}
updated = updateConfigurationLocked(config, next);
@@ -8347,7 +8339,9 @@
mAlwaysFinishActivities = alwaysFinishActivities;
// This happens before any activities are started, so we can
// change mConfiguration in-place.
+ mConfiguration.locale = Locale.getDefault();
mConfiguration.updateFrom(configuration);
+ mConfigurationSeq = mConfiguration.seq = 1;
if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
}
}
@@ -13090,6 +13084,11 @@
values.userSetLocale);
}
+ mConfigurationSeq++;
+ if (mConfigurationSeq <= 0) {
+ mConfigurationSeq = 1;
+ }
+ newConfig.seq = mConfigurationSeq;
mConfiguration = newConfig;
Log.i(TAG, "Config changed: " + newConfig);
@@ -13146,6 +13145,10 @@
}
}
+ if (values != null && mWindowManager != null) {
+ mWindowManager.setNewConfiguration(mConfiguration);
+ }
+
return kept;
}
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 89761a8..2f2cc32 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -29,6 +29,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.util.Log;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -267,6 +268,9 @@
int[] outId = new int[1];
inm.enqueueNotification(localPackageName, localForegroundId,
localForegroundNoti, outId);
+ } catch (RuntimeException e) {
+ Log.w(ActivityManagerService.TAG, "Error showing notification for service",
+ e);
} catch (RemoteException e) {
}
}
@@ -288,6 +292,9 @@
}
try {
inm.cancelNotification(localPackageName, localForegroundId);
+ } catch (RuntimeException e) {
+ Log.w(ActivityManagerService.TAG, "Error canceling notification for"
+ + " service", e);
} catch (RemoteException e) {
}
}
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index c7c3335..dab8b72 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -972,7 +972,7 @@
return;
}
- prepareTracking(0);
+ prepareTracking(0, true);
performFling(0, 2000.0f, true);
}
@@ -980,7 +980,9 @@
if (SPEW) {
Log.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
+ " mExpandedVisible=" + mExpandedVisible
+ + " mExpanded=" + mExpanded
+ " mAnimating=" + mAnimating
+ + " mAnimY=" + mAnimY
+ " mAnimVel=" + mAnimVel);
}
@@ -988,12 +990,16 @@
return;
}
+ int y;
if (mAnimating) {
- return;
+ y = (int)mAnimY;
+ } else {
+ y = mDisplay.getHeight()-1;
}
-
- int y = mDisplay.getHeight()-1;
- prepareTracking(y);
+ // Let the fling think that we're open so it goes in the right direction
+ // and doesn't try to re-open the windowshade.
+ mExpanded = true;
+ prepareTracking(y, false);
performFling(y, -2000.0f, true);
}
@@ -1108,10 +1114,9 @@
}
}
- void prepareTracking(int y) {
+ void prepareTracking(int y, boolean opening) {
mTracking = true;
mVelocityTracker = VelocityTracker.obtain();
- boolean opening = !mExpanded;
if (opening) {
mAnimAccel = 2000.0f;
mAnimVel = 200;
@@ -1199,10 +1204,11 @@
}
boolean interceptTouchEvent(MotionEvent event) {
- if (SPEW) Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event);
+ if (SPEW) Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
+ + mDisabled);
if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
- return true;
+ return false;
}
final int statusBarSize = mStatusBarView.getHeight();
@@ -1218,7 +1224,7 @@
}
if ((!mExpanded && y < hitSize) ||
(mExpanded && y > (mDisplay.getHeight()-hitSize))) {
- prepareTracking(y);
+ prepareTracking(y, !mExpanded); // opening if we're not already fully visible
mVelocityTracker.addMovement(event);
}
} else if (mTracking) {
@@ -1679,9 +1685,7 @@
if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
Log.d(TAG, "DISABLE_EXPAND: yes");
- mAnimating = false;
- updateExpandedViewPos(0);
- performCollapse();
+ animateCollapse();
}
}
if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
diff --git a/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java b/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
index 7569d7a..3bbb447 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
@@ -73,11 +73,65 @@
for (int i = 0; i < containers.length; i++) {
if (containers[i].startsWith("com.android.unittests.AsecTests.")) {
- ms.destroySecureContainer(containers[i]);
+ ms.destroySecureContainer(containers[i], true);
}
}
}
+ private boolean containerExists(String localId) throws RemoteException {
+ IMountService ms = getMs();
+ String[] containers = ms.getSecureContainerList();
+ String fullId = "com.android.unittests.AsecTests." + localId;
+
+ for (int i = 0; i < containers.length; i++) {
+ if (containers[i].equals(fullId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private int createContainer(String localId, int size, String key) throws RemoteException {
+ Assert.assertTrue(isMediaMounted());
+ String fullId = "com.android.unittests.AsecTests." + localId;
+
+ IMountService ms = getMs();
+ return ms.createSecureContainer(fullId, size, "fat", key, android.os.Process.myUid());
+ }
+
+ private int mountContainer(String localId, String key) throws RemoteException {
+ Assert.assertTrue(isMediaMounted());
+ String fullId = "com.android.unittests.AsecTests." + localId;
+
+ IMountService ms = getMs();
+ return ms.mountSecureContainer(fullId, key, android.os.Process.myUid());
+ }
+
+ private int renameContainer(String localId1, String localId2) throws RemoteException {
+ Assert.assertTrue(isMediaMounted());
+ String fullId1 = "com.android.unittests.AsecTests." + localId1;
+ String fullId2 = "com.android.unittests.AsecTests." + localId2;
+
+ IMountService ms = getMs();
+ return ms.renameSecureContainer(fullId1, fullId2);
+ }
+
+ private int unmountContainer(String localId, boolean force) throws RemoteException {
+ Assert.assertTrue(isMediaMounted());
+ String fullId = "com.android.unittests.AsecTests." + localId;
+
+ IMountService ms = getMs();
+ return ms.unmountSecureContainer(fullId, force);
+ }
+
+ private int destroyContainer(String localId, boolean force) throws RemoteException {
+ Assert.assertTrue(isMediaMounted());
+ String fullId = "com.android.unittests.AsecTests." + localId;
+
+ IMountService ms = getMs();
+ return ms.destroySecureContainer(fullId, force);
+ }
+
private IMountService getMs() {
IBinder service = ServiceManager.getService("mount");
if (service != null) {
@@ -100,67 +154,174 @@
}
public void testCreateContainer() {
- Assert.assertTrue(isMediaMounted());
- IMountService ms = getMs();
try {
- int rc = ms.createSecureContainer("com.android.unittests.AsecTests.testCreateContainer", 4, "fat", "none", 1000);
- Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ createContainer("testCreateContainer", 4, "none"));
+ Assert.assertEquals(true, containerExists("testCreateContainer"));
+ } catch (Exception e) {
+ failStr(e);
+ }
+ }
+
+ public void testCreateMinSizeContainer() {
+ try {
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ createContainer("testCreateContainer", 1, "none"));
+ Assert.assertEquals(true, containerExists("testCreateContainer"));
+ } catch (Exception e) {
+ failStr(e);
+ }
+ }
+
+ public void testCreateZeroSizeContainer() {
+ try {
+ Assert.assertEquals(StorageResultCode.OperationFailedInternalError,
+ createContainer("testCreateZeroContainer", 0, "none"));
+ } catch (Exception e) {
+ failStr(e);
+ }
+ }
+
+ public void testCreateDuplicateContainer() {
+ try {
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ createContainer("testCreateDupContainer", 4, "none"));
+
+ Assert.assertEquals(StorageResultCode.OperationFailedInternalError,
+ createContainer("testCreateDupContainer", 4, "none"));
} catch (Exception e) {
failStr(e);
}
}
public void testDestroyContainer() {
- Assert.assertTrue(isMediaMounted());
- IMountService ms = getMs();
try {
- int rc = ms.createSecureContainer("com.android.unittests.AsecTests.testDestroyContainer", 4, "fat", "none", 1000);
- Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
- rc = ms.destroySecureContainer("com.android.unittests.AsecTests.testDestroyContainer");
- Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ createContainer("testDestroyContainer", 4, "none"));
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ destroyContainer("testDestroyContainer", false));
} catch (Exception e) {
failStr(e);
}
}
public void testMountContainer() {
- Assert.assertTrue(isMediaMounted());
- IMountService ms = getMs();
try {
- int rc = ms.createSecureContainer(
- "com.android.unittests.AsecTests.testMountContainer", 4, "fat", "none", 1000);
- Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ createContainer("testMountContainer", 4, "none"));
- rc = ms.unmountSecureContainer("com.android.unittests.AsecTests.testMountContainer");
- Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ unmountContainer("testMountContainer", false));
- rc = ms.mountSecureContainer("com.android.unittests.AsecTests.testMountContainer", "none", 1000);
- Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ mountContainer("testMountContainer", "none"));
} catch (Exception e) {
failStr(e);
}
}
public void testMountBadKey() {
- Assert.assertTrue(isMediaMounted());
+ try {
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ createContainer("testMountBadKey", 4, "00000000000000000000000000000000"));
+
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ unmountContainer("testMountBadKey", false));
+
+ Assert.assertEquals(StorageResultCode.OperationFailedInternalError,
+ mountContainer("testMountContainer", "000000000000000000000000000000001"));
+
+ Assert.assertEquals(StorageResultCode.OperationFailedInternalError,
+ mountContainer("testMountContainer", "none"));
+ } catch (Exception e) {
+ failStr(e);
+ }
+ }
+
+ public void testUnmountBusyContainer() {
IMountService ms = getMs();
try {
- int rc = ms.createSecureContainer(
- "com.android.unittests.AsecTests.testMountBadKey", 4, "fat",
- "00000000000000000000000000000000", 1000);
- Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ createContainer("testUnmountBusyContainer", 4, "none"));
- rc = ms.unmountSecureContainer("com.android.unittests.AsecTests.testMountBadKey");
- Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+ String path = ms.getSecureContainerPath("com.android.unittests.AsecTests.testUnmountBusyContainer");
- rc = ms.mountSecureContainer(
- "com.android.unittests.AsecTests.testMountBadKey",
- "00000000000000000000000000000001", 1001);
- Assert.assertEquals(StorageResultCode.OperationFailedInternalError, rc);
+ File f = new File(path, "reference");
+ FileOutputStream fos = new FileOutputStream(f);
- rc = ms.mountSecureContainer(
- "com.android.unittests.AsecTests.testMountBadKey", "none", 1001);
- Assert.assertEquals(StorageResultCode.OperationFailedInternalError, rc);
+ Assert.assertEquals(StorageResultCode.OperationFailedStorageBusy,
+ unmountContainer("testUnmountBusyContainer", false));
+
+ fos.close();
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ unmountContainer("testUnmountBusyContainer", false));
+ } catch (Exception e) {
+ failStr(e);
+ }
+ }
+
+ public void testDestroyBusyContainer() {
+ IMountService ms = getMs();
+ try {
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ createContainer("testDestroyBusyContainer", 4, "none"));
+
+ String path = ms.getSecureContainerPath("com.android.unittests.AsecTests.testDestroyBusyContainer");
+
+ File f = new File(path, "reference");
+ FileOutputStream fos = new FileOutputStream(f);
+
+ Assert.assertEquals(StorageResultCode.OperationFailedStorageBusy,
+ destroyContainer("testDestroyBusyContainer", false));
+
+ fos.close();
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ destroyContainer("testDestroyBusyContainer", false));
+ } catch (Exception e) {
+ failStr(e);
+ }
+ }
+
+ public void testRenameContainer() {
+ try {
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ createContainer("testRenameContainer.1", 4, "none"));
+
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ unmountContainer("testRenameContainer.1", false));
+
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ renameContainer("testRenameContainer.1", "testRenameContainer.2"));
+
+ Assert.assertEquals(false, containerExists("testRenameContainer.1"));
+ Assert.assertEquals(true, containerExists("testRenameContainer.2"));
+ } catch (Exception e) {
+ failStr(e);
+ }
+ }
+
+ public void testRenameMountedContainer() {
+ try {
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ createContainer("testRenameContainer.1", 4, "none"));
+
+ Assert.assertEquals(StorageResultCode.OperationFailedStorageMounted,
+ renameContainer("testRenameContainer.1", "testRenameContainer.2"));
+ } catch (Exception e) {
+ failStr(e);
+ }
+ }
+
+ public void testRenameToExistingContainer() {
+ try {
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ createContainer("testRenameContainer.1", 4, "none"));
+
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ createContainer("testRenameContainer.2", 4, "none"));
+
+ Assert.assertEquals(StorageResultCode.OperationFailedStorageMounted,
+ renameContainer("testRenameContainer.1", "testRenameContainer.2"));
} catch (Exception e) {
failStr(e);
}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index 8f4d0a1..be9571c 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -716,7 +716,7 @@
}
try {
String mPath = Environment.getExternalStorageDirectory().toString();
- int ret = getMs().unmountVolume(mPath);
+ int ret = getMs().unmountVolume(mPath, false);
return ret == StorageResultCode.OperationSucceeded;
} catch (RemoteException e) {
return true;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
index 50451e7..ce1bf8d 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
@@ -47,6 +47,7 @@
private static final int EVENT_RELEASE_TOUCH_POINT = 16;
private static final int EVENT_CLEAR_TOUCH_POINTS = 17;
private static final int EVENT_CANCEL_TOUCH_POINT = 18;
+ private static final int EVENT_SET_TOUCH_MODIFIER = 19;
private static final int LAYOUT_CLEAR_LIST = 20;
private static final int LAYOUT_DISPLAY = 21;
@@ -145,6 +146,13 @@
mEventSender.updateTouchPoint(id, x, y);
break;
+ case EVENT_SET_TOUCH_MODIFIER:
+ Bundle modifierArgs = (Bundle) msg.obj;
+ String modifier = modifierArgs.getString("modifier");
+ boolean enabled = modifierArgs.getBoolean("enabled");
+ mEventSender.setTouchModifier(modifier, enabled);
+ break;
+
case EVENT_RELEASE_TOUCH_POINT:
mEventSender.releaseTouchPoint(msg.arg1);
break;
@@ -320,7 +328,10 @@
}
public void setTouchModifier(String modifier, boolean enabled) {
- // TODO(benm): Android doesn't support key modifiers on touch events yet.
+ Bundle map = new Bundle();
+ map.putString("modifier", modifier);
+ map.putBoolean("enabled", enabled);
+ obtainMessage(EVENT_SET_TOUCH_MODIFIER, map).sendToTarget();
}
public void touchMove() {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 4d51356..14a6abf 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -51,24 +51,10 @@
}
- public static String isKnownBug(String file) {
- int index = file.indexOf("fast");
- if (index != -1) {
- String sub = file.substring(index);
- // Log.e("FileFilter", "Looking for:"+sub);
- if (bugList.containsKey(sub))
- return bugList.get(sub);
- }
- return null;
- }
-
final static HashSet<String> ignoreResultList = new HashSet<String>();
- final static Hashtable<String, String> bugList =
- new Hashtable<String, String>();
-
+
static {
fillIgnoreResultSet();
- fillBugTable();
}
static final String[] ignoreTestDirs = {
@@ -84,38 +70,35 @@
static final String [] ignoreTestList = {
"editing/selection/move-left-right.html",
- "fast/events/touch/basic-multi-touch-events.html", // We do not support multi touch events.
"fast/js/regexp-charclass-crash.html", // RegExp is too large, causing OOM
"fast/regex/test1.html", // RegExp is exponential
"fast/regex/slow.html", // RegExp is exponential
- "storage/domstorage/localstorage/iframe-events.html", // Expects test to be in LayoutTests
"storage/domstorage/localstorage/private-browsing-affects-storage.html", // No notion of private browsing.
- "storage/domstorage/sessionstorage/iframe-events.html", // Expects test to be in LayoutTests
"storage/domstorage/sessionstorage/private-browsing-affects-storage.html", // No notion of private browsing.
"storage/private-browsing-readonly.html", // No notion of private browsing.
};
static void fillIgnoreResultSet() {
ignoreResultList.add("fast/css/case-transform.html"); // will not fix #619707
- ignoreResultList.add("fast/css/computed-style.html"); // different platform defaults for font and different screen size
ignoreResultList.add("fast/dom/Element/offsetLeft-offsetTop-body-quirk.html"); // different screen size result in extra spaces in Apple compared to us
ignoreResultList.add("fast/dom/Window/Plug-ins.html"); // need test plugin
ignoreResultList.add("fast/dom/Window/window-properties.html"); // xslt and xpath elements missing from property list
ignoreResultList.add("fast/dom/Window/window-screen-properties.html"); // pixel depth
ignoreResultList.add("fast/dom/Window/window-xy-properties.html"); // requires eventSender.mouseDown(),mouseUp()
- ignoreResultList.add("fast/dom/character-index-for-point.html"); // requires textInputController.characterIndexForPoint
+ ignoreResultList.add("fast/dom/attribute-namespaces-get-set.html"); // http://b/733229
ignoreResultList.add("fast/dom/gc-9.html"); // requires xpath support
ignoreResultList.add("fast/dom/global-constructors.html"); // requires xslt and xpath support
ignoreResultList.add("fast/dom/object-embed-plugin-scripting.html"); // dynamic plugins not supported
ignoreResultList.add("fast/dom/tabindex-clamp.html"); // there is extra spacing in the file due to multiple input boxes fitting on one line on Apple, ours are wrapped. Space at line ends are stripped.
ignoreResultList.add("fast/events/anchor-image-scrolled-x-y.html"); // requires eventSender.mouseDown(),mouseUp()
+ ignoreResultList.add("fast/events/arrow-navigation.html"); // http://b/735233
ignoreResultList.add("fast/events/capture-on-target.html"); // requires eventSender.mouseDown(),mouseUp()
ignoreResultList.add("fast/events/dblclick-addEventListener.html"); // requires eventSender.mouseDown(),mouseUp()
ignoreResultList.add("fast/events/drag-in-frames.html"); // requires eventSender.mouseDown(),mouseUp()
ignoreResultList.add("fast/events/drag-outside-window.html"); // requires eventSender.mouseDown(),mouseUp()
- ignoreResultList.add("fast/events/event-sender-mouse-click.html"); // requires eventSender.mouseDown(),mouseUp()
ignoreResultList.add("fast/events/event-view-toString.html"); // requires eventSender.mouseDown(),mouseUp()
ignoreResultList.add("fast/events/frame-click-focus.html"); // requires eventSender.mouseDown(),mouseUp()
+ ignoreResultList.add("fast/events/frame-tab-focus.html"); // http://b/734308
ignoreResultList.add("fast/events/iframe-object-onload.html"); // there is extra spacing in the file due to multiple frame boxes fitting on one line on Apple, ours are wrapped. Space at line ends are stripped.
ignoreResultList.add("fast/events/input-image-scrolled-x-y.html"); // requires eventSender.mouseDown(),mouseUp()
ignoreResultList.add("fast/events/mouseclick-target-and-positioning.html"); // requires eventSender.mouseDown(),mouseUp()
@@ -123,70 +106,49 @@
ignoreResultList.add("fast/events/mouseover-mouseout2.html"); // requires eventSender.mouseDown(),mouseUp()
ignoreResultList.add("fast/events/mouseup-outside-button.html"); // requires eventSender.mouseDown(),mouseUp()
ignoreResultList.add("fast/events/mouseup-outside-document.html"); // requires eventSender.mouseDown(),mouseUp()
- ignoreResultList.add("fast/events/objc-event-api.html"); // eventSender.mouseDown(), mouseUp() and objc API missing
- ignoreResultList.add("fast/events/objc-keyboard-event-creation.html"); // eventSender.mouseDown(), mouseUp() and objc API missing
ignoreResultList.add("fast/events/onclick-list-marker.html"); // requires eventSender.mouseDown(),mouseUp()
ignoreResultList.add("fast/events/ondragenter.html"); // requires eventSender.mouseDown(),mouseUp()
ignoreResultList.add("fast/events/onload-webkit-before-webcore.html"); // missing space in textrun, ok as text is wrapped. ignore. #714933
+ ignoreResultList.add("fast/events/option-tab.html"); // http://b/734308
ignoreResultList.add("fast/events/window-events-bubble.html"); // requires eventSender.mouseDown(),mouseUp()
ignoreResultList.add("fast/events/window-events-bubble2.html"); // requires eventSender.mouseDown(),mouseUp()
ignoreResultList.add("fast/events/window-events-capture.html"); // requires eventSender.mouseDown(),mouseUp()
- ignoreResultList.add("fast/forms/attributed-strings.html"); // missing support for textInputController.makeAttributedString()
ignoreResultList.add("fast/forms/drag-into-textarea.html"); // requires eventSender.mouseDown(),mouseUp()
+ ignoreResultList.add("fast/forms/focus-control-to-page.html"); // http://b/716638
+ ignoreResultList.add("fast/forms/focus2.html"); // http://b/735111
ignoreResultList.add("fast/forms/form-data-encoding-2.html"); // charset convert. #516936 ignore, won't fix
ignoreResultList.add("fast/forms/form-data-encoding.html"); // charset convert. #516936 ignore, won't fix
ignoreResultList.add("fast/forms/input-appearance-maxlength.html"); // execCommand "insertText" not supported
ignoreResultList.add("fast/forms/input-select-on-click.html"); // requires eventSender.mouseDown(),mouseUp()
- ignoreResultList.add("fast/forms/input-truncate-newline.html"); // Copy&Paste commands not supported
ignoreResultList.add("fast/forms/listbox-onchange.html"); // requires eventSender.mouseDown(),mouseUp()
+ ignoreResultList.add("fast/forms/listbox-selection.html"); // http://b/735116
ignoreResultList.add("fast/forms/onselect-textarea.html"); // requires eventSender.mouseMoveTo, mouseDown & mouseUp and abs. position of mouse to select a word. ignore, won't fix #716583
ignoreResultList.add("fast/forms/onselect-textfield.html"); // requires eventSender.mouseMoveTo, mouseDown & mouseUp and abs. position of mouse to select a word. ignore, won't fix #716583
ignoreResultList.add("fast/forms/plaintext-mode-1.html"); // not implemented queryCommandEnabled:BackColor, Undo & Redo
ignoreResultList.add("fast/forms/search-cancel-button-mouseup.html"); // requires eventSender.mouseDown(),mouseUp()
+ ignoreResultList.add("fast/forms/search-event-delay.html"); // http://b/735120
ignoreResultList.add("fast/forms/select-empty-list.html"); // requires eventSender.mouseDown(),mouseUp()
+ ignoreResultList.add("fast/forms/select-type-ahead-non-latin.html"); // http://b/735244
ignoreResultList.add("fast/forms/selected-index-assert.html"); // not capturing the console messages
ignoreResultList.add("fast/forms/selection-functions.html"); // there is extra spacing as the text areas and input boxes fit next to each other on Apple, but are wrapped on our screen.
ignoreResultList.add("fast/forms/textarea-appearance-wrap.html"); // Our text areas are a little thinner than Apples. Also RTL test failes
- ignoreResultList.add("fast/forms/textarea-hard-linewrap.html"); // Our text areas are a little thinner than Apples
ignoreResultList.add("fast/forms/textarea-initial-caret-position.html"); // Text selection done differently on our platform. When a inputbox gets focus, the entire block is selected.
ignoreResultList.add("fast/forms/textarea-no-scroll-on-blur.html"); // Text selection done differently on our platform. When a inputbox gets focus, the entire block is selected.
ignoreResultList.add("fast/forms/textarea-paste-newline.html"); // Copy&Paste commands not supported
ignoreResultList.add("fast/forms/textarea-scrolled-endline-caret.html"); // requires eventSender.mouseDown(),mouseUp()
+ ignoreResultList.add("fast/frames/iframe-window-focus.html"); // http://b/735140
ignoreResultList.add("fast/frames/frameElement-widthheight.html"); // screen width&height are different
ignoreResultList.add("fast/frames/frame-js-url-clientWidth.html"); // screen width&height are different
+ ignoreResultList.add("fast/html/tab-order.html"); // http://b/719289
ignoreResultList.add("fast/js/navigator-mimeTypes-length.html"); // dynamic plugins not supported
+ ignoreResultList.add("fast/js/string-capitalization.html"); // http://b/516936
ignoreResultList.add("fast/loader/local-JavaScript-from-local.html"); // Requires LayoutTests to exist at /tmp/LayoutTests
ignoreResultList.add("fast/loader/local-iFrame-source-from-local.html"); // Requires LayoutTests to exist at /tmp/LayoutTests
ignoreResultList.add("fast/loader/opaque-base-url.html"); // extra spacing because iFrames rendered next to each other on Apple
+ ignoreResultList.add("fast/overflow/scroll-vertical-not-horizontal.html"); // http://b/735196
ignoreResultList.add("fast/parser/script-tag-with-trailing-slash.html"); // not capturing the console messages
ignoreResultList.add("fast/replaced/image-map.html"); // requires eventSender.mouseDown(),mouseUp()
- ignoreResultList.add("fast/text/attributed-substring-from-range.html"); // requires JS test API, textInputController
- ignoreResultList.add("fast/text/attributed-substring-from-range-001.html"); // requires JS test API, textInputController
ignoreResultList.add("fast/text/plain-text-line-breaks.html"); // extra spacing because iFrames rendered next to each other on Apple
}
- static void fillBugTable() {
- bugList.put("fast/forms/focus-control-to-page.html", "716638");
- bugList.put("fast/html/tab-order.html", "719289");
- bugList.put("fast/dom/attribute-namespaces-get-set.html", "733229");
- bugList.put("fast/dom/set-innerHTML.html", "733823");
- bugList.put("fast/dom/xmlhttprequest-get.html", "733846");
- bugList.put("fast/encoding/css-charset-default.html", "733856");
- bugList.put("fast/encoding/default-xhtml-encoding.html", "733882");
- bugList.put("fast/encoding/meta-in-xhtml.html", "733882");
- bugList.put("fast/events/frame-tab-focus.html", "734308");
- bugList.put("fast/events/option-tab.html", "734308");
- bugList.put("fast/forms/focus2.html", "735111");
- bugList.put("fast/forms/listbox-selection.html", "735116");
- bugList.put("fast/forms/search-event-delay.html", "735120");
- bugList.put("fast/frames/iframe-window-focus.html", "735140");
- bugList.put("fast/innerHTML/004.html", "733882");
- bugList.put("fast/js/string-capitalization.html", "516936");
- bugList.put("fast/js/string-concatenate-outofmemory.html","735152");
- bugList.put("fast/parser/external-entities.html", "735176");
- bugList.put("fast/overflow/scroll-vertical-not-horizontal.html", "735196");
- bugList.put("fast/events/arrow-navigation.html", "735233");
- bugList.put("fast/forms/select-type-ahead-non-latin.html", "735244");
- }
-
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
index 1a265e8..ef0c6c6 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
@@ -54,6 +54,9 @@
String[] files = d.list();
for (int i = 0; i < files.length; i++) {
String s = dir + "/" + files[i];
+ if (s.endsWith("TEMPLATE.html")) {
+ continue;
+ }
if (FileFilter.ignoreTest(s)) {
Log.v(LOGTAG, " Ignoring: " + s);
continue;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 2667520..02a7046 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -716,6 +716,7 @@
mCanOpenWindows = false;
mEventSender.resetMouse();
mEventSender.clearTouchPoints();
+ mEventSender.clearTouchMetaState();
mPageFinished = false;
mOneHundredPercentComplete = false;
mDumpWebKitData = false;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java
index 996eaba..0c2347d 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java
@@ -207,7 +207,7 @@
tp.setDownTime(SystemClock.uptimeMillis());
MotionEvent event = MotionEvent.obtain(tp.downTime(), tp.downTime(),
- MotionEvent.ACTION_DOWN, tp.getX(), tp.getY(), 0);
+ MotionEvent.ACTION_DOWN, tp.getX(), tp.getY(), mTouchMetaState);
mWebView.onTouchEvent(event);
}
@@ -223,7 +223,7 @@
}
MotionEvent event = MotionEvent.obtain(tp.downTime(), SystemClock.uptimeMillis(),
- MotionEvent.ACTION_MOVE, tp.getX(), tp.getY(), 0);
+ MotionEvent.ACTION_MOVE, tp.getX(), tp.getY(), mTouchMetaState);
mWebView.onTouchEvent(event);
tp.setMoved(false);
@@ -237,7 +237,7 @@
}
MotionEvent event = MotionEvent.obtain(tp.downTime(), SystemClock.uptimeMillis(),
- MotionEvent.ACTION_UP, tp.getX(), tp.getY(), 0);
+ MotionEvent.ACTION_UP, tp.getX(), tp.getY(), mTouchMetaState);
mWebView.onTouchEvent(event);
if (tp.isReleased()) {
@@ -253,7 +253,7 @@
if (tp.cancelled()) {
MotionEvent event = MotionEvent.obtain(tp.downTime(), SystemClock.uptimeMillis(),
- MotionEvent.ACTION_CANCEL, tp.getX(), tp.getY(), 0);
+ MotionEvent.ACTION_CANCEL, tp.getX(), tp.getY(), mTouchMetaState);
mWebView.onTouchEvent(event);
}
}
@@ -285,8 +285,20 @@
}
public void setTouchModifier(String modifier, boolean enabled) {
- // TODO(benm): This needs implementing when Android supports sending key modifiers
- // in touch events.
+ int mask = 0;
+ if ("alt".equals(modifier.toLowerCase())) {
+ mask = KeyEvent.META_ALT_ON;
+ } else if ("shift".equals(modifier.toLowerCase())) {
+ mask = KeyEvent.META_SHIFT_ON;
+ } else if ("ctrl".equals(modifier.toLowerCase())) {
+ mask = KeyEvent.META_SYM_ON;
+ }
+
+ if (enabled) {
+ mTouchMetaState |= mask;
+ } else {
+ mTouchMetaState &= ~mask;
+ }
}
public void releaseTouchPoint(int id) {
@@ -302,6 +314,10 @@
mTouchPoints.clear();
}
+ public void clearTouchMetaState() {
+ mTouchMetaState = 0;
+ }
+
private int contentsToWindowX(int x) {
return (int) (x * mWebView.getScale()) - mWebView.getScrollX();
}
@@ -352,4 +368,5 @@
};
private Vector<TouchPoint> mTouchPoints;
+ private int mTouchMetaState;
}
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 663a33a..69b2207 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -938,17 +938,17 @@
uint8_t mask = 0;
uint8_t value = 0;
if (strcmp(name, kWildcardName) == 0) {
- mask = out->MASK_KEYSHIDDEN;
- value = out->KEYSHIDDEN_ANY;
+ mask = ResTable_config::MASK_KEYSHIDDEN;
+ value = ResTable_config::KEYSHIDDEN_ANY;
} else if (strcmp(name, "keysexposed") == 0) {
- mask = out->MASK_KEYSHIDDEN;
- value = out->KEYSHIDDEN_NO;
+ mask = ResTable_config::MASK_KEYSHIDDEN;
+ value = ResTable_config::KEYSHIDDEN_NO;
} else if (strcmp(name, "keyshidden") == 0) {
- mask = out->MASK_KEYSHIDDEN;
- value = out->KEYSHIDDEN_YES;
+ mask = ResTable_config::MASK_KEYSHIDDEN;
+ value = ResTable_config::KEYSHIDDEN_YES;
} else if (strcmp(name, "keyssoft") == 0) {
- mask = out->MASK_KEYSHIDDEN;
- value = out->KEYSHIDDEN_SOFT;
+ mask = ResTable_config::MASK_KEYSHIDDEN;
+ value = ResTable_config::KEYSHIDDEN_SOFT;
}
if (mask != 0) {
@@ -985,14 +985,14 @@
uint8_t mask = 0;
uint8_t value = 0;
if (strcmp(name, kWildcardName) == 0) {
- mask = out->MASK_NAVHIDDEN;
- value = out->NAVHIDDEN_ANY;
+ mask = ResTable_config::MASK_NAVHIDDEN;
+ value = ResTable_config::NAVHIDDEN_ANY;
} else if (strcmp(name, "navexposed") == 0) {
- mask = out->MASK_NAVHIDDEN;
- value = out->NAVHIDDEN_NO;
+ mask = ResTable_config::MASK_NAVHIDDEN;
+ value = ResTable_config::NAVHIDDEN_NO;
} else if (strcmp(name, "navhidden") == 0) {
- mask = out->MASK_NAVHIDDEN;
- value = out->NAVHIDDEN_YES;
+ mask = ResTable_config::MASK_NAVHIDDEN;
+ value = ResTable_config::NAVHIDDEN_YES;
}
if (mask != 0) {
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index a389bfb..0b531c2 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -382,7 +382,7 @@
}
attr.createIfNeeded(outTable);
if (!attr.hasErrors) {
- char buf[10];
+ char buf[11];
sprintf(buf, "%d", l10n_required);
err = outTable->addBag(attr.sourcePos, myPackage, attr16, attr.ident,
String16(""), String16("^l10n"), String16(buf), NULL, NULL);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 990498f..41d9f9d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -30,6 +30,7 @@
import com.android.tools.layoutlib.create.MethodAdapter;
import com.android.tools.layoutlib.create.OverrideMethod;
+import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
@@ -1133,7 +1134,7 @@
}
@SuppressWarnings("unused")
- public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4)
+ public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4, Configuration arg5)
throws RemoteException {
// pass for now.
}