Merge "LayoutLib: move asserts around." into honeycomb
diff --git a/api/11.xml b/api/11.xml
index 43bb440..e2f8025 100644
--- a/api/11.xml
+++ b/api/11.xml
@@ -61129,17 +61129,6 @@
visibility="public"
>
</method>
-<method name="getGL"
- return="javax.microedition.khronos.opengles.GL"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="getHeight"
return="int"
abstract="false"
diff --git a/api/current.xml b/api/current.xml
index 57a76de..344d6b4 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1255,17 +1255,6 @@
visibility="public"
>
</field>
-<field name="WRITE_MEDIA_STORAGE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""android.permission.WRITE_MEDIA_STORAGE""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="WRITE_SECURE_SETTINGS"
type="java.lang.String"
transient="false"
@@ -58409,6 +58398,17 @@
visibility="public"
>
</method>
+<method name="isEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<field name="applicationInfo"
type="android.content.pm.ApplicationInfo"
transient="false"
@@ -78255,17 +78255,6 @@
visibility="public"
>
</method>
-<method name="getGL"
- return="javax.microedition.khronos.opengles.GL"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="protected"
->
-</method>
<method name="getHeight"
return="int"
abstract="false"
@@ -136934,6 +136923,19 @@
deprecated="not deprecated"
visibility="protected"
>
+<parameter name="result" type="Result">
+</parameter>
+</method>
+<method name="onCancelled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
</method>
<method name="onPostExecute"
return="void"
@@ -166353,8 +166355,6 @@
</parameter>
<parameter name="mips" type="android.renderscript.Allocation.MipmapControl">
</parameter>
-<parameter name="layout" type="android.renderscript.Allocation.CubemapLayout">
-</parameter>
<parameter name="usage" type="int">
</parameter>
</method>
@@ -166372,8 +166372,6 @@
</parameter>
<parameter name="b" type="android.graphics.Bitmap">
</parameter>
-<parameter name="layout" type="android.renderscript.Allocation.CubemapLayout">
-</parameter>
</method>
<method name="createFromBitmap"
return="android.renderscript.Allocation"
@@ -166633,39 +166631,6 @@
>
</field>
</class>
-<class name="Allocation.CubemapLayout"
- extends="java.lang.Enum"
- abstract="false"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="valueOf"
- return="android.renderscript.Allocation.CubemapLayout"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="name" type="java.lang.String">
-</parameter>
-</method>
-<method name="values"
- return="android.renderscript.Allocation.CubemapLayout[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-</class>
<class name="Allocation.MipmapControl"
extends="java.lang.Enum"
abstract="false"
@@ -198616,6 +198581,17 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
+<method name="isLenient"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="nextBoolean"
return="boolean"
abstract="false"
@@ -198746,21 +198722,6 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
-<method name="syntaxError"
- return="java.io.IOException"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="message" type="java.lang.String">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
</class>
<class name="JsonToken"
extends="java.lang.Enum"
@@ -198893,6 +198854,17 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
+<method name="isLenient"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="name"
return="android.util.JsonWriter"
abstract="false"
@@ -198934,6 +198906,19 @@
<parameter name="indent" type="java.lang.String">
</parameter>
</method>
+<method name="setLenient"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="lenient" type="boolean">
+</parameter>
+</method>
<method name="value"
return="android.util.JsonWriter"
abstract="false"
@@ -198994,6 +198979,21 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
+<method name="value"
+ return="android.util.JsonWriter"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="java.lang.Number">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
</class>
<class name="Log"
extends="java.lang.Object"
@@ -199373,6 +199373,25 @@
</parameter>
</method>
</class>
+<class name="MalformedJsonException"
+ extends="java.io.IOException"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="MalformedJsonException"
+ type="android.util.MalformedJsonException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+</class>
<class name="MonthDisplayHelper"
extends="java.lang.Object"
abstract="false"
@@ -258003,7 +258022,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="t" type="T">
+<parameter name="arg0" type="T">
</parameter>
</method>
</interface>
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 8b292c9..0bce748 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -237,43 +237,7 @@
private BroadcastReceiver mConnectivityIntentReceiver =
new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
- NetworkInfo networkInfo =
- intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
- NetworkInfo.State state = (networkInfo == null ? NetworkInfo.State.UNKNOWN :
- networkInfo.getState());
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "received connectivity action. network info: " + networkInfo);
- }
-
- final boolean wasConnected = mDataConnectionIsConnected;
- // only pay attention to the CONNECTED and DISCONNECTED states.
- // if connected, we are connected.
- // if disconnected, we may not be connected. in some cases, we may be connected on
- // a different network.
- // e.g., if switching from GPRS to WiFi, we may receive the CONNECTED to WiFi and
- // DISCONNECTED for GPRS in any order. if we receive the CONNECTED first, and then
- // a DISCONNECTED, we want to make sure we set mDataConnectionIsConnected to true
- // since we still have a WiFi connection.
- switch (state) {
- case CONNECTED:
- mDataConnectionIsConnected = true;
- break;
- case DISCONNECTED:
- mDataConnectionIsConnected = !intent.getBooleanExtra(
- ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
- break;
- default:
- // ignore the rest of the states -- leave our boolean alone.
- }
- if (mDataConnectionIsConnected) {
- if (!wasConnected) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Reconnection detected: clearing all backoffs");
- }
- mSyncStorageEngine.clearAllBackoffs();
- }
- sendCheckAlarmsMessage();
- }
+ sendCheckAlarmsMessage();
}
};
@@ -1409,8 +1373,12 @@
public void handleMessage(Message msg) {
long earliestFuturePollTime = Long.MAX_VALUE;
long nextPendingSyncTime = Long.MAX_VALUE;
+ // Setting the value here instead of a method because we want the dumpsys logs
+ // to have the most recent value used.
try {
waitUntilReadyToRun();
+ NetworkInfo info = getConnectivityManager().getActiveNetworkInfo();
+ mDataConnectionIsConnected = (info != null) && info.isConnected();
mSyncManagerWakeLock.acquire();
// Always do this first so that we be sure that any periodic syncs that
// are ready to run have been converted into pending syncs. This allows the
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index f16c4ef..2812477 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -98,6 +98,13 @@
}
return name;
}
+
+ /**
+ * Return whether this component and its enclosing application are enabled.
+ */
+ public boolean isEnabled() {
+ return enabled && applicationInfo.enabled;
+ }
/**
* Return the icon resource identifier to use for this component. If
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index 5e96928..c76cc6c 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -131,6 +131,10 @@
long retValue = native_1x1_long();
mDatabase.logTimeStat(mSql, timeStart);
return retValue;
+ } catch (SQLiteDoneException e) {
+ throw new SQLiteDoneException(
+ "expected 1 row from this query but query returned no data. check the query: " +
+ mSql);
} finally {
releaseAndUnlock();
}
@@ -150,6 +154,10 @@
String retValue = native_1x1_string();
mDatabase.logTimeStat(mSql, timeStart);
return retValue;
+ } catch (SQLiteDoneException e) {
+ throw new SQLiteDoneException(
+ "expected 1 row from this query but query returned no data. check the query: " +
+ mSql);
} finally {
releaseAndUnlock();
}
@@ -172,6 +180,10 @@
} catch (IOException ex) {
Log.e(TAG, "simpleQueryForBlobFileDescriptor() failed", ex);
return null;
+ } catch (SQLiteDoneException e) {
+ throw new SQLiteDoneException(
+ "expected 1 row from this query but query returned no data. check the query: " +
+ mSql);
} finally {
releaseAndUnlock();
}
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 46a29a9..9f7e31c 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -26,6 +26,7 @@
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -115,11 +116,11 @@
* <h2>Cancelling a task</h2>
* <p>A task can be cancelled at any time by invoking {@link #cancel(boolean)}. Invoking
* this method will cause subsequent calls to {@link #isCancelled()} to return true.
- * After invoking this method, {@link #onCancelled()}, instead of {@link #onPostExecute(Object)}
- * will be invoked after {@link #doInBackground(Object[])} returns. To ensure that
- * a task is cancelled as quickly as possible, you should always check the return
- * value of {@link #isCancelled()} periodically from {@link #doInBackground(Object[])},
- * if possible (inside a loop for instance.)</p>
+ * After invoking this method, {@link #onCancelled(Object)}, instead of
+ * {@link #onPostExecute(Object)} will be invoked after {@link #doInBackground(Object[])}
+ * returns. To ensure that a task is cancelled as quickly as possible, you should always
+ * check the return value of {@link #isCancelled()} periodically from
+ * {@link #doInBackground(Object[])}, if possible (inside a loop for instance.)</p>
*
* <h2>Threading rules</h2>
* <p>There are a few threading rules that must be followed for this class to
@@ -173,6 +174,8 @@
private final FutureTask<Result> mFuture;
private volatile Status mStatus = Status.PENDING;
+
+ private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
/**
* Indicates the current status of the task. Each status will be set only once
@@ -204,15 +207,10 @@
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
+ mTaskInvoked.set(true);
+
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-
- Result result = doInBackground(mParams);
-
- Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
- new AsyncTaskResult<Result>(AsyncTask.this, result));
- message.sendToTarget();
-
- return result;
+ return postResult(doInBackground(mParams));
}
};
@@ -220,14 +218,16 @@
@Override
protected void done() {
try {
- get();
+ final Result result = get();
+
+ postResultIfNotInvoked(result);
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
- // Taken care of in the WorkerRunnable
+ postResultIfNotInvoked(null);
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
@@ -236,6 +236,20 @@
};
}
+ private void postResultIfNotInvoked(Result result) {
+ final boolean wasTaskInvoked = mTaskInvoked.get();
+ if (!wasTaskInvoked) {
+ postResult(result);
+ }
+ }
+
+ private Result postResult(Result result) {
+ Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
+ new AsyncTaskResult<Result>(this, result));
+ message.sendToTarget();
+ return result;
+ }
+
/**
* Returns the current status of this task.
*
@@ -282,7 +296,7 @@
*
* @see #onPreExecute
* @see #doInBackground
- * @see #onCancelled()
+ * @see #onCancelled(Object)
*/
@SuppressWarnings({"UnusedDeclaration"})
protected void onPostExecute(Result result) {
@@ -302,9 +316,33 @@
}
/**
- * Runs on the UI thread after {@link #cancel(boolean)} is invoked and
- * {@link #doInBackground(Object[])} has finished.
+ * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
+ * {@link #doInBackground(Object[])} has finished.</p>
+ *
+ * <p>The default implementation simply invokes {@link #onCancelled()} and
+ * ignores the result. If you write your own implementation, do not call
+ * <code>super.onCancelled(result)</code>.</p>
*
+ * @param result The result, if any, computed in
+ * {@link #doInBackground(Object[])}, can be null
+ *
+ * @see #cancel(boolean)
+ * @see #isCancelled()
+ */
+ @SuppressWarnings({"UnusedParameters"})
+ protected void onCancelled(Result result) {
+ onCancelled();
+ }
+
+ /**
+ * <p>Applications should preferably override {@link #onCancelled(Object)}.
+ * This method is invoked by the default implementation of
+ * {@link #onCancelled(Object)}.</p>
+ *
+ * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
+ * {@link #doInBackground(Object[])} has finished.</p>
+ *
+ * @see #onCancelled(Object)
* @see #cancel(boolean)
* @see #isCancelled()
*/
@@ -335,7 +373,7 @@
* whether the thread executing this task should be interrupted in
* an attempt to stop the task.</p>
*
- * <p>Calling this method will result in {@link #onCancelled()} being
+ * <p>Calling this method will result in {@link #onCancelled(Object)} being
* invoked on the UI thread after {@link #doInBackground(Object[])}
* returns. Calling this method guarantees that {@link #onPostExecute(Object)}
* is never invoked. After invoking this method, you should check the
@@ -352,7 +390,7 @@
* <tt>true</tt> otherwise
*
* @see #isCancelled()
- * @see #onCancelled()
+ * @see #onCancelled(Object)
*/
public final boolean cancel(boolean mayInterruptIfRunning) {
return mFuture.cancel(mayInterruptIfRunning);
@@ -452,7 +490,7 @@
private void finish(Result result) {
if (isCancelled()) {
- onCancelled();
+ onCancelled(result);
} else {
onPostExecute(result);
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d1ca0c9..ee091f0 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -3430,12 +3430,6 @@
* <th colspan='4'>PhoneLookup</th>
* </tr>
* <tr>
- * <td>long</td>
- * <td>{@link #_ID}</td>
- * <td>read-only</td>
- * <td>Data row ID.</td>
- * </tr>
- * <tr>
* <td>String</td>
* <td>{@link #NUMBER}</td>
* <td>read-only</td>
@@ -3462,6 +3456,12 @@
* <th colspan='4'>Join with {@link Contacts}</th>
* </tr>
* <tr>
+ * <td>long</td>
+ * <td>{@link #_ID}</td>
+ * <td>read-only</td>
+ * <td>Contact ID.</td>
+ * </tr>
+ * <tr>
* <td>String</td>
* <td>{@link #LOOKUP_KEY}</td>
* <td>read-only</td>
diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java
index 8025545..8f44895 100644
--- a/core/java/android/util/JsonReader.java
+++ b/core/java/android/util/JsonReader.java
@@ -16,6 +16,7 @@
package android.util;
+import java.io.EOFException;
import java.io.IOException;
import java.io.Reader;
import java.io.Closeable;
@@ -249,6 +250,13 @@
}
/**
+ * Returns true if this parser is liberal in what it accepts.
+ */
+ public boolean isLenient() {
+ return lenient;
+ }
+
+ /**
* Consumes the next token from the JSON stream and asserts that it is the
* beginning of a new array.
*/
@@ -311,7 +319,7 @@
case EMPTY_DOCUMENT:
replaceTop(JsonScope.NONEMPTY_DOCUMENT);
JsonToken firstToken = nextValue();
- if (token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) {
+ if (!lenient && token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) {
throw new IOException(
"Expected JSON document to start with '[' or '{' but was " + token);
}
@@ -327,7 +335,15 @@
case NONEMPTY_OBJECT:
return nextInObject(false);
case NONEMPTY_DOCUMENT:
- return token = JsonToken.END_DOCUMENT;
+ try {
+ JsonToken token = nextValue();
+ if (lenient) {
+ return token;
+ }
+ throw syntaxError("Expected EOF");
+ } catch (EOFException e) {
+ return token = JsonToken.END_DOCUMENT; // TODO: avoid throwing here?
+ }
case CLOSED:
throw new IllegalStateException("JsonReader is closed");
default:
@@ -758,7 +774,7 @@
}
}
- throw syntaxError("End of input");
+ throw new EOFException("End of input");
}
private void checkLenient() throws IOException {
@@ -1030,8 +1046,6 @@
* form -12.34e+56. Fractional and exponential parts are optional. Leading
* zeroes are not allowed in the value or exponential part, but are allowed
* in the fraction.
- *
- * <p>This has a side effect of setting isInteger.
*/
private JsonToken decodeNumber(char[] chars, int offset, int length) {
int i = offset;
@@ -1085,8 +1099,8 @@
* Throws a new IO exception with the given message and a context snippet
* with this reader's content.
*/
- public IOException syntaxError(String message) throws IOException {
- throw new JsonSyntaxException(message + " near " + getSnippet());
+ private IOException syntaxError(String message) throws IOException {
+ throw new MalformedJsonException(message + " near " + getSnippet());
}
private CharSequence getSnippet() {
@@ -1097,10 +1111,4 @@
snippet.append(buffer, pos, afterPos);
return snippet;
}
-
- private static class JsonSyntaxException extends IOException {
- private JsonSyntaxException(String s) {
- super(s);
- }
- }
}
diff --git a/core/java/android/util/JsonWriter.java b/core/java/android/util/JsonWriter.java
index 89cad79..47e84c5 100644
--- a/core/java/android/util/JsonWriter.java
+++ b/core/java/android/util/JsonWriter.java
@@ -138,6 +138,8 @@
*/
private String separator = ":";
+ private boolean lenient;
+
/**
* Creates a new instance that writes a JSON-encoded stream to {@code out}.
* For best performance, ensure {@link Writer} is buffered; wrapping in
@@ -169,6 +171,29 @@
}
/**
+ * Configure this writer to relax its syntax rules. By default, this writer
+ * only emits well-formed JSON as specified by <a
+ * href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. Setting the writer
+ * to lenient permits the following:
+ * <ul>
+ * <li>Top-level values of any type. With strict writing, the top-level
+ * value must be an object or an array.
+ * <li>Numbers may be {@link Double#isNaN() NaNs} or {@link
+ * Double#isInfinite() infinities}.
+ * </ul>
+ */
+ public void setLenient(boolean lenient) {
+ this.lenient = lenient;
+ }
+
+ /**
+ * Returns true if this writer has relaxed syntax rules.
+ */
+ public boolean isLenient() {
+ return lenient;
+ }
+
+ /**
* Begins encoding a new array. Each call to this method must be paired with
* a call to {@link #endArray}.
*
@@ -306,11 +331,11 @@
* Encodes {@code value}.
*
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or
- * {@link Double#isInfinite() infinities}.
+ * {@link Double#isInfinite() infinities} unless this writer is lenient.
* @return this writer.
*/
public JsonWriter value(double value) throws IOException {
- if (Double.isNaN(value) || Double.isInfinite(value)) {
+ if (!lenient && (Double.isNaN(value) || Double.isInfinite(value))) {
throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
}
beforeValue(false);
@@ -330,6 +355,28 @@
}
/**
+ * Encodes {@code value}.
+ *
+ * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
+ * {@link Double#isInfinite() infinities} unless this writer is lenient.
+ * @return this writer.
+ */
+ public JsonWriter value(Number value) throws IOException {
+ if (value == null) {
+ return nullValue();
+ }
+
+ String string = value.toString();
+ if (!lenient &&
+ (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) {
+ throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
+ }
+ beforeValue(false);
+ out.append(string);
+ return this;
+ }
+
+ /**
* Ensures all buffered data is written to the underlying {@link Writer}
* and flushes that writer.
*/
@@ -364,7 +411,6 @@
switch (c) {
case '"':
case '\\':
- case '/':
out.write('\\');
out.write(c);
break;
@@ -439,7 +485,7 @@
private void beforeValue(boolean root) throws IOException {
switch (peek()) {
case EMPTY_DOCUMENT: // first in document
- if (!root) {
+ if (!lenient && !root) {
throw new IllegalStateException(
"JSON must start with an array or an object.");
}
diff --git a/core/java/android/util/MalformedJsonException.java b/core/java/android/util/MalformedJsonException.java
new file mode 100644
index 0000000..63c19ff
--- /dev/null
+++ b/core/java/android/util/MalformedJsonException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 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.util;
+
+import java.io.IOException;
+
+/**
+ * Thrown when a reader encounters malformed JSON. Some syntax errors can be
+ * ignored by calling {@link JsonReader#setLenient(boolean)}.
+ */
+public final class MalformedJsonException extends IOException {
+ private static final long serialVersionUID = 1L;
+
+ public MalformedJsonException(String message) {
+ super(message);
+ }
+}
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 4c2f0b4..1313fcc 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -204,11 +204,6 @@
case KeyEvent.KEYCODE_DPAD_RIGHT:
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_DOWN:
- if (!mWebView.nativeCursorMatchesFocus()) {
- return down ? mWebView.onKeyDown(keyCode, event) : mWebView
- .onKeyUp(keyCode, event);
-
- }
isArrowKey = true;
break;
}
@@ -258,10 +253,6 @@
if (isPopupShowing()) {
return super.dispatchKeyEvent(event);
}
- if (!mWebView.nativeCursorMatchesFocus()) {
- return down ? mWebView.onKeyDown(keyCode, event) : mWebView
- .onKeyUp(keyCode, event);
- }
// Center key should be passed to a potential onClick
if (!down) {
mWebView.centerKeyPressOnTextField();
@@ -753,12 +744,7 @@
if (event.getAction() != MotionEvent.ACTION_MOVE) {
return false;
}
- // If the Cursor is not on the text input, webview should handle the
- // trackball
- if (!mWebView.nativeCursorMatchesFocus()) {
- return mWebView.onTrackballEvent(event);
- }
- Spannable text = (Spannable) getText();
+ Spannable text = getText();
MovementMethod move = getMovementMethod();
if (move != null && getLayout() != null &&
move.onTrackballEvent(this, text, event)) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 61f0bce..e8283a6 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -56,6 +56,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.os.SystemClock;
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
import android.text.Selection;
@@ -2961,12 +2962,12 @@
* @return boolean True if the find dialog is shown, false otherwise.
*/
public boolean showFindDialog(String text, boolean showIme) {
- mFindCallback = new FindActionModeCallback(mContext);
- if (startActionMode(mFindCallback) == null) {
+ FindActionModeCallback callback = new FindActionModeCallback(mContext);
+ if (startActionMode(callback) == null) {
// Could not start the action mode, so end Find on page
- mFindCallback = null;
return false;
}
+ mFindCallback = callback;
setFindIsUp(true);
mFindCallback.setWebView(this);
if (showIme) {
@@ -4564,14 +4565,6 @@
return true;
}
- if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
- || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
- if (!nativePageShouldHandleShiftAndArrows() && !nativeCursorWantsKeyEvents()
- && !mSelectingText) {
- setUpSelect();
- }
- }
-
if (keyCode == KeyEvent.KEYCODE_PAGE_UP) {
if (event.hasNoModifiers()) {
pageUp(false);
@@ -4662,12 +4655,6 @@
if (!wantsKeyEvents) return false;
}
- if (keyCode != KeyEvent.KEYCODE_SHIFT_LEFT
- && keyCode != KeyEvent.KEYCODE_SHIFT_RIGHT) {
- // turn off copy select if a shift-key combo is pressed
- selectionDone();
- }
-
if (getSettings().getNavDump()) {
switch (keyCode) {
case KeyEvent.KEYCODE_4:
@@ -4766,14 +4753,6 @@
return true;
}
- if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
- || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
- if (!nativePageShouldHandleShiftAndArrows() && copySelection()) {
- selectionDone();
- return true;
- }
- }
-
if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
&& keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
if (nativePageShouldHandleShiftAndArrows()) {
@@ -5234,7 +5213,8 @@
// Textfields, plugins, and contentEditable nodes need to receive the
// shift up key even if another key was released while the shift key
// was held down.
- if (!inEditingMode() && (mNativeClass == 0
+ boolean inEditingMode = inEditingMode();
+ if (!inEditingMode && (mNativeClass == 0
|| !nativePageShouldHandleShiftAndArrows())) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
mGotKeyDown = true;
@@ -5251,7 +5231,13 @@
}
if (dispatch) {
- return super.dispatchKeyEvent(event);
+ if (inEditingMode) {
+ // Ensure that the WebTextView gets the event, even if it does
+ // not currently have a bounds.
+ return mWebTextView.dispatchKeyEvent(event);
+ } else {
+ return super.dispatchKeyEvent(event);
+ }
} else {
// We didn't dispatch, so let something else handle the key
return false;
@@ -5344,17 +5330,10 @@
+ " numPointers=" + ev.getPointerCount());
}
- int action = ev.getAction();
- float x = ev.getX();
- float y = ev.getY();
- long eventTime = ev.getEventTime();
-
- // mDeferMultitouch is a hack for layout tests, where it is used to
- // force passing multi-touch events to webkit.
- // FIXME: always pass multi-touch events to webkit and remove everything
- // related to mDeferMultitouch.
- if (ev.getPointerCount() > 1 &&
- (mDeferMultitouch || mZoomManager.isZoomScaleFixed())) {
+ // Always pass multi-touch event to WebKit first.
+ // If WebKit doesn't consume it and set preventDefault to true,
+ // WebView's private handler will handle it.
+ if (ev.getPointerCount() > 1) {
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "passing " + ev.getPointerCount() + " points to webkit");
}
@@ -5362,59 +5341,15 @@
return true;
}
- final ScaleGestureDetector detector =
- mZoomManager.getMultiTouchGestureDetector();
+ return handleTouchEventCommon(ev);
+ }
- if (mZoomManager.supportsMultiTouchZoom() && ev.getPointerCount() > 1) {
- if (!detector.isInProgress() &&
- ev.getActionMasked() != MotionEvent.ACTION_POINTER_DOWN) {
- // Insert a fake pointer down event in order to start
- // the zoom scale detector.
- MotionEvent temp = MotionEvent.obtain(ev);
- // Clear the original event and set it to
- // ACTION_POINTER_DOWN.
- try {
- temp.setAction(temp.getAction() &
- ~MotionEvent.ACTION_MASK |
- MotionEvent.ACTION_POINTER_DOWN);
- detector.onTouchEvent(temp);
- } finally {
- temp.recycle();
- }
- }
+ private boolean handleTouchEventCommon(MotionEvent ev) {
+ int action = ev.getAction();
+ float x = ev.getX();
+ float y = ev.getY();
+ long eventTime = ev.getEventTime();
- detector.onTouchEvent(ev);
-
- if (detector.isInProgress()) {
- mLastTouchTime = eventTime;
- cancelLongPress();
- mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- if (!mZoomManager.supportsPanDuringZoom()) {
- return true;
- }
- mTouchMode = TOUCH_DRAG_MODE;
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- }
- }
-
- x = detector.getFocusX();
- y = detector.getFocusY();
- action = ev.getAction() & MotionEvent.ACTION_MASK;
- if (action == MotionEvent.ACTION_POINTER_DOWN) {
- cancelTouch();
- action = MotionEvent.ACTION_DOWN;
- } else if (action == MotionEvent.ACTION_POINTER_UP) {
- // set mLastTouchX/Y to the remaining point
- mLastTouchX = x;
- mLastTouchY = y;
- } else if (action == MotionEvent.ACTION_MOVE) {
- // negative x or y indicate it is on the edge, skip it.
- if (x < 0 || y < 0) {
- return true;
- }
- }
- }
// Due to the touch screen edge effect, a touch closer to the edge
// always snapped to the edge. As getViewWidth() can be different from
@@ -5627,22 +5562,6 @@
break;
}
- // Only lock dragging to one axis if we don't have a scale in progress.
- // Scaling implies free-roaming movement. Note this is only ever a question
- // if mZoomManager.supportsPanDuringZoom() is true.
- if (detector != null && !detector.isInProgress()) {
- // if it starts nearly horizontal or vertical, enforce it
- int ax = Math.abs(deltaX);
- int ay = Math.abs(deltaY);
- if (ax > MAX_SLOPE_FOR_DIAG * ay) {
- mSnapScrollMode = SNAP_X;
- mSnapPositive = deltaX > 0;
- } else if (ay > MAX_SLOPE_FOR_DIAG * ax) {
- mSnapScrollMode = SNAP_Y;
- mSnapPositive = deltaY > 0;
- }
- }
-
mTouchMode = TOUCH_DRAG_MODE;
mLastTouchX = x;
mLastTouchY = y;
@@ -5899,13 +5818,82 @@
ted.mPoints[c] = new Point(x, y);
}
ted.mMetaState = ev.getMetaState();
- ted.mReprocess = mDeferTouchProcess;
+ ted.mReprocess = true;
+ ted.mMotionEvent = MotionEvent.obtain(ev);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
cancelLongPress();
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
mPreventDefault = PREVENT_DEFAULT_IGNORE;
}
+ private boolean handleMultiTouchInWebView(MotionEvent ev) {
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "multi-touch: " + ev + " at " + ev.getEventTime()
+ + " mTouchMode=" + mTouchMode
+ + " numPointers=" + ev.getPointerCount()
+ + " scrolloffset=(" + mScrollX + "," + mScrollY + ")");
+ }
+
+ final ScaleGestureDetector detector =
+ mZoomManager.getMultiTouchGestureDetector();
+ int action = ev.getAction();
+ float x = ev.getX();
+ float y = ev.getY();
+ long eventTime = ev.getEventTime();
+
+ if (!detector.isInProgress() &&
+ ev.getActionMasked() != MotionEvent.ACTION_POINTER_DOWN) {
+ // Insert a fake pointer down event in order to start
+ // the zoom scale detector.
+ MotionEvent temp = MotionEvent.obtain(ev);
+ // Clear the original event and set it to
+ // ACTION_POINTER_DOWN.
+ try {
+ temp.setAction(temp.getAction() &
+ ~MotionEvent.ACTION_MASK |
+ MotionEvent.ACTION_POINTER_DOWN);
+ detector.onTouchEvent(temp);
+ } finally {
+ temp.recycle();
+ }
+ }
+
+ detector.onTouchEvent(ev);
+
+ if (detector.isInProgress()) {
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "detector is in progress");
+ }
+ mLastTouchTime = eventTime;
+ cancelLongPress();
+ mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
+ if (!mZoomManager.supportsPanDuringZoom()) {
+ return false;
+ }
+ mTouchMode = TOUCH_DRAG_MODE;
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ }
+
+ action = ev.getAction() & MotionEvent.ACTION_MASK;
+ if (action == MotionEvent.ACTION_POINTER_DOWN) {
+ cancelTouch();
+ action = MotionEvent.ACTION_DOWN;
+ } else if (action == MotionEvent.ACTION_POINTER_UP) {
+ // set mLastTouchX/Y to the remaining point
+ mLastTouchX = x;
+ mLastTouchY = y;
+ } else if (action == MotionEvent.ACTION_MOVE) {
+ // negative x or y indicate it is on the edge, skip it.
+ if (x < 0 || y < 0) {
+ return false;
+ }
+ }
+
+ return handleTouchEventCommon(ev);
+ }
+
private void cancelWebCoreTouchEvent(int x, int y, boolean removeEvents) {
if (shouldForwardTouchEvent()) {
if (removeEvents) {
@@ -7278,6 +7266,13 @@
// prevent default is not called in WebCore, so the
// message needs to be reprocessed in UI
TouchEventData ted = (TouchEventData) msg.obj;
+
+ if (ted.mPoints.length > 1) { // for multi-touch.
+ handleMultiTouchInWebView(ted.mMotionEvent);
+ break;
+ }
+
+ // Following is for single touch.
switch (ted.mAction) {
case MotionEvent.ACTION_DOWN:
mLastDeferTouchX = contentToViewX(ted.mPoints[0].x)
@@ -8103,7 +8098,6 @@
private native int nativeCursorFramePointer();
private native Rect nativeCursorNodeBounds();
private native int nativeCursorNodePointer();
- /* package */ native boolean nativeCursorMatchesFocus();
private native boolean nativeCursorIntersects(Rect visibleRect);
private native boolean nativeCursorIsAnchor();
private native boolean nativeCursorIsTextInput();
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index a482b74..c874160 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -33,6 +33,7 @@
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.webkit.DeviceMotionService;
@@ -830,6 +831,7 @@
Point[] mPoints;
int mMetaState;
boolean mReprocess;
+ MotionEvent mMotionEvent;
}
static class GeolocationPermissionsData {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index b85670c..bccde8d 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -4810,7 +4810,10 @@
if (mFiltered && mPopup != null && mPopup.isShowing()) {
if (event.getAction() == KeyEvent.ACTION_DOWN
&& event.getRepeatCount() == 0) {
- getKeyDispatcherState().startTracking(event, this);
+ KeyEvent.DispatcherState state = getKeyDispatcherState();
+ if (state != null) {
+ state.startTracking(event, this);
+ }
handled = true;
} else if (event.getAction() == KeyEvent.ACTION_UP
&& event.isTracking() && !event.isCanceled()) {
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index ee037cd..4d8d21f 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -607,10 +607,16 @@
// special case for the back key, we do not even try to send it
// to the drop down list but instead, consume it immediately
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
- getKeyDispatcherState().startTracking(event, this);
+ KeyEvent.DispatcherState state = getKeyDispatcherState();
+ if (state != null) {
+ state.startTracking(event, this);
+ }
return true;
} else if (event.getAction() == KeyEvent.ACTION_UP) {
- getKeyDispatcherState().handleUpEvent(event);
+ KeyEvent.DispatcherState state = getKeyDispatcherState();
+ if (state != null) {
+ state.handleUpEvent(event);
+ }
if (event.isTracking() && !event.isCanceled()) {
dismissDropDown();
return true;
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 3bba816..444a163d 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -915,10 +915,16 @@
// to the drop down list but instead, consume it immediately
final View anchorView = mDropDownAnchorView;
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
- anchorView.getKeyDispatcherState().startTracking(event, this);
+ KeyEvent.DispatcherState state = anchorView.getKeyDispatcherState();
+ if (state != null) {
+ state.startTracking(event, this);
+ }
return true;
} else if (event.getAction() == KeyEvent.ACTION_UP) {
- anchorView.getKeyDispatcherState().handleUpEvent(event);
+ KeyEvent.DispatcherState state = anchorView.getKeyDispatcherState();
+ if (state != null) {
+ state.handleUpEvent(event);
+ }
if (event.isTracking() && !event.isCanceled()) {
dismiss();
return true;
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 5a5b6f4..79d6a81 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1468,12 +1468,17 @@
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
if (event.getAction() == KeyEvent.ACTION_DOWN
&& event.getRepeatCount() == 0) {
- getKeyDispatcherState().startTracking(event, this);
+ KeyEvent.DispatcherState state = getKeyDispatcherState();
+ if (state != null) {
+ state.startTracking(event, this);
+ }
return true;
- } else if (event.getAction() == KeyEvent.ACTION_UP
- && getKeyDispatcherState().isTracking(event) && !event.isCanceled()) {
- dismiss();
- return true;
+ } else if (event.getAction() == KeyEvent.ACTION_UP) {
+ KeyEvent.DispatcherState state = getKeyDispatcherState();
+ if (state != null && state.isTracking(event) && !event.isCanceled()) {
+ dismiss();
+ return true;
+ }
}
return super.dispatchKeyEvent(event);
} else {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index cc5be00..7675e0c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4780,7 +4780,6 @@
}
hideControllers();
- stopSelectionActionMode();
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
@@ -5119,6 +5118,7 @@
if (mInputMethodState != null) {
mInputMethodState.mExtracting = req;
}
+ // This stops a possible text selection mode. Maybe not intended.
hideControllers();
}
@@ -6781,7 +6781,7 @@
sendOnTextChanged(buffer, start, before, after);
onTextChanged(buffer, start, before, after);
- // Hide the controller if the amount of content changed
+ // Hide the controllers if the amount of content changed
if (before != after) {
hideControllers();
}
@@ -8207,9 +8207,12 @@
selectCurrentWord();
}
- final InputMethodManager imm = (InputMethodManager)
- getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.showSoftInput(this, 0, null);
+ if (!mTextIsSelectable) {
+ // Show the IME, except when selection non editable text.
+ final InputMethodManager imm = (InputMethodManager)
+ getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(this, 0, null);
+ }
ActionMode.Callback actionModeCallback = new SelectionActionModeCallback();
mSelectionActionMode = startActionMode(actionModeCallback);
@@ -8233,6 +8236,7 @@
private void stopSelectionActionMode() {
if (mSelectionActionMode != null) {
+ // This will hide the mSelectionModifierCursorController
mSelectionActionMode.finish();
}
}
@@ -8356,8 +8360,12 @@
if (mCustomSelectionActionModeCallback != null) {
mCustomSelectionActionModeCallback.onDestroyActionMode(mode);
}
- Selection.setSelection((Spannable) mText, getSelectionStart());
- hideSelectionModifierCursorController();
+ Selection.setSelection((Spannable) mText, getSelectionEnd());
+
+ if (mSelectionModifierCursorController != null) {
+ mSelectionModifierCursorController.hide();
+ }
+
mSelectionActionMode = null;
}
}
@@ -9173,16 +9181,12 @@
}
}
- private void hideSelectionModifierCursorController() {
- // No need to create the controller to hide it.
- if (mSelectionModifierCursorController != null) {
- mSelectionModifierCursorController.hide();
- }
- }
-
+ /**
+ * Hides the insertion controller and stops text selection mode, hiding the selection controller
+ */
private void hideControllers() {
hideInsertionPointCursorController();
- hideSelectionModifierCursorController();
+ stopSelectionActionMode();
}
/**
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 9381675..463902f 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -139,6 +139,10 @@
mReserveOverflow = reserveOverflow;
}
+ public View getOverflowButton() {
+ return mOverflowButton;
+ }
+
@Override
protected LayoutParams generateDefaultLayoutParams() {
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index fe41f52..b93fac4 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -68,6 +68,10 @@
}
}
+ public void setAnchorView(View anchor) {
+ mAnchorView = new WeakReference<View>(anchor);
+ }
+
public void show() {
if (!tryShow()) {
throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp
index ada4dd3..52e8f42 100644
--- a/core/jni/com_android_internal_os_ZygoteInit.cpp
+++ b/core/jni/com_android_internal_os_ZygoteInit.cpp
@@ -45,14 +45,10 @@
static jint com_android_internal_os_ZygoteInit_setreuid(
JNIEnv* env, jobject clazz, jint ruid, jint euid)
{
- int err;
-
- errno = 0;
- err = setreuid(ruid, euid);
-
- //LOGI("setreuid(%d,%d) err %d errno %d", ruid, euid, err, errno);
-
- return errno;
+ if (setreuid(ruid, euid) < 0) {
+ return errno;
+ }
+ return 0;
}
/*
@@ -62,14 +58,10 @@
static jint com_android_internal_os_ZygoteInit_setregid(
JNIEnv* env, jobject clazz, jint rgid, jint egid)
{
- int err;
-
- errno = 0;
- err = setregid(rgid, egid);
-
- //LOGI("setregid(%d,%d) err %d errno %d", rgid, egid, err, errno);
-
- return errno;
+ if (setregid(rgid, egid) < 0) {
+ return errno;
+ }
+ return 0;
}
/*
@@ -79,13 +71,10 @@
static jint com_android_internal_os_ZygoteInit_setpgid(
JNIEnv* env, jobject clazz, jint pid, jint pgid)
{
- int err;
-
- errno = 0;
-
- err = setpgid(pid, pgid);
-
- return errno;
+ if (setpgid(pid, pgid) < 0) {
+ return errno;
+ }
+ return 0;
}
/*
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1d43442..67adc28 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -540,7 +540,8 @@
android:description="@string/permdesc_sdcardWrite"
android:protectionLevel="dangerous" />
- <!-- Allows an application to write to internal media storage -->
+ <!-- Allows an application to write to internal media storage
+ @hide -->
<permission android:name="android.permission.WRITE_MEDIA_STORAGE"
android:permissionGroup="android.permission-group.STORAGE"
android:label="@string/permlab_mediaStorageWrite"
diff --git a/core/tests/coretests/src/android/util/JsonReaderTest.java b/core/tests/coretests/src/android/util/JsonReaderTest.java
index 216a772..b5c2c27 100644
--- a/core/tests/coretests/src/android/util/JsonReaderTest.java
+++ b/core/tests/coretests/src/android/util/JsonReaderTest.java
@@ -16,11 +16,10 @@
package android.util;
-import java.util.Arrays;
-import junit.framework.TestCase;
-
import java.io.IOException;
import java.io.StringReader;
+import java.util.Arrays;
+import junit.framework.TestCase;
public final class JsonReaderTest extends TestCase {
@@ -677,7 +676,7 @@
try {
reader.nextString();
fail();
- } catch (IOException expected) {
+ } catch (MalformedJsonException expected) {
}
}
@@ -811,4 +810,50 @@
reader.nextNull();
reader.endArray();
}
+
+ public void testStrictMultipleTopLevelValues() throws IOException {
+ JsonReader reader = new JsonReader(new StringReader("[] []"));
+ reader.beginArray();
+ reader.endArray();
+ try {
+ reader.peek();
+ fail();
+ } catch (IOException expected) {
+ }
+ }
+
+ public void testLenientMultipleTopLevelValues() throws IOException {
+ JsonReader reader = new JsonReader(new StringReader("[] true {}"));
+ reader.setLenient(true);
+ reader.beginArray();
+ reader.endArray();
+ assertEquals(true, reader.nextBoolean());
+ reader.beginObject();
+ reader.endObject();
+ assertEquals(JsonToken.END_DOCUMENT, reader.peek());
+ }
+
+ public void testStrictTopLevelValueType() {
+ JsonReader reader = new JsonReader(new StringReader("true"));
+ try {
+ reader.nextBoolean();
+ fail();
+ } catch (IOException expected) {
+ }
+ }
+
+ public void testLenientTopLevelValueType() throws IOException {
+ JsonReader reader = new JsonReader(new StringReader("true"));
+ reader.setLenient(true);
+ assertEquals(true, reader.nextBoolean());
+ }
+
+ public void testStrictNonExecutePrefix() {
+ JsonReader reader = new JsonReader(new StringReader(")]}'\n []"));
+ try {
+ reader.beginArray();
+ fail();
+ } catch (IOException expected) {
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/util/JsonWriterTest.java b/core/tests/coretests/src/android/util/JsonWriterTest.java
index fa84023..b29e2fd 100644
--- a/core/tests/coretests/src/android/util/JsonWriterTest.java
+++ b/core/tests/coretests/src/android/util/JsonWriterTest.java
@@ -16,10 +16,11 @@
package android.util;
-import junit.framework.TestCase;
-
import java.io.IOException;
import java.io.StringWriter;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import junit.framework.TestCase;
public final class JsonWriterTest extends TestCase {
@@ -119,7 +120,7 @@
JsonWriter jsonWriter = new JsonWriter(stringWriter);
jsonWriter.beginObject();
jsonWriter.name("a");
- jsonWriter.value(null);
+ jsonWriter.value((String) null);
jsonWriter.endObject();
assertEquals("{\"a\":null}", stringWriter.toString());
}
@@ -145,6 +146,27 @@
}
}
+ public void testNonFiniteBoxedDoubles() throws IOException {
+ StringWriter stringWriter = new StringWriter();
+ JsonWriter jsonWriter = new JsonWriter(stringWriter);
+ jsonWriter.beginArray();
+ try {
+ jsonWriter.value(new Double(Double.NaN));
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ jsonWriter.value(new Double(Double.NEGATIVE_INFINITY));
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ jsonWriter.value(new Double(Double.POSITIVE_INFINITY));
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
public void testDoubles() throws IOException {
StringWriter stringWriter = new StringWriter();
JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -189,6 +211,22 @@
+ "9223372036854775807]", stringWriter.toString());
}
+ public void testNumbers() throws IOException {
+ StringWriter stringWriter = new StringWriter();
+ JsonWriter jsonWriter = new JsonWriter(stringWriter);
+ jsonWriter.beginArray();
+ jsonWriter.value(new BigInteger("0"));
+ jsonWriter.value(new BigInteger("9223372036854775808"));
+ jsonWriter.value(new BigInteger("-9223372036854775809"));
+ jsonWriter.value(new BigDecimal("3.141592653589793238462643383"));
+ jsonWriter.endArray();
+ jsonWriter.close();
+ assertEquals("[0,"
+ + "9223372036854775808,"
+ + "-9223372036854775809,"
+ + "3.141592653589793238462643383]", stringWriter.toString());
+ }
+
public void testBooleans() throws IOException {
StringWriter stringWriter = new StringWriter();
JsonWriter jsonWriter = new JsonWriter(stringWriter);
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 66c6d81..184620b 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -85,8 +85,12 @@
@Override
protected void finalize() throws Throwable {
- if (mNativeCanvas != 0) {
- finalizer(mNativeCanvas);
+ try {
+ if (mNativeCanvas != 0) {
+ finalizer(mNativeCanvas);
+ }
+ } finally {
+ super.finalize();
}
}
}
@@ -137,6 +141,8 @@
* Returns null.
*
* @deprecated This method is not supported and should not be invoked.
+ *
+ * @hide
*/
@Deprecated
protected GL getGL() {
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 53962e1..7a47c3b 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -53,19 +53,6 @@
public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008;
- public enum CubemapLayout {
- VERTICAL_FACE_LIST (0),
- HORIZONTAL_FACE_LIST (1),
- VERTICAL_CROSS (2),
- HORIZONTAL_CROSS (3);
-
- int mID;
- CubemapLayout(int id) {
- mID = id;
- }
- }
-
-
public enum MipmapControl {
MIPMAP_NONE(0),
MIPMAP_FULL(1),
@@ -416,33 +403,41 @@
USAGE_GRAPHICS_TEXTURE);
}
+ /**
+ * Creates a cubemap allocation from a bitmap containing the
+ * horizontal list of cube faces. Each individual face must be
+ * the same size and power of 2
+ *
+ * @param rs
+ * @param b bitmap with cubemap faces layed out in the following
+ * format: right, left, top, bottom, front, back
+ * @param mips specifies desired mipmap behaviour for the cubemap
+ * @param usage bitfield specifying how the cubemap is utilized
+ *
+ **/
static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
MipmapControl mips,
- CubemapLayout layout,
int usage) {
rs.validate();
int height = b.getHeight();
int width = b.getWidth();
- if (layout != CubemapLayout.VERTICAL_FACE_LIST) {
- throw new RSIllegalArgumentException("Only vertical face list supported");
- }
- if (height % 6 != 0) {
+ if (width % 6 != 0) {
throw new RSIllegalArgumentException("Cubemap height must be multiple of 6");
}
- if (height / 6 != width) {
+ if (width / 6 != height) {
throw new RSIllegalArgumentException("Only square cobe map faces supported");
}
- boolean isPow2 = (width & (width - 1)) == 0;
+ boolean isPow2 = (height & (height - 1)) == 0;
if (!isPow2) {
throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
}
Element e = elementFromBitmap(rs, b);
Type.Builder tb = new Type.Builder(rs, e);
- tb.setX(width);
- tb.setY(width);
+ tb.setX(height);
+ tb.setY(height);
tb.setFaces(true);
tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
Type t = tb.create();
@@ -454,10 +449,9 @@
return new Allocation(id, rs, t, usage);
}
- static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
- CubemapLayout layout) {
+ static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b) {
return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
- layout, USAGE_GRAPHICS_TEXTURE);
+ USAGE_GRAPHICS_TEXTURE);
}
static public Allocation createFromBitmapResource(RenderScript rs,
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index ff92e08..cbc15d8 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -113,8 +113,11 @@
int mBufferCount;
// mCurrentTexture is the buffer slot index of the buffer that is currently
- // bound to the OpenGL texture. A value of INVALID_BUFFER_SLOT, indicating
- // that no buffer is currently bound to the texture.
+ // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
+ // indicating that no buffer slot is currently bound to the texture. Note,
+ // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
+ // that no buffer is bound to the texture. A call to setBufferCount will
+ // reset mCurrentTexture to INVALID_BUFFER_SLOT.
int mCurrentTexture;
// mLastQueued is the buffer slot index of the most recently enqueued buffer.
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index b3815c4..4599d70 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -101,6 +101,8 @@
List<sp<AMessage> > mDeferredQueue;
+ bool mSentFormat;
+
status_t allocateBuffersOnPort(OMX_U32 portIndex);
status_t freeBuffersOnPort(OMX_U32 portIndex);
status_t freeBuffer(OMX_U32 portIndex, size_t i);
@@ -145,6 +147,8 @@
void deferMessage(const sp<AMessage> &msg);
void processDeferredMessages();
+ void sendFormatChange();
+
DISALLOW_EVIL_CONSTRUCTORS(ACodec);
};
diff --git a/include/media/stagefright/foundation/AMessage.h b/include/media/stagefright/foundation/AMessage.h
index 91ec60c..72dc730 100644
--- a/include/media/stagefright/foundation/AMessage.h
+++ b/include/media/stagefright/foundation/AMessage.h
@@ -52,6 +52,10 @@
void setObject(const char *name, const sp<RefBase> &obj);
void setMessage(const char *name, const sp<AMessage> &obj);
+ void setRect(
+ const char *name,
+ int32_t left, int32_t top, int32_t right, int32_t bottom);
+
bool findInt32(const char *name, int32_t *value) const;
bool findInt64(const char *name, int64_t *value) const;
bool findSize(const char *name, size_t *value) const;
@@ -62,6 +66,10 @@
bool findObject(const char *name, sp<RefBase> *obj) const;
bool findMessage(const char *name, sp<AMessage> *obj) const;
+ bool findRect(
+ const char *name,
+ int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const;
+
void post(int64_t delayUs = 0);
// Performs a deep-copy of "this", contained messages are in turn "dup'ed".
@@ -85,11 +93,16 @@
kTypeString,
kTypeObject,
kTypeMessage,
+ kTypeRect,
};
uint32_t mWhat;
ALooper::handler_id mTarget;
+ struct Rect {
+ int32_t mLeft, mTop, mRight, mBottom;
+ };
+
struct Item {
union {
int32_t int32Value;
@@ -100,6 +113,7 @@
void *ptrValue;
RefBase *refValue;
AString *stringValue;
+ Rect rectValue;
} u;
const char *mName;
Type mType;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 9579996..11a48d9 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "SurfaceTexture"
+//#define LOG_NDEBUG 0
#define GL_GLEXT_PROTOTYPES
#define EGL_EGLEXT_PROTOTYPES
@@ -36,21 +37,32 @@
SurfaceTexture::SurfaceTexture(GLuint tex) :
mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT),
mLastQueued(INVALID_BUFFER_SLOT), mTexName(tex) {
+ LOGV("SurfaceTexture::SurfaceTexture");
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+ mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+ mSlots[i].mOwnedByClient = false;
+ }
}
SurfaceTexture::~SurfaceTexture() {
+ LOGV("SurfaceTexture::~SurfaceTexture");
freeAllBuffers();
}
status_t SurfaceTexture::setBufferCount(int bufferCount) {
+ LOGV("SurfaceTexture::setBufferCount");
Mutex::Autolock lock(mMutex);
freeAllBuffers();
mBufferCount = bufferCount;
+ mCurrentTexture = INVALID_BUFFER_SLOT;
+ mLastQueued = INVALID_BUFFER_SLOT;
return OK;
}
sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+ LOGV("SurfaceTexture::requestBuffer");
Mutex::Autolock lock(mMutex);
if (buf < 0 || mBufferCount <= buf) {
LOGE("requestBuffer: slot index out of range [0, %d]: %d",
@@ -75,6 +87,7 @@
}
status_t SurfaceTexture::dequeueBuffer(int *buf) {
+ LOGV("SurfaceTexture::dequeueBuffer");
Mutex::Autolock lock(mMutex);
int found = INVALID_BUFFER_SLOT;
for (int i = 0; i < mBufferCount; i++) {
@@ -92,6 +105,7 @@
}
status_t SurfaceTexture::queueBuffer(int buf) {
+ LOGV("SurfaceTexture::queueBuffer");
Mutex::Autolock lock(mMutex);
if (buf < 0 || mBufferCount <= buf) {
LOGE("queueBuffer: slot index out of range [0, %d]: %d",
@@ -111,6 +125,7 @@
}
void SurfaceTexture::cancelBuffer(int buf) {
+ LOGV("SurfaceTexture::cancelBuffer");
Mutex::Autolock lock(mMutex);
if (buf < 0 || mBufferCount <= buf) {
LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount,
@@ -124,18 +139,21 @@
}
status_t SurfaceTexture::setCrop(const Rect& reg) {
+ LOGV("SurfaceTexture::setCrop");
Mutex::Autolock lock(mMutex);
// XXX: How should we handle crops?
return OK;
}
status_t SurfaceTexture::setTransform(uint32_t transform) {
+ LOGV("SurfaceTexture::setTransform");
Mutex::Autolock lock(mMutex);
// XXX: How should we handle transforms?
return OK;
}
status_t SurfaceTexture::updateTexImage() {
+ LOGV("SurfaceTexture::updateTexImage");
Mutex::Autolock lock(mMutex);
// We always bind the texture even if we don't update its contents.
diff --git a/libs/rs/java/Samples/res/drawable/cubemap_test.png b/libs/rs/java/Samples/res/drawable/cubemap_test.png
index 75ad0a4..baf35d0 100644
--- a/libs/rs/java/Samples/res/drawable/cubemap_test.png
+++ b/libs/rs/java/Samples/res/drawable/cubemap_test.png
Binary files differ
diff --git a/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java b/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java
index 5430a13..1afcee3 100644
--- a/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java
+++ b/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java
@@ -22,7 +22,6 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.renderscript.*;
-import android.renderscript.Allocation.CubemapLayout;
import android.renderscript.Allocation.MipmapControl;
import android.renderscript.Program.TextureType;
import android.renderscript.ProgramStore.DepthFunc;
@@ -318,8 +317,7 @@
mTexTransparent = loadTextureARGB(R.drawable.leaf);
mTexChecker = loadTextureRGB(R.drawable.checker);
Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.cubemap_test);
- mTexCube = Allocation.createCubemapFromBitmap(mRS, b,
- Allocation.CubemapLayout.VERTICAL_FACE_LIST);
+ mTexCube = Allocation.createCubemapFromBitmap(mRS, b);
mScript.set_gTexTorus(mTexTorus);
mScript.set_gTexOpaque(mTexOpaque);
diff --git a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java
index cac105a..87840a7 100644
--- a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java
+++ b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java
@@ -22,7 +22,6 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.renderscript.*;
-import android.renderscript.Allocation.CubemapLayout;
import android.renderscript.Font.Style;
import android.renderscript.Program.TextureType;
import android.renderscript.ProgramStore.DepthFunc;
@@ -308,8 +307,7 @@
mTexTransparent = loadTextureARGB(R.drawable.leaf);
mTexChecker = loadTextureRGB(R.drawable.checker);
Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.cubemap_test);
- mTexCube = Allocation.createCubemapFromBitmap(mRS, b,
- Allocation.CubemapLayout.VERTICAL_FACE_LIST);
+ mTexCube = Allocation.createCubemapFromBitmap(mRS, b);
mScript.set_gTexTorus(mTexTorus);
mScript.set_gTexOpaque(mTexOpaque);
diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
index a50321e..fc3a065 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
@@ -66,6 +66,7 @@
unitTests.add(new UT_primitives(this, mRes, mCtx));
unitTests.add(new UT_rsdebug(this, mRes, mCtx));
+ unitTests.add(new UT_rstime(this, mRes, mCtx));
unitTests.add(new UT_rstypes(this, mRes, mCtx));
unitTests.add(new UT_fp_mad(this, mRes, mCtx));
/*
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_rstime.java b/libs/rs/java/tests/src/com/android/rs/test/UT_rstime.java
new file mode 100644
index 0000000..f302e1a
--- /dev/null
+++ b/libs/rs/java/tests/src/com/android/rs/test/UT_rstime.java
@@ -0,0 +1,40 @@
+/*
+ * 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.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_rstime extends UnitTest {
+ private Resources mRes;
+
+ protected UT_rstime(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "rsTime", ctx);
+ mRes = res;
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ ScriptC_rstime s = new ScriptC_rstime(pRS, mRes, R.raw.rstime);
+ pRS.setMessageHandler(mRsMessage);
+ s.invoke_test_rstime(0, 0);
+ pRS.finish();
+ waitForMessage();
+ pRS.destroy();
+ }
+}
diff --git a/libs/rs/java/tests/src/com/android/rs/test/rstime.rs b/libs/rs/java/tests/src/com/android/rs/test/rstime.rs
new file mode 100644
index 0000000..5e3e078
--- /dev/null
+++ b/libs/rs/java/tests/src/com/android/rs/test/rstime.rs
@@ -0,0 +1,52 @@
+#include "shared.rsh"
+
+static bool basic_test(uint32_t index) {
+ bool failed = false;
+
+ rs_time_t curTime = rsTime(0);
+ rs_tm tm;
+ rsDebug("curTime", curTime);
+
+ rsLocaltime(&tm, &curTime);
+
+ rsDebug("tm.tm_sec", tm.tm_sec);
+ rsDebug("tm.tm_min", tm.tm_min);
+ rsDebug("tm.tm_hour", tm.tm_hour);
+ rsDebug("tm.tm_mday", tm.tm_mday);
+ rsDebug("tm.tm_mon", tm.tm_mon);
+ rsDebug("tm.tm_year", tm.tm_year);
+ rsDebug("tm.tm_wday", tm.tm_wday);
+ rsDebug("tm.tm_yday", tm.tm_yday);
+ rsDebug("tm.tm_isdst", tm.tm_isdst);
+
+ // Test a specific time (only valid for PST localtime)
+ curTime = 1294438893;
+ rsLocaltime(&tm, &curTime);
+
+ _RS_ASSERT(tm.tm_sec == 33);
+ _RS_ASSERT(tm.tm_min == 21);
+ _RS_ASSERT(tm.tm_hour == 14);
+ _RS_ASSERT(tm.tm_mday == 7);
+ _RS_ASSERT(tm.tm_mon == 0);
+ _RS_ASSERT(tm.tm_year == 111);
+ _RS_ASSERT(tm.tm_wday == 5);
+ _RS_ASSERT(tm.tm_yday == 6);
+ _RS_ASSERT(tm.tm_isdst == 0);
+
+ return failed;
+}
+
+void test_rstime(uint32_t index, int test_num) {
+ bool failed = false;
+ failed |= basic_test(index);
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ rsDebug("rstime_test FAILED", -1);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ rsDebug("rstime_test PASSED", 0);
+ }
+}
+
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 3608e43..673ade2 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -831,16 +831,21 @@
return NULL;
}
+ uint32_t faceSize = t->getDimX();
+ uint32_t strideBytes = faceSize * 6 * t->getElementSizeBytes();
+ uint32_t copySize = faceSize * t->getElementSizeBytes();
+
uint8_t *sourcePtr = (uint8_t*)data;
for (uint32_t face = 0; face < 6; face ++) {
Adapter2D faceAdapter(rsc, texAlloc);
faceAdapter.setFace(face);
- size_t cpySize = t->getDimX() * t->getDimX() * t->getElementSizeBytes();
- memcpy(faceAdapter.getElement(0, 0), sourcePtr, cpySize);
+ for (uint32_t dI = 0; dI < faceSize; dI ++) {
+ memcpy(faceAdapter.getElement(0, dI), sourcePtr + strideBytes * dI, copySize);
+ }
// Move the data pointer to the next cube face
- sourcePtr += cpySize;
+ sourcePtr += copySize;
if (mips == RS_ALLOCATION_MIPMAP_FULL) {
Adapter2D adapt(rsc, texAlloc);
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 6a065b2..c5ee7ee 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -44,6 +44,7 @@
uint32_t Context::gThreadTLSKeyCount = 0;
uint32_t Context::gGLContextCount = 0;
pthread_mutex_t Context::gInitMutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t Context::gLibMutex = PTHREAD_MUTEX_INITIALIZER;
static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
if (returnVal != EGL_TRUE) {
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 3c402c4..df275bc 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -75,6 +75,8 @@
static uint32_t gThreadTLSKeyCount;
static uint32_t gGLContextCount;
static pthread_mutex_t gInitMutex;
+ // Library mutex (for providing thread-safe calls from the runtime)
+ static pthread_mutex_t gLibMutex;
struct ScriptTLSStruct {
Context * mContext;
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index f61b983..0b21669 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -100,70 +100,24 @@
// Time routines
//////////////////////////////////////////////////////////////////////////////
-static int32_t SC_second() {
+static time_t SC_time(time_t *timer) {
GET_TLS();
-
- time_t rawtime;
- time(&rawtime);
-
- struct tm *timeinfo;
- timeinfo = localtime(&rawtime);
- return timeinfo->tm_sec;
+ return time(timer);
}
-static int32_t SC_minute() {
+static tm* SC_localtime(tm *local, time_t *timer) {
GET_TLS();
+ if (!local) {
+ return NULL;
+ }
- time_t rawtime;
- time(&rawtime);
-
- struct tm *timeinfo;
- timeinfo = localtime(&rawtime);
- return timeinfo->tm_min;
-}
-
-static int32_t SC_hour() {
- GET_TLS();
-
- time_t rawtime;
- time(&rawtime);
-
- struct tm *timeinfo;
- timeinfo = localtime(&rawtime);
- return timeinfo->tm_hour;
-}
-
-static int32_t SC_day() {
- GET_TLS();
-
- time_t rawtime;
- time(&rawtime);
-
- struct tm *timeinfo;
- timeinfo = localtime(&rawtime);
- return timeinfo->tm_mday;
-}
-
-static int32_t SC_month() {
- GET_TLS();
-
- time_t rawtime;
- time(&rawtime);
-
- struct tm *timeinfo;
- timeinfo = localtime(&rawtime);
- return timeinfo->tm_mon;
-}
-
-static int32_t SC_year() {
- GET_TLS();
-
- time_t rawtime;
- time(&rawtime);
-
- struct tm *timeinfo;
- timeinfo = localtime(&rawtime);
- return timeinfo->tm_year;
+ // The native localtime function is not thread-safe, so we
+ // have to apply locking for proper behavior in RenderScript.
+ pthread_mutex_lock(&rsc->gLibMutex);
+ tm *tmp = localtime(timer);
+ memcpy(local, tmp, sizeof(*tmp));
+ pthread_mutex_unlock(&rsc->gLibMutex);
+ return local;
}
static int64_t SC_uptimeMillis() {
@@ -498,12 +452,8 @@
{ "_Z6rsFracf", (void *)&SC_frac, true },
// time
- { "_Z8rsSecondv", (void *)&SC_second, true },
- { "_Z8rsMinutev", (void *)&SC_minute, true },
- { "_Z6rsHourv", (void *)&SC_hour, true },
- { "_Z5rsDayv", (void *)&SC_day, true },
- { "_Z7rsMonthv", (void *)&SC_month, true },
- { "_Z6rsYearv", (void *)&SC_year, true },
+ { "_Z6rsTimePi", (void *)&SC_time, true },
+ { "_Z11rsLocaltimeP5rs_tmPKi", (void *)&SC_localtime, true },
{ "_Z14rsUptimeMillisv", (void*)&SC_uptimeMillis, true },
{ "_Z13rsUptimeNanosv", (void*)&SC_uptimeNanos, true },
{ "_Z7rsGetDtv", (void*)&SC_getDt, false },
diff --git a/libs/rs/scriptc/rs_math.rsh b/libs/rs/scriptc/rs_math.rsh
index d059997..a74c0e0 100644
--- a/libs/rs/scriptc/rs_math.rsh
+++ b/libs/rs/scriptc/rs_math.rsh
@@ -118,32 +118,6 @@
extern float __attribute__((overloadable))
rsFrac(float);
-// time
-extern int32_t __attribute__((overloadable))
- rsSecond(void);
-extern int32_t __attribute__((overloadable))
- rsMinute(void);
-extern int32_t __attribute__((overloadable))
- rsHour(void);
-extern int32_t __attribute__((overloadable))
- rsDay(void);
-extern int32_t __attribute__((overloadable))
- rsMonth(void);
-extern int32_t __attribute__((overloadable))
- rsYear(void);
-
-// Return the current system clock in milliseconds
-extern int64_t __attribute__((overloadable))
- rsUptimeMillis(void);
-
-// Return the current system clock in nanoseconds
-extern int64_t __attribute__((overloadable))
- rsUptimeNanos(void);
-
-// Return the time in seconds since function was last called in this script.
-extern float __attribute__((overloadable))
- rsGetDt(void);
-
// Send a message back to the client. Will not block and returns true
// if the message was sendable and false if the fifo was full.
// A message ID is required. Data payload is optional.
diff --git a/libs/rs/scriptc/rs_time.rsh b/libs/rs/scriptc/rs_time.rsh
new file mode 100644
index 0000000..f1abed63
--- /dev/null
+++ b/libs/rs/scriptc/rs_time.rsh
@@ -0,0 +1,36 @@
+#ifndef __RS_TIME_RSH__
+#define __RS_TIME_RSH__
+
+typedef int rs_time_t;
+
+typedef struct {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+} rs_tm;
+
+extern rs_time_t __attribute__((overloadable))
+ rsTime(rs_time_t *timer);
+
+extern rs_tm * __attribute__((overloadable))
+ rsLocaltime(rs_tm *local, const rs_time_t *timer);
+
+// Return the current system clock in milliseconds
+extern int64_t __attribute__((overloadable))
+ rsUptimeMillis(void);
+
+// Return the current system clock in nanoseconds
+extern int64_t __attribute__((overloadable))
+ rsUptimeNanos(void);
+
+// Return the time in seconds since function was last called in this script.
+extern float __attribute__((overloadable))
+ rsGetDt(void);
+
+#endif
diff --git a/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp b/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp
index 4d4cd8d..802d1fb 100644
--- a/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp
+++ b/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp
@@ -309,6 +309,18 @@
realNotify->setInt32("width", width);
realNotify->setInt32("height", height);
+
+ int32_t cropLeft, cropTop, cropRight, cropBottom;
+ if (!meta->findRect(
+ kKeyCropRect,
+ &cropLeft, &cropTop, &cropRight, &cropBottom)) {
+ cropLeft = 0;
+ cropTop = 0;
+ cropRight = width - 1;
+ cropBottom = height - 1;
+ }
+
+ realNotify->setRect("crop", cropLeft, cropTop, cropRight, cropBottom);
}
notify->post();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index e1b371e..7f534c0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -271,22 +271,43 @@
finishFlushIfPossible();
} else if (what == ACodec::kWhatOutputFormatChanged) {
- CHECK(audio);
+ if (audio) {
+ int32_t numChannels;
+ CHECK(codecRequest->findInt32("channel-count", &numChannels));
- int32_t numChannels;
- CHECK(codecRequest->findInt32("channel-count", &numChannels));
+ int32_t sampleRate;
+ CHECK(codecRequest->findInt32("sample-rate", &sampleRate));
- int32_t sampleRate;
- CHECK(codecRequest->findInt32("sample-rate", &sampleRate));
+ LOGV("Audio output format changed to %d Hz, %d channels",
+ sampleRate, numChannels);
- LOGV("Audio output format changed to %d Hz, %d channels",
- sampleRate, numChannels);
+ mAudioSink->close();
+ CHECK_EQ(mAudioSink->open(sampleRate, numChannels), (status_t)OK);
+ mAudioSink->start();
- mAudioSink->close();
- CHECK_EQ(mAudioSink->open(sampleRate, numChannels), (status_t)OK);
- mAudioSink->start();
+ mRenderer->signalAudioSinkChanged();
+ } else {
+ // video
- mRenderer->signalAudioSinkChanged();
+ int32_t width, height;
+ CHECK(codecRequest->findInt32("width", &width));
+ CHECK(codecRequest->findInt32("height", &height));
+
+ int32_t cropLeft, cropTop, cropRight, cropBottom;
+ CHECK(codecRequest->findRect(
+ "crop",
+ &cropLeft, &cropTop, &cropRight, &cropBottom));
+
+ LOGV("Video output format changed to %d x %d "
+ "(crop: %d, %d, %d, %d)",
+ width, height,
+ cropLeft, cropTop, cropRight, cropBottom);
+
+ notifyListener(
+ MEDIA_SET_VIDEO_SIZE,
+ cropRight - cropLeft + 1,
+ cropBottom - cropTop + 1);
+ }
} else if (what == ACodec::kWhatShutdownCompleted) {
LOGV("%s shutdown completed", audio ? "audio" : "video");
if (audio) {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 39e0c51..dfb4e00 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -299,7 +299,8 @@
////////////////////////////////////////////////////////////////////////////////
ACodec::ACodec()
- : mNode(NULL) {
+ : mNode(NULL),
+ mSentFormat(false) {
mUninitializedState = new UninitializedState(this);
mLoadedToIdleState = new LoadedToIdleState(this);
mIdleToExecutingState = new IdleToExecutingState(this);
@@ -980,6 +981,103 @@
}
}
+void ACodec::sendFormatChange() {
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatOutputFormatChanged);
+
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+ def.nPortIndex = kPortIndexOutput;
+
+ CHECK_EQ(mOMX->getParameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)),
+ (status_t)OK);
+
+ CHECK_EQ((int)def.eDir, (int)OMX_DirOutput);
+
+ switch (def.eDomain) {
+ case OMX_PortDomainVideo:
+ {
+ OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
+
+ notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RAW);
+ notify->setInt32("width", videoDef->nFrameWidth);
+ notify->setInt32("height", videoDef->nFrameHeight);
+
+ OMX_CONFIG_RECTTYPE rect;
+ InitOMXParams(&rect);
+ rect.nPortIndex = kPortIndexOutput;
+
+ if (mOMX->getConfig(
+ mNode, OMX_IndexConfigCommonOutputCrop,
+ &rect, sizeof(rect)) != OK) {
+ rect.nLeft = 0;
+ rect.nTop = 0;
+ rect.nWidth = videoDef->nFrameWidth;
+ rect.nHeight = videoDef->nFrameHeight;
+ }
+
+ CHECK_GE(rect.nLeft, 0);
+ CHECK_GE(rect.nTop, 0);
+ CHECK_GE(rect.nWidth, 0u);
+ CHECK_GE(rect.nHeight, 0u);
+ CHECK_LE(rect.nLeft + rect.nWidth - 1, videoDef->nFrameWidth);
+ CHECK_LE(rect.nTop + rect.nHeight - 1, videoDef->nFrameHeight);
+
+ notify->setRect(
+ "crop",
+ rect.nLeft,
+ rect.nTop,
+ rect.nLeft + rect.nWidth - 1,
+ rect.nTop + rect.nHeight - 1);
+
+ if (mNativeWindow != NULL) {
+ android_native_rect_t crop;
+ crop.left = rect.nLeft;
+ crop.top = rect.nTop;
+ crop.right = rect.nLeft + rect.nWidth - 1;
+ crop.bottom = rect.nTop + rect.nHeight - 1;
+
+ CHECK_EQ(0, native_window_set_crop(
+ mNativeWindow.get(), &crop));
+ }
+ break;
+ }
+
+ case OMX_PortDomainAudio:
+ {
+ OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
+ CHECK_EQ((int)audioDef->eEncoding, (int)OMX_AUDIO_CodingPCM);
+
+ OMX_AUDIO_PARAM_PCMMODETYPE params;
+ InitOMXParams(¶ms);
+ params.nPortIndex = kPortIndexOutput;
+
+ CHECK_EQ(mOMX->getParameter(
+ mNode, OMX_IndexParamAudioPcm,
+ ¶ms, sizeof(params)),
+ (status_t)OK);
+
+ CHECK(params.nChannels == 1 || params.bInterleaved);
+ CHECK_EQ(params.nBitPerSample, 16u);
+ CHECK_EQ((int)params.eNumData, (int)OMX_NumericalDataSigned);
+ CHECK_EQ((int)params.ePCMMode, (int)OMX_AUDIO_PCMModeLinear);
+
+ notify->setString("mime", MEDIA_MIMETYPE_AUDIO_RAW);
+ notify->setInt32("channel-count", params.nChannels);
+ notify->setInt32("sample-rate", params.nSamplingRate);
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+
+ notify->post();
+
+ mSentFormat = true;
+}
+
////////////////////////////////////////////////////////////////////////////////
ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
@@ -1305,6 +1403,10 @@
info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
}
} else {
+ if (!mCodec->mSentFormat) {
+ mCodec->sendFormatChange();
+ }
+
if (mCodec->mNativeWindow == NULL) {
info->mData->setRange(rangeOffset, rangeLength);
}
@@ -1717,7 +1819,7 @@
{
CHECK_EQ(data1, (OMX_U32)kPortIndexOutput);
- if (data2 == OMX_IndexParamPortDefinition) {
+ if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
CHECK_EQ(mCodec->mOMX->sendCommand(
mCodec->mNode,
OMX_CommandPortDisable, kPortIndexOutput),
@@ -1729,6 +1831,8 @@
}
mCodec->changeState(mCodec->mOutputPortSettingsChangedState);
+ } else if (data2 == OMX_IndexConfigCommonOutputCrop) {
+ mCodec->mSentFormat = false;
} else {
LOGV("[%s] OMX_EventPortSettingsChanged 0x%08lx",
mCodec->mComponentName.c_str(), data2);
@@ -1816,6 +1920,8 @@
} else if (data1 == (OMX_U32)OMX_CommandPortEnable) {
CHECK_EQ(data2, (OMX_U32)kPortIndexOutput);
+ mCodec->mSentFormat = false;
+
LOGV("[%s] Output port now reenabled.",
mCodec->mComponentName.c_str());
@@ -1869,6 +1975,8 @@
void ACodec::ExecutingToIdleState::stateEntered() {
LOGV("[%s] Now Executing->Idle", mCodec->mComponentName.c_str());
+
+ mCodec->mSentFormat = false;
}
bool ACodec::ExecutingToIdleState::onOMXEvent(
diff --git a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
index 0f08f6e..38778fb 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
@@ -132,7 +132,10 @@
}
MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
- CHECK_EQ(mode, actualMode);
+ if (mode != actualMode) {
+ PVCleanUpVideoDecoder(mHandle);
+ return UNKNOWN_ERROR;
+ }
PVSetPostProcType((VideoDecControls *) mHandle, 0);
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index 0e40acc..b592c3f 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -171,6 +171,18 @@
item->u.refValue = obj.get();
}
+void AMessage::setRect(
+ const char *name,
+ int32_t left, int32_t top, int32_t right, int32_t bottom) {
+ Item *item = allocateItem(name);
+ item->mType = kTypeRect;
+
+ item->u.rectValue.mLeft = left;
+ item->u.rectValue.mTop = top;
+ item->u.rectValue.mRight = right;
+ item->u.rectValue.mBottom = bottom;
+}
+
bool AMessage::findString(const char *name, AString *value) const {
const Item *item = findItem(name, kTypeString);
if (item) {
@@ -198,6 +210,22 @@
return false;
}
+bool AMessage::findRect(
+ const char *name,
+ int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const {
+ const Item *item = findItem(name, kTypeRect);
+ if (item == NULL) {
+ return false;
+ }
+
+ *left = item->u.rectValue.mLeft;
+ *top = item->u.rectValue.mTop;
+ *right = item->u.rectValue.mRight;
+ *bottom = item->u.rectValue.mBottom;
+
+ return true;
+}
+
void AMessage::post(int64_t delayUs) {
extern ALooperRoster gLooperRoster;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 2fcd04e..38eed50 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -26,9 +26,11 @@
import com.android.internal.view.BaseSurfaceHolder;
import com.android.internal.view.RootViewSurfaceTaker;
import com.android.internal.view.StandaloneActionMode;
+import com.android.internal.view.menu.ActionMenuView;
import com.android.internal.view.menu.ContextMenuBuilder;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuDialogHelper;
+import com.android.internal.view.menu.MenuItemImpl;
import com.android.internal.view.menu.MenuPopupHelper;
import com.android.internal.view.menu.MenuView;
import com.android.internal.view.menu.SubMenuBuilder;
@@ -881,12 +883,16 @@
// The window manager will give us a valid window token
new MenuDialogHelper(subMenu).show(null);
} else if (hasFeature(FEATURE_ACTION_BAR)) {
- mActionButtonPopup = new ActionButtonSubmenu(getContext(), subMenu);
- mActionButtonPopup.show();
- Callback cb = getCallback();
- if (cb != null) {
- cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
- }
+ mDecor.post(new Runnable() {
+ public void run() {
+ mActionButtonPopup = new ActionButtonSubmenu(getContext(), subMenu);
+ mActionButtonPopup.show();
+ Callback cb = getCallback();
+ if (cb != null) {
+ cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
+ }
+ }
+ });
}
return true;
@@ -3009,6 +3015,20 @@
public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) {
super(context, subMenu);
mSubMenu = subMenu;
+
+ MenuBuilder parentMenu = subMenu.getRootMenu();
+ MenuItemImpl item = (MenuItemImpl) subMenu.getItem();
+ if (!item.isActionButton()) {
+ // Give a reasonable anchor to nested submenus.
+ ActionMenuView amv = (ActionMenuView) parentMenu.getMenuView(
+ MenuBuilder.TYPE_ACTION_BUTTON, null);
+
+ View anchor = amv.getOverflowButton();
+ if (anchor == null) {
+ anchor = amv;
+ }
+ setAnchorView(anchor);
+ }
}
@Override
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index ae408fc..22dd804 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -144,6 +144,7 @@
// update the provider list.
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
mContext.registerReceiver(mBroadcastReceiver, filter);
@@ -643,6 +644,12 @@
}
boolean addProviderLocked(ResolveInfo ri) {
+ if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+ return false;
+ }
+ if (!ri.activityInfo.isEnabled()) {
+ return false;
+ }
Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName,
ri.activityInfo.name), ri);
if (p != null) {
@@ -1160,6 +1167,7 @@
}
} else {
boolean added = false;
+ boolean changed = false;
String pkgList[] = null;
if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
@@ -1178,14 +1186,16 @@
}
pkgList = new String[] { pkgName };
added = Intent.ACTION_PACKAGE_ADDED.equals(action);
+ changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
}
if (pkgList == null || pkgList.length == 0) {
return;
}
- if (added) {
+ if (added || changed) {
synchronized (mAppWidgetIds) {
Bundle extras = intent.getExtras();
- if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+ if (changed || (extras != null &&
+ extras.getBoolean(Intent.EXTRA_REPLACING, false))) {
for (String pkgName : pkgList) {
// The package was just upgraded
updateProvidersForPackageLocked(pkgName);
diff --git a/tests/CoreTests/android/core/HeapTest.java b/tests/CoreTests/android/core/HeapTest.java
index 6116f5e..98cb28a 100644
--- a/tests/CoreTests/android/core/HeapTest.java
+++ b/tests/CoreTests/android/core/HeapTest.java
@@ -540,94 +540,4 @@
objSize = (objSize * 4) / 5;
}
}
-
- // TODO: flaky test
- //@SmallTest
- public void testExternalOomeLarge() {
- /* Just shy of the typical max heap size so that it will actually
- * try to allocate it instead of short-circuiting.
- */
- final int HUGE_SIZE = (16 * 1024 * 1024 - 32);
-
- assertFalse(VMRuntime.getRuntime().trackExternalAllocation(HUGE_SIZE));
- }
-
- /**
- * "Allocates" external memory in progressively smaller chunks until there's
- * only roughly 16 bytes left.
- *
- * @return the number of bytes allocated
- */
- private long allocateMaxExternal() {
- final VMRuntime runtime = VMRuntime.getRuntime();
- final int SIXTEEN_MB = (16 * 1024 * 1024);
- final int MIN_SIZE = 16;
- long totalAllocated = 0;
- boolean success;
-
- success = false;
- try {
- /* "Allocate" progressively smaller chunks to "fill up" the entire heap.
- */
- int objSize = 1 * 1024 * 1024;
- while (objSize >= MIN_SIZE) {
- boolean sawFailure = false;
- for (int i = 0; i < SIXTEEN_MB / objSize; i++) {
- if (runtime.trackExternalAllocation(objSize)) {
- totalAllocated += objSize;
- } else {
- sawFailure = true;
- break;
- }
- }
-
- if (!sawFailure) {
- throw new RuntimeException("Test failed: " +
- "no failure while filling heap");
- }
-
- objSize = (objSize * 4) / 5;
- }
- success = true;
- } finally {
- if (!success) {
- runtime.trackExternalFree(totalAllocated);
- totalAllocated = 0;
- }
- }
- return totalAllocated;
- }
-
- public void xxtest00ExternalOomeSmall() {
- VMRuntime.getRuntime().trackExternalFree(allocateMaxExternal());
- }
-
- /**
- * Allocates as much external memory as possible, then allocates from the heap
- * until an OOME is caught.
- *
- * It's nice to run this test while the real heap is small, hence the '00' in its
- * name to force it to run before testOomeSmall().
- */
- public void xxtest00CombinedOomeSmall() {
- long totalAllocated = 0;
- boolean sawEx = false;
- try {
- totalAllocated = allocateMaxExternal();
- LinkedList<Object> list = new LinkedList<Object>();
- try {
- while (true) {
- list.add((Object)new byte[8192]);
- }
- /*NOTREACHED*/
- } catch (OutOfMemoryError oom) {
- sawEx = true;
- }
- } finally {
- VMRuntime.getRuntime().trackExternalFree(totalAllocated);
- }
- assertTrue(sawEx);
- }
-
- //TODO: test external alloc debugging/inspection
}
diff --git a/tests/StatusBar/AndroidManifest.xml b/tests/StatusBar/AndroidManifest.xml
index ddb756b..81442bf 100644
--- a/tests/StatusBar/AndroidManifest.xml
+++ b/tests/StatusBar/AndroidManifest.xml
@@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.STATUS_BAR" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.VIBRATE" />
+ <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
<application>
<activity android:name="StatusBarTest" android:label="_StatusBar">
diff --git a/tests/StatusBar/src/com/android/statusbartest/PowerTest.java b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
index 92d5bee..31a1cf5a 100644
--- a/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
@@ -26,6 +26,8 @@
import android.os.IPowerManager;
import android.widget.ListView;
import android.content.Intent;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.StatusBarManager;
@@ -66,6 +68,24 @@
return mTests;
}
private Test[] mTests = new Test[] {
+ new Test("Enable settings widget") {
+ public void run() {
+ PackageManager pm = getPackageManager();
+ pm.setComponentEnabledSetting(new ComponentName("com.android.settings",
+ "com.android.settings.widget.SettingsAppWidgetProvider"),
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+
+ }
+ },
+ new Test("Disable settings widget") {
+ public void run() {
+ PackageManager pm = getPackageManager();
+ pm.setComponentEnabledSetting(new ComponentName("com.android.settings",
+ "com.android.settings.widget.SettingsAppWidgetProvider"),
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
+
+ }
+ },
new Test("Enable proximity") {
public void run() {
mProx.acquire();