Merge "Fix for bug 2427961 android.security.tests.SystemKeyStoreTest:testBasicAccess is failing. Fixed issues in test."
diff --git a/Android.mk b/Android.mk
index ec6f96b..7bb5b5f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -33,6 +33,9 @@
# FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
LOCAL_SRC_FILES := $(call find-other-java-files,$(FRAMEWORKS_BASE_SUBDIRS))
+# EventLogTags files.
+LOCAL_SRC_FILES += core/java/android/content/EventLogTags.logtags
+
# The following filters out code we are temporarily not including at all.
# TODO: Move AWT and beans (and associated harmony code) back into libcore.
# TODO: Maybe remove javax.microedition entirely?
@@ -367,6 +370,8 @@
sample_dir := development/samples
+# the list here should match the list of samples included in the sdk samples package
+# (see development/build/sdk.atree)
web_docs_sample_code_flags := \
-hdf android.hasSamples 1 \
-samplecode $(sample_dir)/ApiDemos \
@@ -377,6 +382,8 @@
resources/samples/BusinessCard "Business Card" \
-samplecode $(sample_dir)/ContactManager \
resources/samples/ContactManager "Contact Manager" \
+ -samplecode $(sample_dir)/CubeLiveWallpaper \
+ resources/samples/CubeLiveWallpaper "Live Wallpaper" \
-samplecode $(sample_dir)/Home \
resources/samples/Home "Home" \
-samplecode $(sample_dir)/JetBoy \
@@ -387,6 +394,8 @@
resources/samples/MultiResolution "Multiple Resolutions" \
-samplecode $(sample_dir)/NotePad \
resources/samples/NotePad "Note Pad" \
+ -samplecode $(sample_dir)/SampleSyncAdapter \
+ resources/samples/SampleSyncAdapter "Sample Sync Adapter" \
-samplecode $(sample_dir)/SearchableDictionary \
resources/samples/SearchableDictionary "Searchable Dictionary" \
-samplecode $(sample_dir)/Snake \
diff --git a/api/current.xml b/api/current.xml
index 3da6b72..24b9c96 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -4585,6 +4585,17 @@
visibility="public"
>
</field>
+<field name="installLocation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843448"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="interpolator"
type="int"
transient="false"
@@ -6818,6 +6829,17 @@
visibility="public"
>
</field>
+<field name="safeMode"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843449"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="saveEnabled"
type="int"
transient="false"
@@ -24886,6 +24908,17 @@
visibility="public"
>
</field>
+<field name="INTENT_ACTION_SEARCH_SETTINGS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.search.action.SEARCH_SETTINGS""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="INTENT_ACTION_SEARCH_SETTINGS_CHANGED"
type="java.lang.String"
transient="false"
@@ -25311,8 +25344,8 @@
visibility="public"
>
</method>
-<method name="getSettingsDescription"
- return="java.lang.String"
+<method name="getSettingsDescriptionId"
+ return="int"
abstract="false"
native="false"
synchronized="false"
@@ -32785,6 +32818,30 @@
<parameter name="mode" type="int">
</parameter>
</method>
+<method name="getExternalCacheDir"
+ return="java.io.File"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getExternalFilesDir"
+ return="java.io.File"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="java.lang.String">
+</parameter>
+</method>
<method name="getFileStreamPath"
return="java.io.File"
abstract="true"
@@ -34293,6 +34350,30 @@
<parameter name="mode" type="int">
</parameter>
</method>
+<method name="getExternalCacheDir"
+ return="java.io.File"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getExternalFilesDir"
+ return="java.io.File"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="java.lang.String">
+</parameter>
+</method>
<method name="getFileStreamPath"
return="java.io.File"
abstract="false"
@@ -41806,6 +41887,17 @@
visibility="public"
>
</field>
+<field name="FLAG_VM_SAFE_MODE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16384"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="className"
type="java.lang.String"
transient="false"
@@ -66226,6 +66318,10 @@
</parameter>
<parameter name="format" type="int">
</parameter>
+<parameter name="width" type="int">
+</parameter>
+<parameter name="height" type="int">
+</parameter>
<parameter name="strides" type="int[]">
</parameter>
</constructor>
@@ -66239,17 +66335,24 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="width" type="int">
-</parameter>
-<parameter name="height" type="int">
-</parameter>
-<parameter name="offsets" type="int[]">
+<parameter name="rectangle" type="android.graphics.Rect">
</parameter>
<parameter name="quality" type="int">
</parameter>
<parameter name="stream" type="java.io.OutputStream">
</parameter>
</method>
+<method name="getHeight"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getStrides"
return="int[]"
abstract="false"
@@ -66261,6 +66364,17 @@
visibility="public"
>
</method>
+<method name="getWidth"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getYuvData"
return="byte[]"
abstract="false"
@@ -66283,25 +66397,6 @@
visibility="public"
>
</method>
-<method name="validate"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="format" type="int">
-</parameter>
-<parameter name="width" type="int">
-</parameter>
-<parameter name="height" type="int">
-</parameter>
-<parameter name="offsets" type="int[]">
-</parameter>
-</method>
</class>
</package>
<package name="android.graphics.drawable"
@@ -83028,6 +83123,25 @@
<parameter name="mimeType" type="java.lang.String">
</parameter>
</method>
+<method name="scanFile"
+ return="void"
+ 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="paths" type="java.lang.String[]">
+</parameter>
+<parameter name="mimeTypes" type="java.lang.String[]">
+</parameter>
+<parameter name="callback" type="android.media.MediaScannerConnection.ScanResultListener">
+</parameter>
+</method>
</class>
<interface name="MediaScannerConnection.MediaScannerConnectionClient"
abstract="true"
@@ -83036,6 +83150,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.media.MediaScannerConnection.ScanResultListener">
+</implements>
<method name="onMediaScannerConnected"
return="void"
abstract="true"
@@ -83063,6 +83179,29 @@
</parameter>
</method>
</interface>
+<interface name="MediaScannerConnection.ScanResultListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onScanCompleted"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+</interface>
<class name="Ringtone"
extends="java.lang.Object"
abstract="false"
@@ -86553,15 +86692,11 @@
type="android.net.SSLCertificateSocketFactory"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
-<parameter name="socketReadTimeoutForSslHandshake" type="int">
+<parameter name="handshakeTimeoutMillis" type="int">
</parameter>
-<exception name="KeyManagementException" type="java.security.KeyManagementException">
-</exception>
-<exception name="NoSuchAlgorithmException" type="java.security.NoSuchAlgorithmException">
-</exception>
</constructor>
<method name="createSocket"
return="java.net.Socket"
@@ -86573,13 +86708,13 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="socket" type="java.net.Socket">
+<parameter name="k" type="java.net.Socket">
</parameter>
-<parameter name="s" type="java.lang.String">
+<parameter name="host" type="java.lang.String">
</parameter>
-<parameter name="i" type="int">
+<parameter name="port" type="int">
</parameter>
-<parameter name="flag" type="boolean">
+<parameter name="close" type="boolean">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
@@ -86594,13 +86729,13 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="inaddr" type="java.net.InetAddress">
+<parameter name="addr" type="java.net.InetAddress">
</parameter>
-<parameter name="i" type="int">
+<parameter name="port" type="int">
</parameter>
-<parameter name="inaddr2" type="java.net.InetAddress">
+<parameter name="localAddr" type="java.net.InetAddress">
</parameter>
-<parameter name="j" type="int">
+<parameter name="localPort" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
@@ -86615,9 +86750,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="inaddr" type="java.net.InetAddress">
+<parameter name="addr" type="java.net.InetAddress">
</parameter>
-<parameter name="i" type="int">
+<parameter name="port" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
@@ -86632,13 +86767,13 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="s" type="java.lang.String">
+<parameter name="host" type="java.lang.String">
</parameter>
-<parameter name="i" type="int">
+<parameter name="port" type="int">
</parameter>
-<parameter name="inaddr" type="java.net.InetAddress">
+<parameter name="localAddr" type="java.net.InetAddress">
</parameter>
-<parameter name="j" type="int">
+<parameter name="localPort" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
@@ -86653,9 +86788,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="s" type="java.lang.String">
+<parameter name="host" type="java.lang.String">
</parameter>
-<parameter name="i" type="int">
+<parameter name="port" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
@@ -86670,7 +86805,22 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="socketReadTimeoutForSslHandshake" type="int">
+<parameter name="handshakeTimeoutMillis" type="int">
+</parameter>
+</method>
+<method name="getDefault"
+ return="javax.net.SocketFactory"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="handshakeTimeoutMillis" type="int">
+</parameter>
+<parameter name="cache" type="android.net.SSLSessionCache">
</parameter>
</method>
<method name="getDefaultCipherSuites"
@@ -86684,6 +86834,21 @@
visibility="public"
>
</method>
+<method name="getHttpSocketFactory"
+ return="org.apache.http.conn.ssl.SSLSocketFactory"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="handshakeTimeoutMillis" type="int">
+</parameter>
+<parameter name="cache" type="android.net.SSLSessionCache">
+</parameter>
+</method>
<method name="getSupportedCipherSuites"
return="java.lang.String[]"
abstract="false"
@@ -86696,6 +86861,37 @@
>
</method>
</class>
+<class name="SSLSessionCache"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SSLSessionCache"
+ type="android.net.SSLSessionCache"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dir" type="java.io.File">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</constructor>
+<constructor name="SSLSessionCache"
+ type="android.net.SSLSessionCache"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+</class>
<class name="TrafficStats"
extends="java.lang.Object"
abstract="false"
@@ -112670,6 +112866,19 @@
visibility="public"
>
</method>
+<method name="getExternalStoragePublicDirectory"
+ return="java.io.File"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="java.lang.String">
+</parameter>
+</method>
<method name="getExternalStorageState"
return="java.lang.String"
abstract="false"
@@ -112692,6 +112901,96 @@
visibility="public"
>
</method>
+<field name="DIRECTORY_ALARMS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DIRECTORY_DCIM"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DIRECTORY_DOWNLOADS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DIRECTORY_MOVIES"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DIRECTORY_MUSIC"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DIRECTORY_NOTIFICATIONS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DIRECTORY_PICTURES"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DIRECTORY_PODCASTS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DIRECTORY_RINGTONES"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MEDIA_BAD_REMOVAL"
type="java.lang.String"
transient="false"
@@ -135745,6 +136044,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_PARTIAL_RESULTS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.speech.extra.PARTIAL_RESULTS""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_PROMPT"
type="java.lang.String"
transient="false"
@@ -144243,6 +144553,30 @@
<parameter name="mode" type="int">
</parameter>
</method>
+<method name="getExternalCacheDir"
+ return="java.io.File"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getExternalFilesDir"
+ return="java.io.File"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="java.lang.String">
+</parameter>
+</method>
<method name="getFileStreamPath"
return="java.io.File"
abstract="false"
@@ -213818,6 +214152,17 @@
visibility="public"
>
</field>
+<field name="DEBUG_ENABLE_SAFEMODE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
</package>
<package name="java.awt.font"
diff --git a/common/Android.mk b/common/Android.mk
index 76091eb..5c5b01b 100644
--- a/common/Android.mk
+++ b/common/Android.mk
@@ -19,6 +19,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := android-common
+LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, java)
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/common/java/com/android/common/AndroidHttpClient.java b/common/java/com/android/common/AndroidHttpClient.java
index 99faf6e..4c65eb0 100644
--- a/common/java/com/android/common/AndroidHttpClient.java
+++ b/common/java/com/android/common/AndroidHttpClient.java
@@ -47,8 +47,6 @@
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.BasicHttpContext;
-import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
-import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
import java.io.IOException;
import java.io.InputStream;
@@ -59,11 +57,11 @@
import java.net.URI;
import java.security.KeyManagementException;
+import android.content.Context;
import android.content.ContentResolver;
+import android.net.SSLCertificateSocketFactory;
+import android.net.SSLSessionCache;
import android.os.Looper;
-import android.os.SystemProperties;
-import android.provider.Settings;
-import android.text.TextUtils;
import android.util.Log;
/**
@@ -76,11 +74,9 @@
* To retain cookies, simply add a cookie store to the HttpContext:</p>
*
* <pre>context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);</pre>
- *
- * {@hide}
*/
public final class AndroidHttpClient implements HttpClient {
-
+
// Gzip of data shorter than this probably won't be worthwhile
public static long DEFAULT_SYNC_MIN_GZIP_BYTES = 256;
@@ -101,12 +97,11 @@
/**
* Create a new HttpClient with reasonable defaults (which you can update).
*
- * @param userAgent to report in your HTTP requests.
- * @param sessionCache persistent session cache
+ * @param userAgent to report in your HTTP requests
+ * @param context to use for caching SSL sessions (may be null for no caching)
* @return AndroidHttpClient for you to use for all your requests.
*/
- public static AndroidHttpClient newInstance(String userAgent,
- SSLClientSessionCache sessionCache) {
+ public static AndroidHttpClient newInstance(String userAgent, Context context) {
HttpParams params = new BasicHttpParams();
// Turn off stale checking. Our connections break all the time anyway,
@@ -122,13 +117,16 @@
// often wants to re-POST after a redirect, which we must do ourselves.
HttpClientParams.setRedirecting(params, false);
+ // Use a session cache for SSL sockets
+ SSLSessionCache sessionCache = context == null ? null : new SSLSessionCache(context);
+
// Set the specified user agent and register standard protocols.
HttpProtocolParams.setUserAgent(params, userAgent);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http",
PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https",
- socketFactoryWithCache(sessionCache), 443));
+ SSLCertificateSocketFactory.getHttpSocketFactory(30 * 1000, sessionCache), 443));
ClientConnectionManager manager =
new ThreadSafeClientConnManager(params, schemeRegistry);
@@ -139,32 +137,6 @@
}
/**
- * Returns a socket factory backed by the given persistent session cache.
- *
- * @param sessionCache to retrieve sessions from, null for no cache
- */
- private static SSLSocketFactory socketFactoryWithCache(
- SSLClientSessionCache sessionCache) {
- if (sessionCache == null) {
- // Use the default factory which doesn't support persistent
- // caching.
- return SSLSocketFactory.getSocketFactory();
- }
-
- // Create a new SSL context backed by the cache.
- // TODO: Keep a weak *identity* hash map of caches to engines. In the
- // mean time, if we have two engines for the same cache, they'll still
- // share sessions but will have to do so through the persistent cache.
- SSLContextImpl sslContext = new SSLContextImpl();
- try {
- sslContext.engineInit(null, null, null, sessionCache, null);
- } catch (KeyManagementException e) {
- throw new AssertionError(e);
- }
- return new SSLSocketFactory(sslContext.engineGetSocketFactory());
- }
-
- /**
* Create a new HttpClient with reasonable defaults (which you can update).
* @param userAgent to report in your HTTP requests.
* @return AndroidHttpClient for you to use for all your requests.
@@ -339,9 +311,7 @@
* Shorter data will not be compressed.
*/
public static long getMinGzipSize(ContentResolver resolver) {
- return Settings.Secure.getLong(resolver,
- Settings.Secure.SYNC_MIN_GZIP_BYTES,
- DEFAULT_SYNC_MIN_GZIP_BYTES);
+ return DEFAULT_SYNC_MIN_GZIP_BYTES; // For now, this is just a constant.
}
/* cURL logging support. */
@@ -367,15 +337,6 @@
}
/**
- * Returns true if auth logging is turned on for this configuration. Can only be set on
- * insecure devices.
- */
- private boolean isAuthLoggable() {
- String secure = SystemProperties.get("ro.secure");
- return "0".equals(secure) && Log.isLoggable(tag + "-auth", level);
- }
-
- /**
* Prints a message using this configuration.
*/
private void println(String message) {
@@ -421,8 +382,9 @@
if (configuration != null
&& configuration.isLoggable()
&& request instanceof HttpUriRequest) {
- configuration.println(toCurl((HttpUriRequest) request,
- configuration.isAuthLoggable()));
+ // Never print auth token -- we used to check ro.secure=0 to
+ // enable that, but can't do that in unbundled code.
+ configuration.println(toCurl((HttpUriRequest) request, false));
}
}
}
diff --git a/common/java/com/android/common/ArrayListCursor.java b/common/java/com/android/common/ArrayListCursor.java
index cc1fe27..9ad5c36 100644
--- a/common/java/com/android/common/ArrayListCursor.java
+++ b/common/java/com/android/common/ArrayListCursor.java
@@ -115,11 +115,6 @@
}
@Override
- public boolean deleteRow() {
- return false;
- }
-
- @Override
public String[] getColumnNames() {
return mColumnNames;
}
diff --git a/common/java/com/android/common/Base64.java b/common/java/com/android/common/Base64.java
index 771875c..772d567 100644
--- a/common/java/com/android/common/Base64.java
+++ b/common/java/com/android/common/Base64.java
@@ -51,6 +51,10 @@
*/
public static final int WEB_SAFE = 8;
+ // --------------------------------------------------------
+ // decoding
+ // --------------------------------------------------------
+
/**
* Lookup table for turning bytes into their position in the
* Base64 alphabet.
@@ -155,18 +159,71 @@
* incorrect padding
*/
public static byte[] decode(byte[] input, int offset, int len, int flags) {
- int p = offset;
// Allocate space for the most data the input could represent.
// (It could contain less if it contains whitespace, etc.)
- byte[] output = new byte[len*3/4];
- len += offset;
+ DecoderState state = new DecoderState(flags, new byte[len*3/4]);
+
+ if (!decodeInternal(input, offset, len, state, true)) {
+ throw new IllegalArgumentException("bad base-64");
+ }
+
+ // Maybe we got lucky and allocated exactly enough output space.
+ if (state.op == state.output.length) {
+ return state.output;
+ }
+
+ // Need to shorten the array, so allocate a new one of the
+ // right size and copy.
+ byte[] temp = new byte[state.op];
+ System.arraycopy(state.output, 0, temp, 0, state.op);
+ return temp;
+ }
+
+ /* package */ static class DecoderState {
+ public byte[] output;
+ public int op;
+
+ public int state; // state number (0 to 6)
+ public int value;
+
+ final public int[] alphabet;
+
+ public DecoderState(int flags, byte[] output) {
+ this.output = output;
+
+ alphabet = ((flags & WEB_SAFE) == 0) ? DECODE : DECODE_WEBSAFE;
+ state = 0;
+ value = 0;
+ }
+ }
+
+ /**
+ * Decode another block of input data.
+ *
+ * @param dstate a DecoderState object whose (caller-provided)
+ * output array is big enough to hold all the decoded data.
+ * On return, dstate.op will be set to the length of the
+ * decoded data.
+ * @param finish true if this is the final call to decodeInternal
+ * with the given DecoderState object. Will finalize the
+ * decoder state and include any final bytes in the output.
+ *
+ * @return true if the state machine is still healthy. false if
+ * bad base-64 data has been detected in the input stream.
+ */
+
+ /* package */ static boolean decodeInternal(
+ byte[] input, int offset, int len, final DecoderState dstate, boolean finish) {
+ if (dstate.state == 6) return false;
+
+ int state = dstate.state;
+ int value = dstate.value;
+ final int[] decode = dstate.alphabet;
+ final byte[] output = dstate.output;
int op = 0;
- final int[] decode = ((flags & WEB_SAFE) == 0) ?
- DECODE : DECODE_WEBSAFE;
-
- int state = 0;
- int value = 0;
+ int p = offset;
+ len += offset;
while (p < len) {
@@ -207,6 +264,8 @@
// one more.
// State 5 is expecting no more data or padding characters
// in the input.
+ // State 6 is the error state; an error has been detected
+ // in the input and no future input can "fix" it.
int d = decode[input[p++] & 0xff];
@@ -216,7 +275,8 @@
value = d;
++state;
} else if (d != SKIP) {
- throw new IllegalArgumentException("bad base-64");
+ dstate.state = 6;
+ return false;
}
break;
@@ -225,7 +285,8 @@
value = (value << 6) | d;
++state;
} else if (d != SKIP) {
- throw new IllegalArgumentException("bad base-64");
+ dstate.state = 6;
+ return false;
}
break;
@@ -239,7 +300,8 @@
output[op++] = (byte) (value >> 4);
state = 4;
} else if (d != SKIP) {
- throw new IllegalArgumentException("bad base-64");
+ dstate.state = 6;
+ return false;
}
break;
@@ -260,7 +322,8 @@
op += 2;
state = 5;
} else if (d != SKIP) {
- throw new IllegalArgumentException("bad base-64");
+ dstate.state = 6;
+ return false;
}
break;
@@ -268,18 +331,30 @@
if (d == EQUALS) {
++state;
} else if (d != SKIP) {
- throw new IllegalArgumentException("bad base-64");
+ dstate.state = 6;
+ return false;
}
break;
case 5:
if (d != SKIP) {
- throw new IllegalArgumentException("bad base-64");
+ dstate.state = 6;
+ return false;
}
break;
}
}
+ if (!finish) {
+ // We're out of input, but a future call could provide
+ // more. Return the output we've produced on this call
+ // and save the current state of the state machine.
+ dstate.state = state;
+ dstate.value = value;
+ dstate.op = op;
+ return true;
+ }
+
// Done reading input. Now figure out where we are left in
// the state machine and finish up.
@@ -290,7 +365,8 @@
case 1:
// Read one extra input byte, which isn't enough to
// make another output byte. Illegal.
- throw new IllegalArgumentException("bad base-64");
+ dstate.state = 6;
+ return false;
case 2:
// Read two extra input bytes, enough to emit 1 more
// output byte. Fine.
@@ -305,25 +381,22 @@
break;
case 4:
// Read one padding '=' when we expected 2. Illegal.
- throw new IllegalArgumentException("bad base-64");
+ dstate.state = 6;
+ return false;
case 5:
// Read all the padding '='s we expected and no more.
// Fine.
break;
}
- // Maybe we got lucky and allocated exactly enough output space.
- if (op == output.length) {
- return output;
- }
-
- // Need to shorten the array, so allocate a new one of the
- // right size and copy.
- byte[] temp = new byte[op];
- System.arraycopy(output, 0, temp, 0, op);
- return temp;
+ dstate.op = op;
+ return true;
}
+ // --------------------------------------------------------
+ // encoding
+ // --------------------------------------------------------
+
/**
* Emit a new line every this many output tuples. Corresponds to
* a 76-character line length (the maximum allowable according to
@@ -416,17 +489,13 @@
* adheres to RFC 2045.
*/
public static byte[] encode(byte[] input, int offset, int len, int flags) {
- final boolean do_padding = (flags & NO_PADDING) == 0;
- final boolean do_newline = (flags & NO_WRAP) == 0;
- final boolean do_cr = (flags & CRLF) != 0;
-
- final byte[] encode = ((flags & WEB_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;
+ EncoderState state = new EncoderState(flags, null);
// Compute the exact length of the array we will produce.
int output_len = len / 3 * 4;
// Account for the tail of the data and the padding bytes, if any.
- if (do_padding) {
+ if (state.do_padding) {
if (len % 3 > 0) {
output_len += 4;
}
@@ -439,26 +508,107 @@
}
// Account for the newlines, if any.
- if (do_newline && len > 0) {
- output_len += (((len-1) / (3 * LINE_GROUPS)) + 1) * (do_cr ? 2 : 1);
+ if (state.do_newline && len > 0) {
+ output_len += (((len-1) / (3 * LINE_GROUPS)) + 1) * (state.do_cr ? 2 : 1);
}
- int op = 0;
- byte[] output = new byte[output_len];
+ state.output = new byte[output_len];
+ encodeInternal(input, offset, len, state, true);
- // The main loop, turning 3 input bytes into 4 output bytes on
- // each iteration.
- int count = do_newline ? LINE_GROUPS : -1;
+ assert state.op == output_len;
+
+ return state.output;
+ }
+
+ /* package */ static class EncoderState {
+ public byte[] output;
+ public int op;
+
+ final public byte[] tail;
+ public int tailLen;
+ public int count;
+
+ final public boolean do_padding;
+ final public boolean do_newline;
+ final public boolean do_cr;
+ final public byte[] alphabet;
+
+ public EncoderState(int flags, byte[] output) {
+ this.output = output;
+
+ do_padding = (flags & NO_PADDING) == 0;
+ do_newline = (flags & NO_WRAP) == 0;
+ do_cr = (flags & CRLF) != 0;
+ alphabet = ((flags & WEB_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;
+
+ tail = new byte[2];
+ tailLen = 0;
+
+ count = do_newline ? LINE_GROUPS : -1;
+ }
+ }
+
+ /**
+ * Encode another block of input data.
+ *
+ * @param estate an EncoderState object whose (caller-provided)
+ * output array is big enough to hold all the encoded data.
+ * On return, estate.op will be set to the length of the
+ * encoded data.
+ * @param finish true if this is the final call to encodeInternal
+ * with the given EncoderState object. Will finalize the
+ * encoder state and include any final bytes in the output.
+ */
+ static void encodeInternal(byte[] input, int offset, int len,
+ final EncoderState estate, boolean finish) {
+ final boolean do_cr = estate.do_cr;
+ final boolean do_newline = estate.do_newline;
+ final boolean do_padding = estate.do_padding;
+ final byte[] output = estate.output;
+
+ int op = 0;
+
int p = offset;
len += offset;
- while (p+3 <= len) {
- int v = ((input[p++] & 0xff) << 16) |
- ((input[p++] & 0xff) << 8) |
- (input[p++] & 0xff);
- output[op++] = encode[(v >> 18) & 0x3f];
- output[op++] = encode[(v >> 12) & 0x3f];
- output[op++] = encode[(v >> 6) & 0x3f];
- output[op++] = encode[v & 0x3f];
+ int v = -1;
+ int count = estate.count;
+
+ // First we need to concatenate the tail of the previous call
+ // with any input bytes available now and see if we can empty
+ // the tail.
+
+ switch (estate.tailLen) {
+ case 0:
+ // There was no tail.
+ break;
+
+ case 1:
+ if (p+2 <= len) {
+ // A 1-byte tail with at least 2 bytes of
+ // input available now.
+ v = ((estate.tail[0] & 0xff) << 16) |
+ ((input[p++] & 0xff) << 8) |
+ (input[p++] & 0xff);
+ estate.tailLen = 0;
+ };
+ break;
+
+ case 2:
+ if (p+1 <= len) {
+ // A 2-byte tail with at least 1 byte of input.
+ v = ((estate.tail[0] & 0xff) << 16) |
+ ((estate.tail[1] & 0xff) << 8) |
+ (input[p++] & 0xff);
+ estate.tailLen = 0;
+ }
+ break;
+ }
+
+ if (v != -1) {
+ output[op++] = estate.alphabet[(v >> 18) & 0x3f];
+ output[op++] = estate.alphabet[(v >> 12) & 0x3f];
+ output[op++] = estate.alphabet[(v >> 6) & 0x3f];
+ output[op++] = estate.alphabet[v & 0x3f];
if (--count == 0) {
if (do_cr) output[op++] = '\r';
output[op++] = '\n';
@@ -466,38 +616,82 @@
}
}
- // Finish up the tail of the input.
- if (p == len-1) {
- int v = (input[p] & 0xff) << 4;
- output[op++] = encode[(v >> 6) & 0x3f];
- output[op++] = encode[v & 0x3f];
- if (do_padding) {
- output[op++] = '=';
- output[op++] = '=';
- }
- if (do_newline) {
+ // At this point either there is no tail, or there are fewer
+ // than 3 bytes of input available.
+
+ // The main loop, turning 3 input bytes into 4 output bytes on
+ // each iteration.
+ while (p+3 <= len) {
+ v = ((input[p++] & 0xff) << 16) |
+ ((input[p++] & 0xff) << 8) |
+ (input[p++] & 0xff);
+ output[op++] = estate.alphabet[(v >> 18) & 0x3f];
+ output[op++] = estate.alphabet[(v >> 12) & 0x3f];
+ output[op++] = estate.alphabet[(v >> 6) & 0x3f];
+ output[op++] = estate.alphabet[v & 0x3f];
+ if (--count == 0) {
if (do_cr) output[op++] = '\r';
output[op++] = '\n';
+ count = LINE_GROUPS;
}
- } else if (p == len-2) {
- int v = ((input[p] & 0xff) << 10) | ((input[p+1] & 0xff) << 2);
- output[op++] = encode[(v >> 12) & 0x3f];
- output[op++] = encode[(v >> 6) & 0x3f];
- output[op++] = encode[v & 0x3f];
- if (do_padding) {
- output[op++] = '=';
- }
- if (do_newline) {
- if (do_cr) output[op++] = '\r';
- output[op++] = '\n';
- }
- } else if (do_newline && op > 0 && count != LINE_GROUPS) {
- if (do_cr) output[op++] = '\r';
- output[op++] = '\n';
}
- assert op == output.length;
- return output;
+ if (finish) {
+ // Finish up the tail of the input. Note that we need to
+ // consume any bytes in estate.tail before any bytes
+ // remaining in input; there should be at most two bytes
+ // total.
+
+ if (p-estate.tailLen == len-1) {
+ int t = 0;
+ v = ((estate.tailLen > 0 ? estate.tail[t++] : input[p++]) & 0xff) << 4;
+ estate.tailLen -= t;
+ output[op++] = estate.alphabet[(v >> 6) & 0x3f];
+ output[op++] = estate.alphabet[v & 0x3f];
+ if (do_padding) {
+ output[op++] = '=';
+ output[op++] = '=';
+ }
+ if (do_newline) {
+ if (do_cr) output[op++] = '\r';
+ output[op++] = '\n';
+ }
+ } else if (p-estate.tailLen == len-2) {
+ int t = 0;
+ v = (((estate.tailLen > 1 ? estate.tail[t++] : input[p++]) & 0xff) << 10) |
+ (((estate.tailLen > 0 ? estate.tail[t++] : input[p++]) & 0xff) << 2);
+ estate.tailLen -= t;
+ output[op++] = estate.alphabet[(v >> 12) & 0x3f];
+ output[op++] = estate.alphabet[(v >> 6) & 0x3f];
+ output[op++] = estate.alphabet[v & 0x3f];
+ if (do_padding) {
+ output[op++] = '=';
+ }
+ if (do_newline) {
+ if (do_cr) output[op++] = '\r';
+ output[op++] = '\n';
+ }
+ } else if (do_newline && op > 0 && count != LINE_GROUPS) {
+ if (do_cr) output[op++] = '\r';
+ output[op++] = '\n';
+ }
+
+ assert estate.tailLen == 0;
+ assert p == len;
+ } else {
+ // Save the leftovers in tail to be consumed on the next
+ // call to encodeInternal.
+
+ if (p == len-1) {
+ estate.tail[estate.tailLen++] = input[p];
+ } else if (p == len-2) {
+ estate.tail[estate.tailLen++] = input[p];
+ estate.tail[estate.tailLen++] = input[p+1];
+ }
+ }
+
+ estate.op = op;
+ estate.count = count;
}
private Base64() { } // don't instantiate
diff --git a/common/java/com/android/common/Base64OutputStream.java b/common/java/com/android/common/Base64OutputStream.java
new file mode 100644
index 0000000..7c37428
--- /dev/null
+++ b/common/java/com/android/common/Base64OutputStream.java
@@ -0,0 +1,147 @@
+/*
+ * 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.common;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An OutputStream that does either Base64 encoding or decoding on the
+ * data written to it, writing the resulting data to another
+ * OutputStream.
+ */
+public class Base64OutputStream extends FilterOutputStream {
+ private final boolean encode;
+ private final Base64.EncoderState estate;
+ private final Base64.DecoderState dstate;
+
+ private byte[] buffer = null;
+ private int bpos = 0;
+
+ private static byte[] EMPTY = new byte[0];
+
+ /**
+ * Performs Base64 encoding on the data written to the stream,
+ * writing the encoded data to another OutputStream.
+ *
+ * @param out the OutputStream to write the encoded data to
+ * @param flags bit flags for controlling the encoder; see the
+ * constants in {@link Base64}
+ */
+ public Base64OutputStream(OutputStream out, int flags) {
+ this(out, flags, true);
+ }
+
+ /**
+ * Performs Base64 encoding or decoding on the data written to the
+ * stream, writing the encoded/decoded data to another
+ * OutputStream.
+ *
+ * @param out the OutputStream to write the encoded data to
+ * @param flags bit flags for controlling the encoder; see the
+ * constants in {@link Base64}
+ * @param encode true to encode, false to decode
+ */
+ public Base64OutputStream(OutputStream out, int flags, boolean encode) {
+ super(out);
+ this.encode = encode;
+ if (encode) {
+ estate = new Base64.EncoderState(flags, null);
+ dstate = null;
+ } else {
+ estate = null;
+ dstate = new Base64.DecoderState(flags, null);
+ }
+ }
+
+ public void write(int b) throws IOException {
+ // To avoid invoking the encoder/decoder routines for single
+ // bytes, we buffer up calls to write(int) in an internal
+ // byte array to transform them into writes of decently-sized
+ // arrays.
+
+ if (buffer == null) {
+ buffer = new byte[1024];
+ }
+ if (bpos >= buffer.length) {
+ // internal buffer full; write it out.
+ internalWrite(buffer, 0, bpos, false);
+ bpos = 0;
+ }
+ buffer[bpos++] = (byte) b;
+ }
+
+ /**
+ * Flush any buffered data from calls to write(int). Needed
+ * before doing a write(byte[], int, int) or a close().
+ */
+ private void flushBuffer() throws IOException {
+ if (bpos > 0) {
+ internalWrite(buffer, 0, bpos, false);
+ bpos = 0;
+ }
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (len <= 0) return;
+ flushBuffer();
+ internalWrite(b, off, len, false);
+ }
+
+ public void close() throws IOException {
+ flushBuffer();
+ internalWrite(EMPTY, 0, 0, true);
+ out.close();
+ }
+
+ /**
+ * Write the given bytes to the encoder/decoder.
+ *
+ * @param finish true if this is the last batch of input, to cause
+ * encoder/decoder state to be finalized.
+ */
+ private void internalWrite(byte[] b, int off, int len, boolean finish) throws IOException {
+ if (encode) {
+ // len*8/5+10 is an overestimate of the most bytes the
+ // encoder can produce for len bytes of input.
+ estate.output = embiggen(estate.output, len*8/5+10);
+ Base64.encodeInternal(b, off, len, estate, finish);
+ out.write(estate.output, 0, estate.op);
+ } else {
+ // len*3/4+10 is an overestimate of the most bytes the
+ // decoder can produce for len bytes of input.
+ dstate.output = embiggen(dstate.output, len*3/4+10);
+ if (!Base64.decodeInternal(b, off, len, dstate, finish)) {
+ throw new IOException("bad base-64");
+ }
+ out.write(dstate.output, 0, dstate.op);
+ }
+ }
+
+ /**
+ * If b.length is at least len, return b. Otherwise return a new
+ * byte array of length len.
+ */
+ private byte[] embiggen(byte[] b, int len) {
+ if (b == null || b.length < len) {
+ return new byte[len];
+ } else {
+ return b;
+ }
+ }
+}
diff --git a/common/java/com/android/common/Patterns.java b/common/java/com/android/common/Patterns.java
index 24a18c0..71c3a5e 100644
--- a/common/java/com/android/common/Patterns.java
+++ b/common/java/com/android/common/Patterns.java
@@ -25,87 +25,87 @@
public class Patterns {
/**
* Regular expression pattern to match all IANA top-level domains.
- * List accurate as of 2007/06/15. List taken from:
+ * List accurate as of 2010/02/05. List taken from:
* http://data.iana.org/TLD/tlds-alpha-by-domain.txt
- * This pattern is auto-generated by //device/tools/make-iana-tld-pattern.py
+ * This pattern is auto-generated by development/tools/make-iana-tld-pattern.py
*/
- public static final Pattern TOP_LEVEL_DOMAIN
- = Pattern.compile(
- "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
- + "|(biz|b[abdefghijmnorstvwyz])"
- + "|(cat|com|coop|c[acdfghiklmnoruvxyz])"
- + "|d[ejkmoz]"
- + "|(edu|e[cegrstu])"
- + "|f[ijkmor]"
- + "|(gov|g[abdefghilmnpqrstuwy])"
- + "|h[kmnrtu]"
- + "|(info|int|i[delmnoqrst])"
- + "|(jobs|j[emop])"
- + "|k[eghimnrwyz]"
- + "|l[abcikrstuvy]"
- + "|(mil|mobi|museum|m[acdghklmnopqrstuvwxyz])"
- + "|(name|net|n[acefgilopruz])"
- + "|(org|om)"
- + "|(pro|p[aefghklmnrstwy])"
- + "|qa"
- + "|r[eouw]"
- + "|s[abcdeghijklmnortuvyz]"
- + "|(tel|travel|t[cdfghjklmnoprtvwz])"
- + "|u[agkmsyz]"
- + "|v[aceginu]"
- + "|w[fs]"
- + "|y[etu]"
- + "|z[amw])");
+ public static final Pattern TOP_LEVEL_DOMAIN = Pattern.compile(
+ "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+ + "|(biz|b[abdefghijmnorstvwyz])"
+ + "|(cat|com|coop|c[acdfghiklmnoruvxyz])"
+ + "|d[ejkmoz]"
+ + "|(edu|e[cegrstu])"
+ + "|f[ijkmor]"
+ + "|(gov|g[abdefghilmnpqrstuwy])"
+ + "|h[kmnrtu]"
+ + "|(info|int|i[delmnoqrst])"
+ + "|(jobs|j[emop])"
+ + "|k[eghimnprwyz]"
+ + "|l[abcikrstuvy]"
+ + "|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])"
+ + "|(name|net|n[acefgilopruz])"
+ + "|(org|om)"
+ + "|(pro|p[aefghklmnrstwy])"
+ + "|qa"
+ + "|r[eosuw]"
+ + "|s[abcdeghijklmnortuvyz]"
+ + "|(tel|travel|t[cdfghjklmnoprtvwz])"
+ + "|u[agksyz]"
+ + "|v[aceginu]"
+ + "|w[fs]"
+ + "|(xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)"
+ + "|y[etu]"
+ + "|z[amw])");
/**
* Regular expression pattern to match RFC 1738 URLs
- * List accurate as of 2007/06/15. List taken from:
+ * List accurate as of 2010/02/05. List taken from:
* http://data.iana.org/TLD/tlds-alpha-by-domain.txt
- * This pattern is auto-generated by //device/tools/make-iana-tld-pattern.py
+ * This pattern is auto-generated by development/tools/make-iana-tld-pattern.py
*/
- public static final Pattern WEB_URL
- = Pattern.compile(
- "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
- + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
- + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
- + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+" // named host
- + "(?:" // plus top level domain
- + "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
- + "|(?:biz|b[abdefghijmnorstvwyz])"
- + "|(?:cat|com|coop|c[acdfghiklmnoruvxyz])"
- + "|d[ejkmoz]"
- + "|(?:edu|e[cegrstu])"
- + "|f[ijkmor]"
- + "|(?:gov|g[abdefghilmnpqrstuwy])"
- + "|h[kmnrtu]"
- + "|(?:info|int|i[delmnoqrst])"
- + "|(?:jobs|j[emop])"
- + "|k[eghimnrwyz]"
- + "|l[abcikrstuvy]"
- + "|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])"
- + "|(?:name|net|n[acefgilopruz])"
- + "|(?:org|om)"
- + "|(?:pro|p[aefghklmnrstwy])"
- + "|qa"
- + "|r[eouw]"
- + "|s[abcdeghijklmnortuvyz]"
- + "|(?:tel|travel|t[cdfghjklmnoprtvwz])"
- + "|u[agkmsyz]"
- + "|v[aceginu]"
- + "|w[fs]"
- + "|y[etu]"
- + "|z[amw]))"
- + "|(?:(?:25[0-5]|2[0-4]" // or ip address
- + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]"
- + "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]"
- + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
- + "|[1-9][0-9]|[0-9])))"
- + "(?:\\:\\d{1,5})?)" // plus option port number
- + "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params
- + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
- + "(?:\\b|$)"); // and finally, a word boundary or end of
- // input. This is to stop foo.sure from
- // matching as foo.su
+ public static final Pattern WEB_URL = Pattern.compile(
+ "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+ + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+ + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
+ + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+" // named host
+ + "(?:" // plus top level domain
+ + "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+ + "|(?:biz|b[abdefghijmnorstvwyz])"
+ + "|(?:cat|com|coop|c[acdfghiklmnoruvxyz])"
+ + "|d[ejkmoz]"
+ + "|(?:edu|e[cegrstu])"
+ + "|f[ijkmor]"
+ + "|(?:gov|g[abdefghilmnpqrstuwy])"
+ + "|h[kmnrtu]"
+ + "|(?:info|int|i[delmnoqrst])"
+ + "|(?:jobs|j[emop])"
+ + "|k[eghimnprwyz]"
+ + "|l[abcikrstuvy]"
+ + "|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])"
+ + "|(?:name|net|n[acefgilopruz])"
+ + "|(?:org|om)"
+ + "|(?:pro|p[aefghklmnrstwy])"
+ + "|qa"
+ + "|r[eosuw]"
+ + "|s[abcdeghijklmnortuvyz]"
+ + "|(?:tel|travel|t[cdfghjklmnoprtvwz])"
+ + "|u[agksyz]"
+ + "|v[aceginu]"
+ + "|w[fs]"
+ + "|(?:xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)"
+ + "|y[etu]"
+ + "|z[amw]))"
+ + "|(?:(?:25[0-5]|2[0-4]" // or ip address
+ + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]"
+ + "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]"
+ + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
+ + "|[1-9][0-9]|[0-9])))"
+ + "(?:\\:\\d{1,5})?)" // plus option port number
+ + "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params
+ + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
+ + "(?:\\b|$)"); // and finally, a word boundary or end of
+ // input. This is to stop foo.sure from
+ // matching as foo.su
public static final Pattern IP_ADDRESS
= Pattern.compile(
diff --git a/common/java/com/android/common/Search.java b/common/java/com/android/common/Search.java
new file mode 100644
index 0000000..55fa6f5
--- /dev/null
+++ b/common/java/com/android/common/Search.java
@@ -0,0 +1,38 @@
+/*
+ * 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.common;
+
+/**
+ * Utilities for search implementations.
+ *
+ * @see android.app.SearchManager
+ */
+public class Search {
+
+ /**
+ * Key for the source identifier set by the application that launched a search intent.
+ * The identifier is search-source specific string. It can be used
+ * by the search provider to keep statistics of where searches are started from.
+ *
+ * The source identifier is stored in the {@link android.app.SearchManager#APP_DATA}
+ * Bundle in {@link android.content.Intent#ACTION_SEARCH} and
+ * {@link android.content.Intent#ACTION_WEB_SEARCH} intents.
+ */
+ public final static String SOURCE = "source";
+
+ private Search() { } // don't instantiate
+}
diff --git a/common/tests/src/com/android/common/Base64Test.java b/common/tests/src/com/android/common/Base64Test.java
index 5c9712a..e6b491f 100644
--- a/common/tests/src/com/android/common/Base64Test.java
+++ b/common/tests/src/com/android/common/Base64Test.java
@@ -18,6 +18,9 @@
import junit.framework.TestCase;
+import java.io.ByteArrayOutputStream;
+import java.util.Random;
+
public class Base64Test extends TestCase {
private static final String TAG = "B64Test";
@@ -55,6 +58,22 @@
}
}
+ /** Assert that actual equals the first len bytes of expected. */
+ private void assertEquals(byte[] expected, int len, byte[] actual, int alen) {
+ assertEquals(len, alen);
+ for (int i = 0; i < len; ++i) {
+ assertEquals(expected[i], actual[i]);
+ }
+ }
+
+ /** Assert that actual equals the first len bytes of expected. */
+ private void assertEquals(byte[] expected, byte[] actual) {
+ assertEquals(expected.length, actual.length);
+ for (int i = 0; i < expected.length; ++i) {
+ assertEquals(expected[i], actual[i]);
+ }
+ }
+
public void testDecodeExtraChars() throws Exception {
// padding 0
assertEquals("hello, world", decodeString("aGVsbG8sIHdvcmxk"));
@@ -205,4 +224,187 @@
assertEquals(out_60.replaceAll("\n", ""), encodeToString(in_60, Base64.NO_WRAP));
assertEquals(out_61.replaceAll("\n", ""), encodeToString(in_61, Base64.NO_WRAP));
}
+
+ /**
+ * Tests that Base64.encodeInternal does correct handling of the
+ * tail for each call.
+ */
+ public void testEncodeInternal() throws Exception {
+ byte[] input = { (byte) 0x61, (byte) 0x62, (byte) 0x63 };
+ byte[] output = new byte[100];
+
+ Base64.EncoderState state = new Base64.EncoderState(Base64.NO_PADDING | Base64.NO_WRAP,
+ output);
+
+ Base64.encodeInternal(input, 0, 3, state, false);
+ assertEquals("YWJj".getBytes(), 4, state.output, state.op);
+ assertEquals(0, state.tailLen);
+
+ Base64.encodeInternal(input, 0, 3, state, false);
+ assertEquals("YWJj".getBytes(), 4, state.output, state.op);
+ assertEquals(0, state.tailLen);
+
+ Base64.encodeInternal(input, 0, 1, state, false);
+ assertEquals(0, state.op);
+ assertEquals(1, state.tailLen);
+
+ Base64.encodeInternal(input, 0, 1, state, false);
+ assertEquals(0, state.op);
+ assertEquals(2, state.tailLen);
+
+ Base64.encodeInternal(input, 0, 1, state, false);
+ assertEquals("YWFh".getBytes(), 4, state.output, state.op);
+ assertEquals(0, state.tailLen);
+
+ Base64.encodeInternal(input, 0, 2, state, false);
+ assertEquals(0, state.op);
+ assertEquals(2, state.tailLen);
+
+ Base64.encodeInternal(input, 0, 2, state, false);
+ assertEquals("YWJh".getBytes(), 4, state.output, state.op);
+ assertEquals(1, state.tailLen);
+
+ Base64.encodeInternal(input, 0, 2, state, false);
+ assertEquals("YmFi".getBytes(), 4, state.output, state.op);
+ assertEquals(0, state.tailLen);
+
+ Base64.encodeInternal(input, 0, 1, state, true);
+ assertEquals("YQ".getBytes(), 2, state.output, state.op);
+ }
+
+ /**
+ * Tests that Base64OutputStream produces exactly the same results
+ * as calling Base64.encode/.decode on an in-memory array.
+ */
+ public void testOutputStream() throws Exception {
+ int[] flagses = { Base64.DEFAULT,
+ Base64.NO_PADDING,
+ Base64.NO_WRAP,
+ Base64.NO_PADDING | Base64.NO_WRAP,
+ Base64.CRLF,
+ Base64.WEB_SAFE };
+ int[] writeLengths = { -10, -5, -1, 0, 1, 1, 2, 2, 3, 10, 100 };
+ Random rng = new Random(32176L);
+
+ // input needs to be at least 1024 bytes to test filling up
+ // the write(int) buffer.
+ byte[] input = ("Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
+ "Quisque congue eleifend odio, eu ornare nulla facilisis eget. " +
+ "Integer eget elit diam, sit amet laoreet nibh. Quisque enim " +
+ "urna, pharetra vitae consequat eget, adipiscing eu ante. " +
+ "Aliquam venenatis arcu nec nibh imperdiet tempor. In id dui " +
+ "eget lorem aliquam rutrum vel vitae eros. In placerat ornare " +
+ "pretium. Curabitur non fringilla mi. Fusce ultricies, turpis " +
+ "eu ultrices suscipit, ligula nisi consectetur eros, dapibus " +
+ "aliquet dui sapien a turpis. Donec ultricies varius ligula, " +
+ "ut hendrerit arcu malesuada at. Praesent sed elit pretium " +
+ "eros luctus gravida. In ac dolor lorem. Cras condimentum " +
+ "convallis elementum. Phasellus vel felis in nulla ultrices " +
+ "venenatis. Nam non tortor non orci convallis convallis. " +
+ "Nam tristique lacinia hendrerit. Pellentesque habitant morbi " +
+ "tristique senectus et netus et malesuada fames ac turpis " +
+ "egestas. Vivamus cursus, nibh eu imperdiet porta, magna " +
+ "ipsum mollis mauris, sit amet fringilla mi nisl eu mi. " +
+ "Phasellus posuere, leo at ultricies vehicula, massa risus " +
+ "volutpat sapien, eu tincidunt diam ipsum eget nulla. Cras " +
+ "molestie dapibus commodo. Ut vel tellus at massa gravida " +
+ "semper non sed orci.").getBytes();
+
+ for (int f = 0; f < flagses.length; ++f) {
+ int flags = flagses[f];
+
+ byte[] expected = Base64.encode(input, flags);
+
+ ByteArrayOutputStream baos;
+ Base64OutputStream b64os;
+ byte[] actual;
+ int p;
+
+ // ----- test encoding ("input" -> "expected") -----
+
+ // one large write(byte[]) of the whole input
+ baos = new ByteArrayOutputStream();
+ b64os = new Base64OutputStream(baos, flags);
+ b64os.write(input);
+ b64os.close();
+ actual = baos.toByteArray();
+ assertEquals(expected, actual);
+
+ // many calls to write(int)
+ baos = new ByteArrayOutputStream();
+ b64os = new Base64OutputStream(baos, flags);
+ for (int i = 0; i < input.length; ++i) {
+ b64os.write(input[i]);
+ }
+ b64os.close();
+ actual = baos.toByteArray();
+ assertEquals(expected, actual);
+
+ // intermixed sequences of write(int) with
+ // write(byte[],int,int) of various lengths.
+ baos = new ByteArrayOutputStream();
+ b64os = new Base64OutputStream(baos, flags);
+ p = 0;
+ while (p < input.length) {
+ int l = writeLengths[rng.nextInt(writeLengths.length)];
+ l = Math.min(l, input.length-p);
+ if (l >= 0) {
+ b64os.write(input, p, l);
+ p += l;
+ } else {
+ l = Math.min(-l, input.length-p);
+ for (int i = 0; i < l; ++i) {
+ b64os.write(input[p+i]);
+ }
+ p += l;
+ }
+ }
+ b64os.close();
+ actual = baos.toByteArray();
+ assertEquals(expected, actual);
+
+ // ----- test decoding ("expected" -> "input") -----
+
+ // one large write(byte[]) of the whole input
+ baos = new ByteArrayOutputStream();
+ b64os = new Base64OutputStream(baos, flags, false);
+ b64os.write(expected);
+ b64os.close();
+ actual = baos.toByteArray();
+ assertEquals(input, actual);
+
+ // many calls to write(int)
+ baos = new ByteArrayOutputStream();
+ b64os = new Base64OutputStream(baos, flags, false);
+ for (int i = 0; i < expected.length; ++i) {
+ b64os.write(expected[i]);
+ }
+ b64os.close();
+ actual = baos.toByteArray();
+ assertEquals(input, actual);
+
+ // intermixed sequences of write(int) with
+ // write(byte[],int,int) of various lengths.
+ baos = new ByteArrayOutputStream();
+ b64os = new Base64OutputStream(baos, flags, false);
+ p = 0;
+ while (p < expected.length) {
+ int l = writeLengths[rng.nextInt(writeLengths.length)];
+ l = Math.min(l, expected.length-p);
+ if (l >= 0) {
+ b64os.write(expected, p, l);
+ p += l;
+ } else {
+ l = Math.min(-l, expected.length-p);
+ for (int i = 0; i < l; ++i) {
+ b64os.write(expected[p+i]);
+ }
+ p += l;
+ }
+ }
+ b64os.close();
+ actual = baos.toByteArray();
+ assertEquals(input, actual);
+ }
+ }
}
diff --git a/common/tests/src/com/android/common/PatternsTest.java b/common/tests/src/com/android/common/PatternsTest.java
index 7fabe5e..635601e 100644
--- a/common/tests/src/com/android/common/PatternsTest.java
+++ b/common/tests/src/com/android/common/PatternsTest.java
@@ -31,6 +31,20 @@
t = Patterns.TOP_LEVEL_DOMAIN.matcher("com").matches();
assertTrue("Missed valid TLD", t);
+ // One of the new top level domain.
+ t = Patterns.TOP_LEVEL_DOMAIN.matcher("me").matches();
+ assertTrue("Missed valid TLD", t);
+
+ // One of the new top level test domain.
+ t = Patterns.TOP_LEVEL_DOMAIN.matcher("xn--0zwm56d").matches();
+ assertTrue("Missed valid TLD", t);
+
+ t = Patterns.TOP_LEVEL_DOMAIN.matcher("mem").matches();
+ assertFalse("Matched invalid TLD!", t);
+
+ t = Patterns.TOP_LEVEL_DOMAIN.matcher("xn").matches();
+ assertFalse("Matched invalid TLD!", t);
+
t = Patterns.TOP_LEVEL_DOMAIN.matcher("xer").matches();
assertFalse("Matched invalid TLD!", t);
}
@@ -42,6 +56,18 @@
t = Patterns.WEB_URL.matcher("http://www.google.com").matches();
assertTrue("Valid URL", t);
+ // Google in one of the new top level domain.
+ t = Patterns.WEB_URL.matcher("http://www.google.me").matches();
+ assertTrue("Valid URL", t);
+ t = Patterns.WEB_URL.matcher("google.me").matches();
+ assertTrue("Valid URL", t);
+
+ // Test url in Chinese: http://xn--fsqu00a.xn--0zwm56d
+ t = Patterns.WEB_URL.matcher("http://xn--fsqu00a.xn--0zwm56d").matches();
+ assertTrue("Valid URL", t);
+ t = Patterns.WEB_URL.matcher("xn--fsqu00a.xn--0zwm56d").matches();
+ assertTrue("Valid URL", t);
+
t = Patterns.WEB_URL.matcher("ftp://www.example.com").matches();
assertFalse("Matched invalid protocol", t);
diff --git a/common/tools/make-iana-tld-pattern.py b/common/tools/make-iana-tld-pattern.py
new file mode 100755
index 0000000..ece4dcf
--- /dev/null
+++ b/common/tools/make-iana-tld-pattern.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+
+from urllib2 import urlopen
+
+TLD_PREFIX = r"""
+ /**
+ * Regular expression pattern to match all IANA top-level domains.
+ * List accurate as of 2010/02/05. List taken from:
+ * http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+ * This pattern is auto-generated by frameworks/base/common/tools/make-iana-tld-pattern.py
+ */
+ public static final Pattern TOP_LEVEL_DOMAIN = Pattern.compile(
+"""
+TLD_SUFFIX = '");'
+
+URL_PREFIX = r"""
+ /**
+ * Regular expression pattern to match RFC 1738 URLs
+ * List accurate as of 2010/02/05. List taken from:
+ * http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+ * This pattern is auto-generated by frameworkds/base/common/tools/make-iana-tld-pattern.py
+ */
+ public static final Pattern WEB_URL = Pattern.compile(
+ "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+ + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+ + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
+ + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+" // named host
+ + "(?:" // plus top level domain
+"""
+
+URL_SUFFIX = r"""
+ + "|(?:(?:25[0-5]|2[0-4]" // or ip address
+ + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]"
+ + "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]"
+ + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
+ + "|[1-9][0-9]|[0-9])))"
+ + "(?:\\:\\d{1,5})?)" // plus option port number
+ + "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params
+ + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
+ + "(?:\\b|$)"); // and finally, a word boundary or end of
+ // input. This is to stop foo.sure from
+ // matching as foo.su
+"""
+
+class Bucket:
+ def __init__(self, baseLetter):
+ self.base=baseLetter
+ self.words=[]
+ self.letters=[]
+
+ def dump(self, isWebUrl=False, isFirst=False, isLast=False):
+ if (len(self.words) == 0) and (len(self.letters) == 0):
+ return ''
+
+ self.words.sort()
+ self.letters.sort()
+
+ output = ' ';
+
+ if isFirst:
+ if isWebUrl:
+ output += '+ "'
+ else:
+ output += '"('
+ else:
+ output += '+ "|'
+
+ if len(self.words) != 0:
+ output += '('
+
+ if isWebUrl:
+ output += '?:'
+
+ firstWord = 1
+ for word in self.words:
+ if firstWord == 0:
+ output += '|'
+ firstWord = 0
+ for letter in word:
+ if letter == '-':
+ output += '\\\\' # escape the '-' character.
+ output += letter
+
+ if len(self.words) > 0 and len(self.letters) > 0:
+ output += '|'
+
+ if len(self.letters) == 1:
+ output += '%c%c' % (self.base, self.letters[0])
+ elif len(self.letters) > 0:
+ output += '%c[' % self.base
+
+ for letter in self.letters:
+ output += letter
+
+ output += ']'
+
+ if len(self.words) != 0:
+ output += ')'
+
+ if not isLast:
+ output += '"'
+ output += '\n'
+
+ return output;
+
+ def add(self, line):
+ length = len(line)
+
+ if line.startswith('#') or (length == 0):
+ return;
+
+ if length == 2:
+ self.letters.append(line[1:2])
+ else:
+ self.words.append(line)
+
+def getBucket(buckets, line):
+ letter = line[0]
+ bucket = buckets.get(letter)
+
+ if bucket is None:
+ bucket = Bucket(letter)
+ buckets[letter] = bucket
+
+ return bucket
+
+def makePattern(prefix, suffix, buckets, isWebUrl=False):
+ output = prefix
+
+ output += getBucket(buckets, 'a').dump(isFirst=True, isWebUrl=isWebUrl)
+
+ for letter in range(ord('b'), ord('z')):
+ output += getBucket(buckets, chr(letter)).dump(isWebUrl=isWebUrl)
+
+ output += getBucket(buckets, 'z').dump(isLast=True, isWebUrl=isWebUrl)
+
+ if isWebUrl:
+ output += '))"'
+ else:
+ output += ')'
+
+ output += suffix
+
+ print output
+
+if __name__ == "__main__":
+ f = urlopen('http://data.iana.org/TLD/tlds-alpha-by-domain.txt')
+ domains = f.readlines()
+ f.close()
+
+ buckets = {}
+
+ for domain in domains:
+ domain = domain.lower()
+
+ if len(domain) > 0:
+ getBucket(buckets, domain[0]).add(domain.strip())
+
+ makePattern(TLD_PREFIX, TLD_SUFFIX, buckets, isWebUrl=False)
+ makePattern(URL_PREFIX, URL_SUFFIX, buckets, isWebUrl=True)
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 652f405..be15ac9 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -27,6 +27,7 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.Parcelable;
+import android.os.Build;
import android.util.Log;
import java.io.IOException;
@@ -841,7 +842,9 @@
"calling this from your main thread can lead to deadlock");
Log.e(TAG, "calling this from your main thread can lead to deadlock and/or ANRs",
exception);
- throw exception;
+ if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.FROYO) {
+ throw exception;
+ }
}
}
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index e3ccd000..7850124 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -1788,7 +1788,7 @@
if (!permissionGranted && isDebuggableMonkeyBuild) {
// TODO: Skip this check when running automated tests. Replace this
// with a more general solution.
- Log.w(TAG, "no credentials permission for usage of " + account + ", "
+ Log.d(TAG, "no credentials permission for usage of " + account + ", "
+ authTokenType + " by uid " + Binder.getCallingUid()
+ " but ignoring since this is a monkey build");
return true;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4923eee..0a18fe5 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -52,6 +52,7 @@
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.PackageParser.Package;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
@@ -85,6 +86,7 @@
import android.os.Vibrator;
import android.os.FileUtils.FileStatus;
import android.os.storage.StorageManager;
+import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.ClipboardManager;
import android.util.AndroidRuntimeException;
@@ -197,9 +199,9 @@
private File mDatabasesDir;
private File mPreferencesDir;
private File mFilesDir;
-
-
private File mCacheDir;
+ private File mExternalFilesDir;
+ private File mExternalCacheDir;
private static long sInstanceCount = 0;
@@ -438,6 +440,38 @@
}
@Override
+ public File getExternalFilesDir(String type) {
+ synchronized (mSync) {
+ if (mExternalFilesDir == null) {
+ mExternalFilesDir = Environment.getExternalStorageAppFilesDirectory(
+ getPackageName());
+ }
+ if (!mExternalFilesDir.exists()) {
+ try {
+ (new File(Environment.getExternalStorageAndroidDataDir(),
+ ".nomedia")).createNewFile();
+ } catch (IOException e) {
+ }
+ if (!mExternalFilesDir.mkdirs()) {
+ Log.w(TAG, "Unable to create external files directory");
+ return null;
+ }
+ }
+ if (type == null) {
+ return mExternalFilesDir;
+ }
+ File dir = new File(mExternalFilesDir, type);
+ if (!dir.exists()) {
+ if (!dir.mkdirs()) {
+ Log.w(TAG, "Unable to create external media directory " + dir);
+ return null;
+ }
+ }
+ return dir;
+ }
+ }
+
+ @Override
public File getCacheDir() {
synchronized (mSync) {
if (mCacheDir == null) {
@@ -457,7 +491,28 @@
return mCacheDir;
}
-
+ @Override
+ public File getExternalCacheDir() {
+ synchronized (mSync) {
+ if (mExternalCacheDir == null) {
+ mExternalCacheDir = Environment.getExternalStorageAppCacheDirectory(
+ getPackageName());
+ }
+ if (!mExternalCacheDir.exists()) {
+ try {
+ (new File(Environment.getExternalStorageAndroidDataDir(),
+ ".nomedia")).createNewFile();
+ } catch (IOException e) {
+ }
+ if (!mExternalCacheDir.mkdirs()) {
+ Log.w(TAG, "Unable to create external cache directory");
+ return null;
+ }
+ }
+ return mExternalCacheDir;
+ }
+ }
+
@Override
public File getFileStreamPath(String name) {
return makeFilename(getFilesDir(), name);
@@ -2593,14 +2648,13 @@
// SD-to-internal app size threshold: currently set to 1 MB
private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024);
- @Override
- public int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI) {
+ public int recommendAppInstallLocation(Package pkg) {
// Initial implementation:
// Package size = code size + cache size + data size
// If code size > 1 MB, install on SD card.
// Else install on internal NAND flash, unless space on NAND is less than 10%
- if ((packageURI == null) || (appInfo == null)) {
+ if (pkg == null) {
return INSTALL_PARSE_FAILED_NOT_APK;
}
@@ -2616,44 +2670,71 @@
double pctNandFree = (double)availInternalFlashSize / (double)totalInternalFlashSize;
- final String archiveFilePath = packageURI.getPath();
+ final String archiveFilePath = pkg.mScanPath;
File apkFile = new File(archiveFilePath);
long pkgLen = apkFile.length();
+ boolean auto = true;
+ // To make final copy
+ long reqInstallSize = pkgLen;
+ // For dex files
+ long reqInternalSize = 1 * pkgLen;
+ boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD);
+ boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalFlashSize);
+ boolean fitsOnSd = (reqInstallSize < availSDSize) && intThresholdOk &&
+ (reqInternalSize < availInternalFlashSize);
+ boolean fitsOnInt = intThresholdOk && intAvailOk;
+
// Consider application flags preferences as well...
- boolean installOnlyOnSD = ((appInfo.flags & PackageManager.INSTALL_ON_SDCARD) != 0);
-
- // These are not very precise measures, but I guess it is hard to estimate sizes
- // before installing the package.
- // As a shortcut, I am assuming that the package fits on NAND flash if the available
- // space is three times that of the APK size. For SD, we only worry about the APK size.
- // Since packages are downloaded into SD, this might not even be necessary.
- boolean fitsOnSD = (pkgLen < availSDSize) && ((2 * pkgLen) < availInternalFlashSize);
- boolean fitsOnInternalFlash = ((pkgLen * 3) < availInternalFlashSize);
-
- // Does not fit, recommend no installation.
- if (!fitsOnSD && !fitsOnInternalFlash) {
- return INSTALL_FAILED_INSUFFICIENT_STORAGE;
- }
-
- if (pkgLen < (INSTALL_ON_SD_THRESHOLD) && fitsOnInternalFlash && !(installOnlyOnSD)) {
- // recommend internal NAND likely
- if (pctNandFree < LOW_NAND_FLASH_TRESHOLD) {
- // Low space on NAND (<10%) - install on SD
- return INSTALL_ON_SDCARD;
+ boolean installOnlyOnSd = (pkg.installLocation ==
+ PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
+ boolean installOnlyInternal = (pkg.installLocation ==
+ PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+ if (installOnlyInternal) {
+ // If set explicitly in manifest,
+ // let that override everything else
+ auto = false;
+ } else if (installOnlyOnSd){
+ // Check if this can be accommodated on the sdcard
+ if (fitsOnSd) {
+ auto = false;
}
- return INSTALL_ON_INTERNAL_FLASH;
} else {
- if (fitsOnSD) {
- // Recommend SD card
- return INSTALL_ON_SDCARD;
- } else if (fitsOnInternalFlash && (pctNandFree >= LOW_NAND_FLASH_TRESHOLD) &&
- !(installOnlyOnSD)) {
- return INSTALL_ON_INTERNAL_FLASH;
- } else {
- return INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ // Check if user option is enabled
+ boolean setInstallLoc = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.SET_INSTALL_LOCATION, 0) != 0;
+ if (setInstallLoc) {
+ // Pick user preference
+ int installPreference = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.DEFAULT_INSTALL_LOCATION,
+ PackageInfo.INSTALL_LOCATION_AUTO);
+ if (installPreference == 1) {
+ installOnlyInternal = true;
+ auto = false;
+ } else if (installPreference == 2) {
+ installOnlyOnSd = true;
+ auto = false;
+ }
}
}
+ if (!auto) {
+ if (installOnlyOnSd) {
+ return fitsOnSd ? INSTALL_ON_SDCARD : INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ } else if (installOnlyInternal){
+ // Check on internal flash
+ return fitsOnInt ? INSTALL_ON_INTERNAL_FLASH : INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ }
+ }
+ // Try to install internally
+ if (fitsOnInt) {
+ return INSTALL_ON_INTERNAL_FLASH;
+ }
+ // Try the sdcard now.
+ if (fitsOnSd) {
+ return INSTALL_ON_SDCARD;
+ }
+ // Return error code
+ return INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
private final ContextImpl mContext;
diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
index 804c8eb..3fd36a37 100644
--- a/core/java/android/app/IntentService.java
+++ b/core/java/android/app/IntentService.java
@@ -42,7 +42,7 @@
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_REDELIVER_INTENT} instead of
* {@link Service#START_NOT_STICKY}, so that if this service's process
- * is called while it is executing the Intent in
+ * is killed while it is executing the Intent in
* {@link #onHandleIntent(Intent)}, then when later restarted the same Intent
* will be re-delivered to it, to retry its execution.
*/
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 3046a2c..5a9a675 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1279,16 +1279,6 @@
public final static String APP_DATA = "app_data";
/**
- * Intent app_data bundle key: Use this key with the bundle from
- * {@link android.content.Intent#getBundleExtra
- * content.Intent.getBundleExtra(APP_DATA)} to obtain the source identifier
- * set by the activity that launched the search.
- *
- * @hide
- */
- public final static String SOURCE = "source";
-
- /**
* Intent extra data key: Use {@link android.content.Intent#getBundleExtra
* content.Intent.getBundleExtra(SEARCH_MODE)} to get the search mode used
* to launch the intent.
@@ -1638,8 +1628,6 @@
/**
* Intent action for starting the global search settings activity.
* The global search provider should handle this intent.
- *
- * @hide Pending API council approval.
*/
public final static String INTENT_ACTION_SEARCH_SETTINGS
= "android.search.action.SEARCH_SETTINGS";
diff --git a/core/java/android/app/SearchableInfo.java b/core/java/android/app/SearchableInfo.java
index 9897742..4496354 100644
--- a/core/java/android/app/SearchableInfo.java
+++ b/core/java/android/app/SearchableInfo.java
@@ -73,7 +73,7 @@
private final boolean mIncludeInGlobalSearch;
private final boolean mQueryAfterZeroResults;
private final boolean mAutoUrlDetect;
- private final String mSettingsDescription;
+ private final int mSettingsDescriptionId;
private final String mSuggestAuthority;
private final String mSuggestPath;
private final String mSuggestSelection;
@@ -155,11 +155,11 @@
}
/**
- * Gets the description to use for this source in system search settings, or null if
- * none has been specified.
+ * Gets the resource ID of the description string to use for this source in system search
+ * settings, or {@code 0} if none has been specified.
*/
- public String getSettingsDescription() {
- return mSettingsDescription;
+ public int getSettingsDescriptionId() {
+ return mSettingsDescriptionId;
}
/**
@@ -311,8 +311,8 @@
mAutoUrlDetect = a.getBoolean(
com.android.internal.R.styleable.Searchable_autoUrlDetect, false);
- mSettingsDescription = a.getString(
- com.android.internal.R.styleable.Searchable_searchSettingsDescription);
+ mSettingsDescriptionId = a.getResourceId(
+ com.android.internal.R.styleable.Searchable_searchSettingsDescription, 0);
mSuggestAuthority = a.getString(
com.android.internal.R.styleable.Searchable_searchSuggestAuthority);
mSuggestPath = a.getString(
@@ -495,7 +495,7 @@
+ ",suggestAuthority=" + searchable.getSuggestAuthority()
+ ",target=" + searchable.getSearchActivity().getClassName()
+ ",global=" + searchable.shouldIncludeInGlobalSearch()
- + ",settingsDescription=" + searchable.getSettingsDescription()
+ + ",settingsDescription=" + searchable.getSettingsDescriptionId()
+ ",threshold=" + searchable.getSuggestThreshold());
} else {
Log.d(LOG_TAG, "Checked " + activityInfo.name + ", no searchable meta-data");
@@ -746,7 +746,7 @@
mQueryAfterZeroResults = in.readInt() != 0;
mAutoUrlDetect = in.readInt() != 0;
- mSettingsDescription = in.readString();
+ mSettingsDescriptionId = in.readInt();
mSuggestAuthority = in.readString();
mSuggestPath = in.readString();
mSuggestSelection = in.readString();
@@ -784,7 +784,7 @@
dest.writeInt(mQueryAfterZeroResults ? 1 : 0);
dest.writeInt(mAutoUrlDetect ? 1 : 0);
- dest.writeString(mSettingsDescription);
+ dest.writeInt(mSettingsDescriptionId);
dest.writeString(mSuggestAuthority);
dest.writeString(mSuggestPath);
dest.writeString(mSuggestSelection);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index b33be23..bdbe341 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -16,6 +16,8 @@
package android.content;
+import android.accounts.Account;
+import android.app.ActivityThread;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
@@ -30,8 +32,8 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.TextUtils;
-import android.accounts.Account;
import android.util.Config;
+import android.util.EventLog;
import android.util.Log;
import java.io.File;
@@ -41,6 +43,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
+import java.util.Random;
import java.util.ArrayList;
@@ -163,6 +166,11 @@
/** @hide */
public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff;
+ // Always log queries which take 100ms+; shorter queries are
+ // sampled accordingly.
+ private static final int SLOW_THRESHOLD_MILLIS = 100;
+ private final Random mRandom = new Random(); // guarded by itself
+
public ContentResolver(Context context) {
mContext = context;
}
@@ -235,12 +243,15 @@
return null;
}
try {
+ long startTime = System.currentTimeMillis();
Cursor qCursor = provider.query(uri, projection, selection, selectionArgs, sortOrder);
- if(qCursor == null) {
+ if (qCursor == null) {
releaseProvider(provider);
return null;
}
- //Wrap the cursor object into CursorWrapperInner object
+ long durationMillis = System.currentTimeMillis() - startTime;
+ maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
+ // Wrap the cursor object into CursorWrapperInner object
return new CursorWrapperInner(qCursor, provider);
} catch (RemoteException e) {
releaseProvider(provider);
@@ -572,7 +583,11 @@
throw new IllegalArgumentException("Unknown URL " + url);
}
try {
- return provider.insert(url, values);
+ long startTime = System.currentTimeMillis();
+ Uri createdRow = provider.insert(url, values);
+ long durationMillis = System.currentTimeMillis() - startTime;
+ maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
+ return createdRow;
} catch (RemoteException e) {
return null;
} finally {
@@ -627,7 +642,11 @@
throw new IllegalArgumentException("Unknown URL " + url);
}
try {
- return provider.bulkInsert(url, values);
+ long startTime = System.currentTimeMillis();
+ int rowsCreated = provider.bulkInsert(url, values);
+ long durationMillis = System.currentTimeMillis() - startTime;
+ maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */);
+ return rowsCreated;
} catch (RemoteException e) {
return 0;
} finally {
@@ -652,7 +671,11 @@
throw new IllegalArgumentException("Unknown URL " + url);
}
try {
- return provider.delete(url, where, selectionArgs);
+ long startTime = System.currentTimeMillis();
+ int rowsDeleted = provider.delete(url, where, selectionArgs);
+ long durationMillis = System.currentTimeMillis() - startTime;
+ maybeLogUpdateToEventLog(durationMillis, url, "delete", where);
+ return rowsDeleted;
} catch (RemoteException e) {
return -1;
} finally {
@@ -680,7 +703,11 @@
throw new IllegalArgumentException("Unknown URI " + uri);
}
try {
- return provider.update(uri, values, where, selectionArgs);
+ long startTime = System.currentTimeMillis();
+ int rowsUpdated = provider.update(uri, values, where, selectionArgs);
+ long durationMillis = System.currentTimeMillis() - startTime;
+ maybeLogUpdateToEventLog(durationMillis, uri, "update", where);
+ return rowsUpdated;
} catch (RemoteException e) {
return -1;
} finally {
@@ -1217,6 +1244,78 @@
}
}
+ /**
+ * Returns sampling percentage for a given duration.
+ *
+ * Always returns at least 1%.
+ */
+ private int samplePercentForDuration(long durationMillis) {
+ if (durationMillis >= SLOW_THRESHOLD_MILLIS) {
+ return 100;
+ }
+ return (int) (100 * durationMillis / SLOW_THRESHOLD_MILLIS) + 1;
+ }
+
+ private void maybeLogQueryToEventLog(long durationMillis,
+ Uri uri, String[] projection,
+ String selection, String sortOrder) {
+ int samplePercent = samplePercentForDuration(durationMillis);
+ if (samplePercent < 100) {
+ synchronized (mRandom) {
+ if (mRandom.nextInt(100) >= samplePercent) {
+ return;
+ }
+ }
+ }
+
+ StringBuilder projectionBuffer = new StringBuilder(100);
+ if (projection != null) {
+ for (int i = 0; i < projection.length; ++i) {
+ // Note: not using a comma delimiter here, as the
+ // multiple arguments to EventLog.writeEvent later
+ // stringify with a comma delimiter, which would make
+ // parsing uglier later.
+ if (i != 0) projectionBuffer.append('/');
+ projectionBuffer.append(projection[i]);
+ }
+ }
+
+ // ActivityThread.currentPackageName() only returns non-null if the
+ // current thread is an application main thread. This parameter tells
+ // us whether an event loop is blocked, and if so, which app it is.
+ String blockingPackage = ActivityThread.currentPackageName();
+
+ EventLog.writeEvent(
+ EventLogTags.CONTENT_QUERY_OPERATION,
+ uri.toString(),
+ projectionBuffer.toString(),
+ selection != null ? selection : "",
+ sortOrder != null ? sortOrder : "",
+ durationMillis,
+ blockingPackage != null ? blockingPackage : "",
+ samplePercent);
+ }
+
+ private void maybeLogUpdateToEventLog(
+ long durationMillis, Uri uri, String operation, String selection) {
+ int samplePercent = samplePercentForDuration(durationMillis);
+ if (samplePercent < 100) {
+ synchronized (mRandom) {
+ if (mRandom.nextInt(100) >= samplePercent) {
+ return;
+ }
+ }
+ }
+ String blockingPackage = ActivityThread.currentPackageName();
+ EventLog.writeEvent(
+ EventLogTags.CONTENT_UPDATE_OPERATION,
+ uri.toString(),
+ operation,
+ selection != null ? selection : "",
+ durationMillis,
+ blockingPackage != null ? blockingPackage : "",
+ samplePercent);
+ }
private final class CursorWrapperInner extends CursorWrapper {
private IContentProvider mContentProvider;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index b4a0bf8..672e5f7 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -25,6 +25,7 @@
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
+import android.media.MediaScannerConnection.ScanResultListener;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -137,7 +138,28 @@
/**
* Return the context of the single, global Application object of the
- * current process.
+ * current process. This generally should only be used if you need a
+ * Context whose lifecycle is separate from the current context, that is
+ * tied to the lifetime of the process rather than the current component.
+ *
+ * <p>Consider for example how this interacts with
+ * {@ #registerReceiver(BroadcastReceiver, IntentFilter)}:
+ * <ul>
+ * <li> <p>If used from an Activity context, the receiver is being registered
+ * within that activity. This means that you are expected to unregister
+ * before the activity is done being destroyed; in fact if you do not do
+ * so, the framework will clean up your leaked registration as it removes
+ * the activity and log an error. Thus, if you use the Activity context
+ * to register a receiver that is static (global to the process, not
+ * associated with an Activity instance) then that registration will be
+ * removed on you at whatever point the activity you used is destroyed.
+ * <li> <p>If used from the Context returned here, the receiver is being
+ * registered with the global state associated with your application. Thus
+ * it will never be unregistered for you. This is necessary if the receiver
+ * is associated with static data, not a particular component. However
+ * using the ApplicationContext elsewhere can easily lead to serious leaks
+ * if you forget to unregister, unbind, etc.
+ * </ul>
*/
public abstract Context getApplicationContext();
@@ -393,11 +415,84 @@
public abstract File getFilesDir();
/**
+ * Returns the absolute path to the directory on the external filesystem
+ * (that is somewhere on {@link android.os.Environment#getExternalStorageDirectory()
+ * Environment.getExternalStorageDirectory()} where the application can
+ * place persistent files it owns. These files are private to the
+ * applications, and not typically visible to the user as media.
+ *
+ * <p>This is like {@link #getFilesDir()} in that these
+ * files will be deleted when the application is uninstalled, however there
+ * are some important differences:
+ *
+ * <ul>
+ * <li>External files are not always available: they will disappear if the
+ * user mounts the external storage on a computer or removes it. See the
+ * APIs on {@link android.os.Environment} for information in the storage state.
+ * <li>There is no security enforced with these files. All applications
+ * can read and write files placed here.
+ * </ul>
+ *
+ * <p>Here is an example of typical code to manipulate a file in
+ * an application's private storage:</p>
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
+ * private_file}
+ *
+ * <p>If you install a non-null <var>type</var> to this function, the returned
+ * file will be a path to a sub-directory of the given type. Though these files
+ * are not automatically scanned by the media scanner, you can explicitly
+ * add them to the media database with
+ * {@link android.media.MediaScannerConnection#scanFile(Context, String[], String[],
+ * ScanResultListener) MediaScannerConnection.scanFile}.
+ * Note that this is not the same as
+ * {@link android.os.Environment#getExternalStoragePublicDirectory
+ * Environment.getExternalStoragePublicDirectory()}, which provides
+ * directories of media shared by all applications. The
+ * directories returned here are
+ * owned by the application, and its contents will be removed when the
+ * application is uninstalled. Unlike
+ * {@link android.os.Environment#getExternalStoragePublicDirectory
+ * Environment.getExternalStoragePublicDirectory()}, the directory
+ * returned here will be automatically created for you.
+ *
+ * <p>Here is an example of typical code to manipulate a picture in
+ * an application's private storage and add it to the media database:</p>
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
+ * private_picture}
+ *
+ * @param type The type of files directory to return. May be null for
+ * the root of the files directory or one of
+ * the following Environment constants for a subdirectory:
+ * {@link android.os.Environment#DIRECTORY_MUSIC},
+ * {@link android.os.Environment#DIRECTORY_PODCASTS},
+ * {@link android.os.Environment#DIRECTORY_RINGTONES},
+ * {@link android.os.Environment#DIRECTORY_ALARMS},
+ * {@link android.os.Environment#DIRECTORY_NOTIFICATIONS},
+ * {@link android.os.Environment#DIRECTORY_PICTURES}, or
+ * {@link android.os.Environment#DIRECTORY_MOVIES}.
+ *
+ * @return Returns the path of the directory holding application files
+ * on external storage. Returns null if external storage is not currently
+ * mounted so it could not ensure the path exists; you will need to call
+ * this method again when it is available.
+ *
+ * @see #getFilesDir
+ */
+ public abstract File getExternalFilesDir(String type);
+
+ /**
* Returns the absolute path to the application specific cache directory
* on the filesystem. These files will be ones that get deleted first when the
- * device runs low on storage
+ * device runs low on storage.
* There is no guarantee when these files will be deleted.
- *
+ *
+ * <strong>Note: you should not <em>rely</em> on the system deleting these
+ * files for you; you should always have a reasonable maximum, such as 1 MB,
+ * for the amount of space you consume with cache files, and prune those
+ * files when exceeding that space.</strong>
+ *
* @return Returns the path of the directory holding application cache files.
*
* @see #openFileOutput
@@ -407,6 +502,37 @@
public abstract File getCacheDir();
/**
+ * Returns the absolute path to the directory on the external filesystem
+ * (that is somewhere on {@link android.os.Environment#getExternalStorageDirectory()
+ * Environment.getExternalStorageDirectory()} where the application can
+ * place cache files it owns.
+ *
+ * <p>This is like {@link #getCacheDir()} in that these
+ * files will be deleted when the application is uninstalled, however there
+ * are some important differences:
+ *
+ * <ul>
+ * <li>The platform does not monitor the space available in external storage,
+ * and thus will not automatically delete these files. Note that you should
+ * be managing the maximum space you will use for these anyway, just like
+ * with {@link #getCacheDir()}.
+ * <li>External files are not always available: they will disappear if the
+ * user mounts the external storage on a computer or removes it. See the
+ * APIs on {@link android.os.Environment} for information in the storage state.
+ * <li>There is no security enforced with these files. All applications
+ * can read and write files placed here.
+ * </ul>
+ *
+ * @return Returns the path of the directory holding application cache files
+ * on external storage. Returns null if external storage is not currently
+ * mounted so it could not ensure the path exists; you will need to call
+ * this method again when it is available.
+ *
+ * @see #getCacheDir
+ */
+ public abstract File getExternalCacheDir();
+
+ /**
* Returns an array of strings naming the private files associated with
* this Context's application package.
*
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 1b34320c..a447108 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -179,11 +179,21 @@
}
@Override
+ public File getExternalFilesDir(String type) {
+ return mBase.getExternalFilesDir(type);
+ }
+
+ @Override
public File getCacheDir() {
return mBase.getCacheDir();
}
@Override
+ public File getExternalCacheDir() {
+ return mBase.getExternalCacheDir();
+ }
+
+ @Override
public File getDir(String name, int mode) {
return mBase.getDir(name, mode);
}
diff --git a/core/java/android/content/EventLogTags.logtags b/core/java/android/content/EventLogTags.logtags
new file mode 100644
index 0000000..a815b95
--- /dev/null
+++ b/core/java/android/content/EventLogTags.logtags
@@ -0,0 +1,6 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package android.content;
+
+52002 content_query_operation (uri|3),(projection|3),(selection|3),(sortorder|3),(time|1|3),(blocking_package|3),(sample_percent|1|6)
+52003 content_update_operation (uri|3),(operation|3),(selection|3),(time|1|3),(blocking_package|3),(sample_percent|1|6)
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index ebb95e87..9ff2e25 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -1041,7 +1041,7 @@
continue;
}
- SyncStorageEngine.AuthorityInfo settings = mSyncStorageEngine.getAuthority(
+ SyncStorageEngine.AuthorityInfo settings = mSyncStorageEngine.getOrCreateAuthority(
account, syncAdapterType.type.authority);
SyncStatusInfo status = mSyncStorageEngine.getOrCreateSyncStatus(settings);
pw.print(" "); pw.print(settings.authority);
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index 07a1f46..fcb910d 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -632,9 +632,11 @@
}
}
- public AuthorityInfo getAuthority(Account account, String authority) {
+ public AuthorityInfo getOrCreateAuthority(Account account, String authority) {
synchronized (mAuthorities) {
- return getAuthorityLocked(account, authority, null);
+ return getOrCreateAuthorityLocked(account, authority,
+ -1 /* assign a new identifier if creating a new authority */,
+ true /* write to storage if this results in a change */);
}
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6591313..123d9b7 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -178,12 +178,20 @@
public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 1<<13;
/**
+ * Value for {@link #flags}: set to true if this application would like to
+ * request the VM to operate under the safe mode. Comes from
+ * {@link android.R.styleable#AndroidManifestApplication_safeMode
+ * android:safeMode} of the <application> tag.
+ */
+ public static final int FLAG_VM_SAFE_MODE = 1<<14;
+
+ /**
* Value for {@link #flags}: this is false if the application has set
* its android:allowBackup to false, true otherwise.
*
* {@hide}
*/
- public static final int FLAG_ALLOW_BACKUP = 1<<14;
+ public static final int FLAG_ALLOW_BACKUP = 1<<15;
/**
* Value for {@link #flags}: this is false if the application has set
@@ -194,7 +202,7 @@
*
* {@hide}
*/
- public static final int FLAG_KILL_AFTER_RESTORE = 1<<15;
+ public static final int FLAG_KILL_AFTER_RESTORE = 1<<16;
/**
* Value for {@link #flags}: this is true if the application has set
@@ -205,7 +213,7 @@
*
* {@hide}
*/
- public static final int FLAG_RESTORE_NEEDS_APPLICATION = 1<<16;
+ public static final int FLAG_RESTORE_NEEDS_APPLICATION = 1<<17;
/**
* Value for {@link #flags}: this is true if the application has set
@@ -215,7 +223,7 @@
*
* {@hide}
*/
- public static final int FLAG_NEVER_ENCRYPT = 1<<17;
+ public static final int FLAG_NEVER_ENCRYPT = 1<<18;
/**
* Value for {@link #flags}: Set to true if the application has been
@@ -223,7 +231,7 @@
*
* {@hide}
*/
- public static final int FLAG_FORWARD_LOCK = 1<<18;
+ public static final int FLAG_FORWARD_LOCK = 1<<19;
/**
* Value for {@link #flags}: Set to true if the application is
@@ -231,7 +239,7 @@
*
* {@hide}
*/
- public static final int FLAG_ON_SDCARD = 1<<19;
+ public static final int FLAG_ON_SDCARD = 1<<20;
/**
* Value for {@link #flags}: Set to true if the application is
@@ -239,7 +247,7 @@
*
* {@hide}
*/
- public static final int FLAG_NATIVE_DEBUGGABLE = 1<<20;
+ public static final int FLAG_NATIVE_DEBUGGABLE = 1<<21;
/**
* Flags associated with the application. Any combination of
@@ -250,7 +258,7 @@
* {@link #FLAG_TEST_ONLY}, {@link #FLAG_SUPPORTS_SMALL_SCREENS},
* {@link #FLAG_SUPPORTS_NORMAL_SCREENS},
* {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_RESIZEABLE_FOR_SCREENS},
- * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}
+ * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE}
*/
public int flags = 0;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 54db5e0..2c8c112 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -305,4 +305,5 @@
*/
void updateExternalMediaStatus(boolean mounted);
+ String nextPackageToClean(String lastPackage);
}
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index a8ce889..c003355 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -131,6 +131,34 @@
* The features that this application has said it requires.
*/
public FeatureInfo[] reqFeatures;
+
+ /**
+ * Constant corresponding to <code>auto</code> in
+ * the {@link android.R.attr#installLocation} attribute.
+ * @hide
+ */
+ public static final int INSTALL_LOCATION_AUTO = 0;
+ /**
+ * Constant corresponding to <code>internalOnly</code> in
+ * the {@link android.R.attr#installLocation} attribute.
+ * @hide
+ */
+ public static final int INSTALL_LOCATION_INTERNAL_ONLY = 1;
+ /**
+ * Constant corresponding to <code>preferExternal</code> in
+ * the {@link android.R.attr#installLocation} attribute.
+ * @hide
+ */
+ public static final int INSTALL_LOCATION_PREFER_EXTERNAL = 2;
+ /**
+ * The launch mode style requested by the activity. From the
+ * {@link android.R.attr#installLocation} attribute, one of
+ * {@link #INSTALL_LOCATION_AUTO},
+ * {@link #INSTALL_LOCATION_INTERNAL_ONLY},
+ * {@link #INSTALL_LOCATION_PREFER_EXTERNAL}
+ * @hide
+ */
+ public int installLocation = INSTALL_LOCATION_INTERNAL_ONLY;
public PackageInfo() {
}
@@ -168,6 +196,7 @@
dest.writeTypedArray(signatures, parcelableFlags);
dest.writeTypedArray(configPreferences, parcelableFlags);
dest.writeTypedArray(reqFeatures, parcelableFlags);
+ dest.writeInt(installLocation);
}
public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -202,5 +231,6 @@
signatures = source.createTypedArray(Signature.CREATOR);
configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR);
reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
+ installLocation = source.readInt();
}
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e3b1694..a61eab9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -622,11 +622,19 @@
public static final String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper";
/**
+ * Action to external storage service to clean out removed apps.
+ * @hide
+ */
+ public static final String ACTION_CLEAN_EXTERNAL_STORAGE
+ = "android.content.pm.CLEAN_EXTERNAL_STORAGE";
+
+ /**
* Determines best place to install an application: either SD or internal FLASH.
- * Tweak the algorithm for best results.
- * @param appInfo ApplicationInfo object of the package to install.
+ * If applications explicitly set installLocation in their manifest, that
+ * preference takes precedence. If not a recommended location is returned
+ * based on current available storage on internal flash or sdcard.
+ * @param pkgInfo PackageParser.Package of the package that is to be installed.
* Call utility method to obtain.
- * @param packageURI URI identifying the package's APK file.
* @return {@link INSTALL_ON_INTERNAL_FLASH} if it is best to install package on internal
* storage, {@link INSTALL_ON_SDCARD} if it is best to install package on SD card,
* and {@link INSTALL_FAILED_INSUFFICIENT_STORAGE} if insufficient space to safely install
@@ -635,7 +643,7 @@
* This recommendation does take into account the package's own flags.
* @hide
*/
- public abstract int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI);
+ public abstract int recommendAppInstallLocation(PackageParser.Package pkg);
/**
* Retrieve overall information about an application package that is
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b31df32..d97b3dd 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -177,6 +177,7 @@
pi.sharedUserId = p.mSharedUserId;
pi.sharedUserLabel = p.mSharedUserLabel;
pi.applicationInfo = p.applicationInfo;
+ pi.installLocation = p.installLocation;
if ((flags&PackageManager.GET_GIDS) != 0) {
pi.gids = gids;
}
@@ -709,6 +710,9 @@
com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
}
sa.recycle();
+ pkg.installLocation = sa.getInteger(
+ com.android.internal.R.styleable.AndroidManifest_installLocation,
+ PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
// Resource boolean are -1, so 1 means we don't know the value.
int supportsSmallScreens = 1;
@@ -1425,6 +1429,12 @@
}
if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestApplication_safeMode,
+ false)) {
+ ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE;
+ }
+
+ if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
true)) {
ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
@@ -2610,6 +2620,8 @@
*/
public ArrayList<FeatureInfo> reqFeatures = null;
+ public int installLocation;
+
public Package(String _name) {
packageName = _name;
applicationInfo.packageName = _name;
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 47c2cac..c0bff66 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -723,6 +723,7 @@
private static final String KEY_FOCAL_LENGTH = "focal-length";
private static final String KEY_HORIZONTAL_VIEW_ANGLE = "horizontal-view-angle";
private static final String KEY_VERTICAL_VIEW_ANGLE = "vertical-view-angle";
+ private static final String KEY_EXPOSURE_COMPENSATION = "exposure-compensation";
// Parameter key suffix for supported values.
private static final String SUPPORTED_VALUES_SUFFIX = "-values";
@@ -1051,7 +1052,8 @@
}
/**
- * Sets the rate at which preview frames are received.
+ * Sets the rate at which preview frames are received. This is the
+ * target frame rate. The actual frame rate depends on the driver.
*
* @param fps the frame rate (frames per second)
*/
@@ -1060,8 +1062,9 @@
}
/**
- * Returns the setting for the rate at which preview frames
- * are received.
+ * Returns the setting for the rate at which preview frames are
+ * received. This is the target frame rate. The actual frame rate
+ * depends on the driver.
*
* @return the frame rate setting (frames per second)
*/
@@ -1540,6 +1543,41 @@
}
/**
+ * Gets the current exposure compensation setting.
+ *
+ * @return the current exposure compensation value multiplied by 100.
+ * null if exposure compensation is not supported. Ex: -100
+ * means -1 EV. 130 means +1.3 EV.
+ * @hide
+ */
+ public int getExposureCompensation() {
+ return getInt(KEY_EXPOSURE_COMPENSATION);
+ }
+
+ /**
+ * Sets the exposure compensation.
+ *
+ * @param value exposure compensation multiplied by 100. Ex: -100 means
+ * -1 EV. 130 means +1.3 EV.
+ * @hide
+ */
+ public void setExposureCompensation(int value) {
+ set(KEY_EXPOSURE_COMPENSATION, value);
+ }
+
+ /**
+ * Gets the supported exposure compensation.
+ *
+ * @return a List of Integer constants. null if exposure compensation is
+ * not supported. The list is sorted from small to large. Ex:
+ * -100, -66, -33, 0, 33, 66, 100.
+ * @hide
+ */
+ public List<Integer> getSupportedExposureCompensation() {
+ return splitInt(get(KEY_EXPOSURE_COMPENSATION + SUPPORTED_VALUES_SUFFIX));
+ }
+
+ /**
* Gets current zoom value. This also works when smooth zoom is in
* progress.
*
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index e40f1b8..ed76b15 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -40,224 +40,174 @@
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
+import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
import org.apache.harmony.xnet.provider.jsse.SSLParameters;
/**
- * SSLSocketFactory that provides optional (on debug devices, only) skipping of ssl certificfate
- * chain validation and custom read timeouts used just when connecting to the server/negotiating
- * an ssl session.
- *
- * You can skip the ssl certificate checking at runtime by setting socket.relaxsslcheck=yes on
- * devices that do not have have ro.secure set.
+ * SSLSocketFactory implementation with several extra features:
+ * <ul>
+ * <li>Timeout specification for SSL handshake operations
+ * <li>Optional SSL session caching with {@link SSLSessionCache}
+ * <li>On development devices, "setprop socket.relaxsslcheck yes" bypasses all
+ * SSL certificate checks, for testing with development servers
+ * </ul>
+ * Note that the handshake timeout does not apply to actual connection.
+ * If you want a connection timeout as well, use {@link #createSocket()} and
+ * {@link Socket#connect(SocketAddress, int)}.
*/
public class SSLCertificateSocketFactory extends SSLSocketFactory {
+ private static final String TAG = "SSLCertificateSocketFactory";
- private static final String LOG_TAG = "SSLCertificateSocketFactory";
-
- private static final TrustManager[] TRUST_MANAGER = new TrustManager[] {
+ private static final TrustManager[] INSECURE_TRUST_MANAGER = new TrustManager[] {
new X509TrustManager() {
- public X509Certificate[] getAcceptedIssuers() {
- return null;
- }
-
- public void checkClientTrusted(X509Certificate[] certs,
- String authType) { }
-
- public void checkServerTrusted(X509Certificate[] certs,
- String authType) { }
+ public X509Certificate[] getAcceptedIssuers() { return null; }
+ public void checkClientTrusted(X509Certificate[] certs, String authType) { }
+ public void checkServerTrusted(X509Certificate[] certs, String authType) { }
}
};
- private final SSLSocketFactory mFactory;
+ private SSLSocketFactory mInsecureFactory = null;
+ private SSLSocketFactory mSecureFactory = null;
- private final int mSocketReadTimeoutForSslHandshake;
+ private final int mHandshakeTimeoutMillis;
+ private final SSLClientSessionCache mSessionCache;
- /**
- * Do not use this constructor (will be deprecated). Use {@link #getDefault(int)} instead.
- */
- public SSLCertificateSocketFactory(int socketReadTimeoutForSslHandshake)
- throws NoSuchAlgorithmException, KeyManagementException {
- this(socketReadTimeoutForSslHandshake, null /* cache */);
+ /** @deprecated Use {@link #getDefault(int)} instead. */
+ public SSLCertificateSocketFactory(int handshakeTimeoutMillis) {
+ this(handshakeTimeoutMillis, null /* cache */);
}
- private SSLCertificateSocketFactory(int socketReadTimeoutForSslHandshake,
- SSLClientSessionCache cache) throws NoSuchAlgorithmException, KeyManagementException {
- SSLContextImpl sslContext = new SSLContextImpl();
- sslContext.engineInit(null /* kms */,
- TRUST_MANAGER, new java.security.SecureRandom(),
- cache /* client cache */, null /* server cache */);
- this.mFactory = sslContext.engineGetSocketFactory();
- this.mSocketReadTimeoutForSslHandshake = socketReadTimeoutForSslHandshake;
+ private SSLCertificateSocketFactory(int handshakeTimeoutMillis, SSLSessionCache cache) {
+ mHandshakeTimeoutMillis = handshakeTimeoutMillis;
+ mSessionCache = cache == null ? null : cache.mSessionCache;
}
/**
* Returns a new instance of a socket factory using the specified socket read
* timeout while connecting with the server/negotiating an ssl session.
*
- * @param socketReadTimeoutForSslHandshake the socket read timeout used for performing
- * ssl handshake. The socket read timeout is set back to 0 after the handshake.
- * @return a new SocketFactory, or null on error
+ * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
+ * for none. The socket timeout is reset to 0 after the handshake.
+ * @return a new SocketFactory with the specified parameters
*/
- public static SocketFactory getDefault(int socketReadTimeoutForSslHandshake) {
- return getDefault(socketReadTimeoutForSslHandshake, null /* cache */);
+ public static SocketFactory getDefault(int handshakeTimeoutMillis) {
+ return getDefault(handshakeTimeoutMillis, null /* cache */);
}
/**
- * Returns a new instance of a socket factory using the specified socket read
- * timeout while connecting with the server/negotiating an ssl session.
+ * Returns a new instance of a socket factory using the specified socket
+ * read timeout while connecting with the server/negotiating an ssl session
* Persists ssl sessions using the provided {@link SSLClientSessionCache}.
*
- * @param socketReadTimeoutForSslHandshake the socket read timeout used for performing
- * ssl handshake. The socket read timeout is set back to 0 after the handshake.
- * @param cache The {@link SSLClientSessionCache} to use, if any.
- * @return a new SocketFactory, or null on error
+ * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
+ * for none. The socket timeout is reset to 0 after the handshake.
+ * @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
+ * @return a new SocketFactory with the specified parameters
+ */
+ public static SocketFactory getDefault(int handshakeTimeoutMillis, SSLSessionCache cache) {
+ return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache);
+ }
+
+ /**
+ * Returns a socket factory (also named SSLSocketFactory, but in a different
+ * namespace) for use with the Apache HTTP stack.
*
- * @hide
- */
- public static SocketFactory getDefault(int socketReadTimeoutForSslHandshake,
- SSLClientSessionCache cache) {
+ * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
+ * for none. The socket timeout is reset to 0 after the handshake.
+ * @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
+ * @return a new SocketFactory with the specified parameters
+ */
+ public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(
+ int handshakeTimeoutMillis,
+ SSLSessionCache cache) {
+ return new org.apache.http.conn.ssl.SSLSocketFactory(
+ new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache));
+ }
+
+ private SSLSocketFactory makeSocketFactory(TrustManager[] trustManagers) {
try {
- return new SSLCertificateSocketFactory(socketReadTimeoutForSslHandshake, cache);
- } catch (NoSuchAlgorithmException e) {
- Log.e(LOG_TAG,
- "SSLCertifcateSocketFactory.getDefault" +
- " NoSuchAlgorithmException " , e);
- return null;
+ SSLContextImpl sslContext = new SSLContextImpl();
+ sslContext.engineInit(null, trustManagers, null, mSessionCache, null);
+ return sslContext.engineGetSocketFactory();
} catch (KeyManagementException e) {
- Log.e(LOG_TAG,
- "SSLCertifcateSocketFactory.getDefault" +
- " KeyManagementException " , e);
- return null;
+ Log.wtf(TAG, e);
+ return (SSLSocketFactory) SSLSocketFactory.getDefault(); // Fallback
}
}
- private boolean hasValidCertificateChain(Certificate[] certs)
- throws IOException {
- boolean trusted = (certs != null && (certs.length > 0));
-
- if (trusted) {
- try {
- // the authtype we pass in doesn't actually matter
- SSLParameters.getDefaultTrustManager()
- .checkServerTrusted((X509Certificate[]) certs, "RSA");
- } catch (GeneralSecurityException e) {
- String exceptionMessage = e != null ? e.getMessage() : "none";
- if (Config.LOGD) {
- Log.d(LOG_TAG,"hasValidCertificateChain(): sec. exception: "
- + exceptionMessage);
- }
- trusted = false;
- }
- }
-
- return trusted;
- }
-
- private void validateSocket(SSLSocket sslSock, String destHost)
- throws IOException
- {
- if (Config.LOGV) {
- Log.v(LOG_TAG,"validateSocket() to host "+destHost);
- }
-
- String relaxSslCheck = SystemProperties.get("socket.relaxsslcheck");
- String secure = SystemProperties.get("ro.secure");
-
+ private synchronized SSLSocketFactory getDelegate() {
// only allow relaxing the ssl check on non-secure builds where the relaxation is
// specifically requested.
- if ("0".equals(secure) && "yes".equals(relaxSslCheck)) {
- if (Config.LOGD) {
- Log.d(LOG_TAG,"sys prop socket.relaxsslcheck is set," +
- " ignoring invalid certs");
+ if ("0".equals(SystemProperties.get("ro.secure")) &&
+ "yes".equals(SystemProperties.get("socket.relaxsslcheck"))) {
+ if (mInsecureFactory == null) {
+ Log.w(TAG, "*** BYPASSING SSL SECURITY CHECKS (socket.relaxsslcheck=yes) ***");
+ mInsecureFactory = makeSocketFactory(INSECURE_TRUST_MANAGER);
}
- return;
- }
-
- Certificate[] certs = null;
- sslSock.setUseClientMode(true);
- sslSock.startHandshake();
- certs = sslSock.getSession().getPeerCertificates();
-
- // check that the root certificate in the chain belongs to
- // a CA we trust
- if (certs == null) {
- Log.e(LOG_TAG,
- "[SSLCertificateSocketFactory] no trusted root CA");
- throw new IOException("no trusted root CA");
- }
-
- if (Config.LOGV) {
- Log.v(LOG_TAG,"validateSocket # certs = " +certs.length);
- }
-
- if (!hasValidCertificateChain(certs)) {
- if (Config.LOGD) {
- Log.d(LOG_TAG,"validateSocket(): certificate untrusted!");
+ return mInsecureFactory;
+ } else {
+ if (mSecureFactory == null) {
+ mSecureFactory = makeSocketFactory(null);
}
- throw new IOException("Certificate untrusted");
- }
-
- X509Certificate lastChainCert = (X509Certificate) certs[0];
-
- if (!DomainNameValidator.match(lastChainCert, destHost)) {
- if (Config.LOGD) {
- Log.d(LOG_TAG,"validateSocket(): domain name check failed");
- }
- throw new IOException("Domain Name check failed");
+ return mSecureFactory;
}
}
- public Socket createSocket(Socket socket, String s, int i, boolean flag)
- throws IOException
- {
- throw new IOException("Cannot validate certification without a hostname");
+ @Override
+ public Socket createSocket(Socket k, String host, int port, boolean close) throws IOException {
+ OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close);
+ s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+ return s;
}
- public Socket createSocket(InetAddress inaddr, int i, InetAddress inaddr2, int j)
- throws IOException
- {
- throw new IOException("Cannot validate certification without a hostname");
+ @Override
+ public Socket createSocket() throws IOException {
+ OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket();
+ s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+ return s;
}
- public Socket createSocket(InetAddress inaddr, int i) throws IOException {
- throw new IOException("Cannot validate certification without a hostname");
+ @Override
+ public Socket createSocket(InetAddress addr, int port, InetAddress localAddr, int localPort)
+ throws IOException {
+ OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
+ addr, port, localAddr, localPort);
+ s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+ return s;
}
- public Socket createSocket(String s, int i, InetAddress inaddr, int j) throws IOException {
- SSLSocket sslSock = (SSLSocket) mFactory.createSocket(s, i, inaddr, j);
-
- if (mSocketReadTimeoutForSslHandshake >= 0) {
- sslSock.setSoTimeout(mSocketReadTimeoutForSslHandshake);
- }
-
- validateSocket(sslSock,s);
- sslSock.setSoTimeout(0);
-
- return sslSock;
+ @Override
+ public Socket createSocket(InetAddress addr, int port) throws IOException {
+ OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port);
+ s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+ return s;
}
- public Socket createSocket(String s, int i) throws IOException {
- SSLSocket sslSock = (SSLSocket) mFactory.createSocket(s, i);
-
- if (mSocketReadTimeoutForSslHandshake >= 0) {
- sslSock.setSoTimeout(mSocketReadTimeoutForSslHandshake);
- }
-
- validateSocket(sslSock,s);
- sslSock.setSoTimeout(0);
-
- return sslSock;
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localAddr, int localPort)
+ throws IOException {
+ OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
+ host, port, localAddr, localPort);
+ s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+ return s;
}
+ @Override
+ public Socket createSocket(String host, int port) throws IOException {
+ OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port);
+ s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+ return s;
+ }
+
+ @Override
public String[] getDefaultCipherSuites() {
- return mFactory.getSupportedCipherSuites();
+ return getDelegate().getSupportedCipherSuites();
}
+ @Override
public String[] getSupportedCipherSuites() {
- return mFactory.getSupportedCipherSuites();
+ return getDelegate().getSupportedCipherSuites();
}
}
-
-
diff --git a/core/java/android/net/SSLSessionCache.java b/core/java/android/net/SSLSessionCache.java
new file mode 100644
index 0000000..4cbeb94
--- /dev/null
+++ b/core/java/android/net/SSLSessionCache.java
@@ -0,0 +1,68 @@
+/*
+ * 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.net;
+
+import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * File-based cache of established SSL sessions. When re-establishing a
+ * connection to the same server, using an SSL session cache can save some time,
+ * power, and bandwidth by skipping directly to an encrypted stream.
+ * This is a persistent cache which can span executions of the application.
+ *
+ * @see SSLCertificateSocketFactory
+ */
+public final class SSLSessionCache {
+ private static final String TAG = "SSLSessionCache";
+ /* package */ final SSLClientSessionCache mSessionCache;
+
+ /**
+ * Create a session cache using the specified directory.
+ * Individual session entries will be files within the directory.
+ * Multiple instances for the same directory share data internally.
+ *
+ * @param dir to store session files in (created if necessary)
+ * @throws IOException if the cache can't be opened
+ */
+ public SSLSessionCache(File dir) throws IOException {
+ mSessionCache = FileClientSessionCache.usingDirectory(dir);
+ }
+
+ /**
+ * Create a session cache at the default location for this app.
+ * Multiple instances share data internally.
+ *
+ * @param context for the application
+ */
+ public SSLSessionCache(Context context) {
+ File dir = context.getDir("sslcache", Context.MODE_PRIVATE);
+ SSLClientSessionCache cache = null;
+ try {
+ cache = FileClientSessionCache.usingDirectory(dir);
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to create SSL session cache in " + dir, e);
+ }
+ mSessionCache = cache;
+ }
+}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index ef1f3be..a9831aa 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -91,6 +91,14 @@
private static final File EXTERNAL_STORAGE_DIRECTORY
= getDirectory("EXTERNAL_STORAGE", "/sdcard");
+ private static final File EXTERNAL_STORAGE_ANDROID_DATA_DIRECTORY
+ = new File (new File(getDirectory("EXTERNAL_STORAGE", "/sdcard"),
+ "Android"), "data");
+
+ private static final File EXTERNAL_STORAGE_ANDROID_MEDIA_DIRECTORY
+ = new File (new File(getDirectory("EXTERNAL_STORAGE", "/sdcard"),
+ "Android"), "media");
+
private static final File DOWNLOAD_CACHE_DIRECTORY
= getDirectory("DOWNLOAD_CACHE", "/cache");
@@ -102,13 +110,183 @@
}
/**
- * Gets the Android external storage directory.
+ * Gets the Android external storage directory. This directory may not
+ * currently be accessible if it has been mounted by the user on their
+ * computer, has been removed from the device, or some other problem has
+ * happened. You can determine its current state with
+ * {@link #getExternalStorageState()}.
+ *
+ * <p>Here is an example of typical code to monitor the state of
+ * external storage:</p>
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
+ * monitor_storage}
*/
public static File getExternalStorageDirectory() {
return EXTERNAL_STORAGE_DIRECTORY;
}
/**
+ * Standard directory in which to place any audio files that should be
+ * in the regular list of music for the user.
+ * This may be combined with
+ * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
+ * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
+ * of directories to categories a particular audio file as more than one
+ * type.
+ */
+ public static String DIRECTORY_MUSIC = "Music";
+
+ /**
+ * Standard directory in which to place any audio files that should be
+ * in the list of podcasts that the user can select (not as regular
+ * music).
+ * This may be combined with {@link #DIRECTORY_MUSIC},
+ * {@link #DIRECTORY_NOTIFICATIONS},
+ * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
+ * of directories to categories a particular audio file as more than one
+ * type.
+ */
+ public static String DIRECTORY_PODCASTS = "Podcasts";
+
+ /**
+ * Standard directory in which to place any audio files that should be
+ * in the list of ringtones that the user can select (not as regular
+ * music).
+ * This may be combined with {@link #DIRECTORY_MUSIC},
+ * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and
+ * {@link #DIRECTORY_ALARMS} as a series
+ * of directories to categories a particular audio file as more than one
+ * type.
+ */
+ public static String DIRECTORY_RINGTONES = "Ringtones";
+
+ /**
+ * Standard directory in which to place any audio files that should be
+ * in the list of alarms that the user can select (not as regular
+ * music).
+ * This may be combined with {@link #DIRECTORY_MUSIC},
+ * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
+ * and {@link #DIRECTORY_RINGTONES} as a series
+ * of directories to categories a particular audio file as more than one
+ * type.
+ */
+ public static String DIRECTORY_ALARMS = "Alarms";
+
+ /**
+ * Standard directory in which to place any audio files that should be
+ * in the list of notifications that the user can select (not as regular
+ * music).
+ * This may be combined with {@link #DIRECTORY_MUSIC},
+ * {@link #DIRECTORY_PODCASTS},
+ * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
+ * of directories to categories a particular audio file as more than one
+ * type.
+ */
+ public static String DIRECTORY_NOTIFICATIONS = "Notifications";
+
+ /**
+ * Standard directory in which to place pictures that are available to
+ * the user. Note that this is primarily a convention for the top-level
+ * public directory, as the media scanner will find and collect pictures
+ * in any directory.
+ */
+ public static String DIRECTORY_PICTURES = "Pictures";
+
+ /**
+ * Standard directory in which to place movies that are available to
+ * the user. Note that this is primarily a convention for the top-level
+ * public directory, as the media scanner will find and collect movies
+ * in any directory.
+ */
+ public static String DIRECTORY_MOVIES = "Movies";
+
+ /**
+ * Standard directory in which to place files that have been downloaded by
+ * the user. Note that this is primarily a convention for the top-level
+ * public directory, you are free to download files anywhere in your own
+ * private directories.
+ */
+ public static String DIRECTORY_DOWNLOADS = "Downloads";
+
+ /**
+ * The traditional location for pictures and videos when mounting the
+ * device as a camera. Note that this is primarily a convention for the
+ * top-level public directory, as this convention makes no sense elsewhere.
+ */
+ public static String DIRECTORY_DCIM = "DCIM";
+
+ /**
+ * Get a top-level public external storage directory for placing files of
+ * a particular type. This is where the user will typically place and
+ * manage their own files, so you should be careful about what you put here
+ * to ensure you don't erase their files or get in the way of their own
+ * organization.
+ *
+ * <p>Here is an example of typical code to manipulate a picture on
+ * the public external storage:</p>
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
+ * public_picture}
+ *
+ * @param type The type of storage directory to return. Should be one of
+ * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
+ * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
+ * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
+ * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, or
+ * {@link #DIRECTORY_DCIM}. May not be null.
+ *
+ * @return Returns the File path for the directory. Note that this
+ * directory may not yet exist, so you must make sure it exists before
+ * using it such as with {@link File#mkdirs File.mkdirs()}.
+ */
+ public static File getExternalStoragePublicDirectory(String type) {
+ return new File(getExternalStorageDirectory(), type);
+ }
+
+ /**
+ * Returns the path for android-specific data on the SD card.
+ * @hide
+ */
+ public static File getExternalStorageAndroidDataDir() {
+ return EXTERNAL_STORAGE_ANDROID_DATA_DIRECTORY;
+ }
+
+ /**
+ * Generates the raw path to an application's data
+ * @hide
+ */
+ public static File getExternalStorageAppDataDirectory(String packageName) {
+ return new File(EXTERNAL_STORAGE_ANDROID_DATA_DIRECTORY, packageName);
+ }
+
+ /**
+ * Generates the raw path to an application's media
+ * @hide
+ */
+ public static File getExternalStorageAppMediaDirectory(String packageName) {
+ return new File(EXTERNAL_STORAGE_ANDROID_MEDIA_DIRECTORY, packageName);
+ }
+
+ /**
+ * Generates the path to an application's files.
+ * @hide
+ */
+ public static File getExternalStorageAppFilesDirectory(String packageName) {
+ return new File(new File(EXTERNAL_STORAGE_ANDROID_DATA_DIRECTORY,
+ packageName), "files");
+ }
+
+ /**
+ * Generates the path to an application's cache.
+ * @hide
+ */
+ public static File getExternalStorageAppCacheDirectory(String packageName) {
+ return new File(new File(EXTERNAL_STORAGE_ANDROID_DATA_DIRECTORY,
+ packageName), "cache");
+ }
+
+ /**
* Gets the Android Download/Cache content directory.
*/
public static File getDownloadCacheDirectory() {
@@ -173,6 +351,8 @@
* Gets the current state of the external storage device.
* Note: This call should be deprecated as it doesn't support
* multiple volumes.
+ *
+ * <p>See {@link #getExternalStorageDirectory()} for an example of its use.
*/
public static String getExternalStorageState() {
try {
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index 3457815..7e99f38 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -52,73 +52,75 @@
public static final int ALL_EVENTS = ACCESS | MODIFY | ATTRIB | CLOSE_WRITE
| CLOSE_NOWRITE | OPEN | MOVED_FROM | MOVED_TO | DELETE | CREATE
- | DELETE_SELF | MOVE_SELF;
+ | DELETE_SELF | MOVE_SELF;
private static final String LOG_TAG = "FileObserver";
private static class ObserverThread extends Thread {
- private HashMap<Integer, WeakReference> m_observers = new HashMap<Integer, WeakReference>();
- private int m_fd;
+ private HashMap<Integer, WeakReference> m_observers = new HashMap<Integer, WeakReference>();
+ private int m_fd;
- public ObserverThread() {
- super("FileObserver");
- m_fd = init();
- }
+ public ObserverThread() {
+ super("FileObserver");
+ m_fd = init();
+ }
- public void run() {
- observe(m_fd);
- }
+ public void run() {
+ observe(m_fd);
+ }
- public int startWatching(String path, int mask, FileObserver observer) {
- int wfd = startWatching(m_fd, path, mask);
+ public int startWatching(String path, int mask, FileObserver observer) {
+ int wfd = startWatching(m_fd, path, mask);
- Integer i = new Integer(wfd);
- if (wfd >= 0) {
- synchronized (m_observers) {
- m_observers.put(i, new WeakReference(observer));
- }
- }
+ Integer i = new Integer(wfd);
+ if (wfd >= 0) {
+ synchronized (m_observers) {
+ m_observers.put(i, new WeakReference(observer));
+ }
+ }
- return i;
- }
+ return i;
+ }
- public void stopWatching(int descriptor) {
- stopWatching(m_fd, descriptor);
- }
+ public void stopWatching(int descriptor) {
+ stopWatching(m_fd, descriptor);
+ }
- public void onEvent(int wfd, int mask, String path) {
- // look up our observer, fixing up the map if necessary...
- FileObserver observer;
+ public void onEvent(int wfd, int mask, String path) {
+ // look up our observer, fixing up the map if necessary...
+ FileObserver observer = null;
- synchronized (m_observers) {
- WeakReference weak = m_observers.get(wfd);
- observer = (FileObserver) weak.get();
- if (observer == null) {
- m_observers.remove(wfd);
+ synchronized (m_observers) {
+ WeakReference weak = m_observers.get(wfd);
+ if (weak != null) { // can happen with lots of events from a dead wfd
+ observer = (FileObserver) weak.get();
+ if (observer == null) {
+ m_observers.remove(wfd);
+ }
+ }
+ }
+
+ // ...then call out to the observer without the sync lock held
+ if (observer != null) {
+ try {
+ observer.onEvent(mask, path);
+ } catch (Throwable throwable) {
+ Log.wtf(LOG_TAG, "Unhandled exception in FileObserver " + observer, throwable);
+ }
}
}
- // ...then call out to the observer without the sync lock held
- if (observer != null) {
- try {
- observer.onEvent(mask, path);
- } catch (Throwable throwable) {
- Log.wtf(LOG_TAG, "Unhandled exception in FileObserver " + observer, throwable);
- }
- }
- }
-
- private native int init();
- private native void observe(int fd);
- private native int startWatching(int fd, String path, int mask);
- private native void stopWatching(int fd, int wfd);
+ private native int init();
+ private native void observe(int fd);
+ private native int startWatching(int fd, String path, int mask);
+ private native void stopWatching(int fd, int wfd);
}
private static ObserverThread s_observerThread;
static {
- s_observerThread = new ObserverThread();
- s_observerThread.start();
+ s_observerThread = new ObserverThread();
+ s_observerThread.start();
}
// instance
@@ -127,30 +129,30 @@
private int m_mask;
public FileObserver(String path) {
- this(path, ALL_EVENTS);
+ this(path, ALL_EVENTS);
}
public FileObserver(String path, int mask) {
- m_path = path;
- m_mask = mask;
- m_descriptor = -1;
+ m_path = path;
+ m_mask = mask;
+ m_descriptor = -1;
}
protected void finalize() {
- stopWatching();
+ stopWatching();
}
public void startWatching() {
- if (m_descriptor < 0) {
- m_descriptor = s_observerThread.startWatching(m_path, m_mask, this);
- }
+ if (m_descriptor < 0) {
+ m_descriptor = s_observerThread.startWatching(m_path, m_mask, this);
+ }
}
public void stopWatching() {
- if (m_descriptor >= 0) {
- s_observerThread.stopWatching(m_descriptor);
- m_descriptor = -1;
- }
+ if (m_descriptor >= 0) {
+ s_observerThread.stopWatching(m_descriptor);
+ m_descriptor = -1;
+ }
}
public abstract void onEvent(int event, String path);
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 699ddb2..4887783 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -504,6 +504,9 @@
argsForZygote.add("--runtime-init");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
+ if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
+ argsForZygote.add("--enable-safemode");
+ }
if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
argsForZygote.add("--enable-debugger");
}
diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl
index 84e3f58..3d1ef25 100644
--- a/core/java/android/os/storage/IMountService.aidl
+++ b/core/java/android/os/storage/IMountService.aidl
@@ -109,6 +109,11 @@
int unmountSecureContainer(String id);
/*
+ * Returns true if the specified container is mounted
+ */
+ boolean isSecureContainerMounted(String id);
+
+ /*
* Rename an unmounted secure container.
* Returns an int consistent with MountServiceResultCode
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bacaf43..076903b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1473,6 +1473,21 @@
public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse";
/**
+ * Let user pick default install location.
+ * @hide
+ */
+ public static final String SET_INSTALL_LOCATION = "set_install_location";
+
+ /**
+ * Default install location value.
+ * 0 = auto, let system decide
+ * 1 = internal
+ * 2 = sdcard
+ * @hide
+ */
+ public static final String DEFAULT_INSTALL_LOCATION = "default_install_location";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
* @hide
@@ -2799,22 +2814,6 @@
"sms_outgoing_check_max_count";
/**
- * Enable use of ssl session caching.
- * 'db' - save each session in a (per process) database
- * 'file' - save each session in a (per process) file
- * not set or any other value - normal java in-memory caching
- * @hide
- */
- public static final String SSL_SESSION_CACHE = "ssl_session_cache";
-
- /**
- * How many bytes long a message has to be, in order to be gzipped.
- * @hide
- */
- public static final String SYNC_MIN_GZIP_BYTES =
- "sync_min_gzip_bytes";
-
- /**
* The number of promoted sources in GlobalSearch.
* @hide
*/
diff --git a/core/java/android/speech/RecognitionListener.java b/core/java/android/speech/RecognitionListener.java
index 5434887..2f5bcc3 100644
--- a/core/java/android/speech/RecognitionListener.java
+++ b/core/java/android/speech/RecognitionListener.java
@@ -79,7 +79,8 @@
* time between {@link #onBeginningOfSpeech()} and {@link #onResults(Bundle)} when partial
* results are ready. This method may be called zero, one or multiple times for each call to
* {@link RecognitionManager#startListening(Intent)}, depending on the speech recognition
- * service implementation.
+ * service implementation. To request partial results, use
+ * {@link RecognizerIntent#EXTRA_PARTIAL_RESULTS}
*
* @param partialResults the returned results. To retrieve the results in
* ArrayList<String> format use {@link Bundle#getStringArrayList(String)} with
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index 334b049..241a8b0 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -77,6 +77,7 @@
* <li>{@link #EXTRA_PROMPT}
* <li>{@link #EXTRA_LANGUAGE}
* <li>{@link #EXTRA_MAX_RESULTS}
+ * <li>{@link #EXTRA_PARTIAL_RESULTS}
* </ul>
*
* <p> Result extras (returned in the result, not to be specified in the request):
@@ -166,6 +167,13 @@
public static final String EXTRA_MAX_RESULTS = "android.speech.extra.MAX_RESULTS";
/**
+ * Optional boolean to indicate whether partial results should be returned by the recognizer
+ * as the user speaks (default is false). The server may ignore a request for partial
+ * results in some or all cases.
+ */
+ public static final String EXTRA_PARTIAL_RESULTS = "android.speech.extra.PARTIAL_RESULTS";
+
+ /**
* When the intent is {@link #ACTION_RECOGNIZE_SPEECH}, the speech input activity will
* return results to you via the activity results mechanism. Alternatively, if you use this
* extra to supply a PendingIntent, the results will be added to its bundle and the
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index 9581080..9a8ee02 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -61,6 +61,7 @@
float mYVelocity[] = new float[MotionEvent.BASE_AVAIL_POINTERS];
float mXVelocity[] = new float[MotionEvent.BASE_AVAIL_POINTERS];
+ int mLastTouch;
private VelocityTracker mNext;
@@ -105,8 +106,11 @@
* Reset the velocity tracker back to its initial state.
*/
public void clear() {
- for (int i = 0; i < MotionEvent.BASE_AVAIL_POINTERS; i++) {
- mPastTime[i][0] = 0;
+ final long[][] pastTime = mPastTime;
+ for (int p = 0; p < MotionEvent.BASE_AVAIL_POINTERS; p++) {
+ for (int i = 0; i < NUM_PAST; i++) {
+ pastTime[p][i] = 0;
+ }
}
}
@@ -133,42 +137,11 @@
}
private void addPoint(int pos, float x, float y, long time) {
- int drop = -1;
- int i;
- if (localLOGV) Log.v(TAG, "Adding past y=" + y + " time=" + time);
- final long[] pastTime = mPastTime[pos];
- for (i=0; i<NUM_PAST; i++) {
- if (pastTime[i] == 0) {
- break;
- } else if (pastTime[i] < time-LONGEST_PAST_TIME) {
- if (localLOGV) Log.v(TAG, "Dropping past too old at "
- + i + " time=" + pastTime[i]);
- drop = i;
- }
- }
- if (localLOGV) Log.v(TAG, "Add index: " + i);
- if (i == NUM_PAST && drop < 0) {
- drop = 0;
- }
- if (drop == i) drop--;
- final float[] pastX = mPastX[pos];
- final float[] pastY = mPastY[pos];
- if (drop >= 0) {
- if (localLOGV) Log.v(TAG, "Dropping up to #" + drop);
- final int start = drop+1;
- final int count = NUM_PAST-drop-1;
- System.arraycopy(pastX, start, pastX, 0, count);
- System.arraycopy(pastY, start, pastY, 0, count);
- System.arraycopy(pastTime, start, pastTime, 0, count);
- i -= (drop+1);
- }
- pastX[i] = x;
- pastY[i] = y;
- pastTime[i] = time;
- i++;
- if (i < NUM_PAST) {
- pastTime[i] = 0;
- }
+ final int lastTouch = (mLastTouch + 1) % NUM_PAST;
+ mPastX[pos][lastTouch] = x;
+ mPastY[pos][lastTouch] = y;
+ mPastTime[pos][lastTouch] = time;
+ mLastTouch = lastTouch;
}
/**
@@ -199,36 +172,41 @@
final float[] pastX = mPastX[pos];
final float[] pastY = mPastY[pos];
final long[] pastTime = mPastTime[pos];
-
+ final int lastTouch = mLastTouch;
+
+ // find oldest acceptable time
+ int oldestTouch = lastTouch;
+ if (pastTime[lastTouch] > 0) { // cleared ?
+ oldestTouch = (lastTouch + 1) % NUM_PAST;
+ final float acceptableTime = pastTime[lastTouch] - LONGEST_PAST_TIME;
+ while (pastTime[oldestTouch] < acceptableTime) {
+ oldestTouch = (oldestTouch + 1) % NUM_PAST;
+ }
+ }
+
// Kind-of stupid.
- final float oldestX = pastX[0];
- final float oldestY = pastY[0];
- final long oldestTime = pastTime[0];
+ final float oldestX = pastX[oldestTouch];
+ final float oldestY = pastY[oldestTouch];
+ final long oldestTime = pastTime[oldestTouch];
float accumX = 0;
float accumY = 0;
- int N=0;
- while (N < NUM_PAST) {
- if (pastTime[N] == 0) {
- break;
- }
- N++;
- }
+ float N = (lastTouch - oldestTouch + NUM_PAST) % NUM_PAST + 1;
// Skip the last received event, since it is probably pretty noisy.
if (N > 3) N--;
for (int i=1; i < N; i++) {
- final int dur = (int)(pastTime[i] - oldestTime);
+ final int j = (oldestTouch + i) % NUM_PAST;
+ final int dur = (int)(pastTime[j] - oldestTime);
if (dur == 0) continue;
- float dist = pastX[i] - oldestX;
+ float dist = pastX[j] - oldestX;
float vel = (dist/dur) * units; // pixels/frame.
- if (accumX == 0) accumX = vel;
- else accumX = (accumX + vel) * .5f;
-
- dist = pastY[i] - oldestY;
+ accumX = (accumX == 0) ? vel : (accumX + vel) * .5f;
+
+ dist = pastY[j] - oldestY;
vel = (dist/dur) * units; // pixels/frame.
- if (accumY == 0) accumY = vel;
- else accumY = (accumY + vel) * .5f;
+ accumY = (accumY == 0) ? vel : (accumY + vel) * .5f;
}
+
mXVelocity[pos] = accumX < 0.0f ? Math.max(accumX, -maxVelocity)
: Math.min(accumX, maxVelocity);
mYVelocity[pos] = accumY < 0.0f ? Math.max(accumY, -maxVelocity)
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 889985a..fb19dcf 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8282,7 +8282,7 @@
*/
public void clearAnimation() {
if (mCurrentAnimation != null) {
- mCurrentAnimation.cancel();
+ mCurrentAnimation.detach();
}
mCurrentAnimation = null;
}
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index ad98259..349b7e5 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -277,6 +277,16 @@
}
/**
+ * @hide
+ */
+ public void detach() {
+ if (mStarted && !mEnded) {
+ mEnded = true;
+ if (mListener != null) mListener.onAnimationEnd(this);
+ }
+ }
+
+ /**
* Whether or not the animation has been initialized.
*
* @return Has this animation been initialized.
@@ -766,10 +776,10 @@
if (expired) {
if (mRepeatCount == mRepeated) {
if (!mEnded) {
+ mEnded = true;
if (mListener != null) {
mListener.onAnimationEnd(this);
}
- mEnded = true;
}
} else {
if (mRepeatCount > 0) {
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 68be08d..9e9cc7e 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -816,6 +816,9 @@
int imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
| EditorInfo.IME_FLAG_NO_FULLSCREEN;
switch (type) {
+ case 0: // NORMAL_TEXT_FIELD
+ imeOptions |= EditorInfo.IME_ACTION_GO;
+ break;
case 1: // TEXT_AREA
single = false;
inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
@@ -851,6 +854,7 @@
imeOptions |= EditorInfo.IME_ACTION_GO;
break;
default:
+ imeOptions |= EditorInfo.IME_ACTION_GO;
break;
}
setHint(null);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 2a7dc9c..8fa8f09 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3379,6 +3379,10 @@
text = "";
}
mWebTextView.setTextAndKeepSelection(text);
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null && imm.isActive(mWebTextView)) {
+ imm.restartInput(mWebTextView);
+ }
}
mWebTextView.requestFocus();
}
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 299ed8a..9ef5e0b 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -103,6 +103,18 @@
mMonthPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
DateFormatSymbols dfs = new DateFormatSymbols();
String[] months = dfs.getShortMonths();
+
+ /*
+ * If the user is in a locale where the month names are numeric,
+ * use just the number instead of the "month" character for
+ * consistency with the other fields.
+ */
+ if (months[0].startsWith("1")) {
+ for (int i = 0; i < months.length; i++) {
+ months[i] = String.valueOf(i + 1);
+ }
+ }
+
mMonthPicker.setRange(1, 12, months);
mMonthPicker.setSpeed(200);
mMonthPicker.setOnChangeListener(new OnChangedListener() {
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 631e7d8..da0c5a2 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -295,7 +295,10 @@
/** from --peer-wait */
boolean peerWait;
- /** from --enable-debugger, --enable-checkjni, --enable-assert */
+ /**
+ * From --enable-debugger, --enable-checkjni, --enable-assert, and
+ * --enable-safemode
+ */
int debugFlags;
/** from --classpath */
@@ -363,6 +366,8 @@
arg.substring(arg.indexOf('=') + 1));
} else if (arg.equals("--enable-debugger")) {
debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
+ } else if (arg.equals("--enable-safemode")) {
+ debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
} else if (arg.equals("--enable-checkjni")) {
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
} else if (arg.equals("--enable-assert")) {
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboard.java b/core/java/com/android/internal/widget/PasswordEntryKeyboard.java
index 51f7f69..c9014723 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboard.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboard.java
@@ -216,61 +216,6 @@
}
}
- /**
- * Sets keyboard extension. Keyboard extension is shown when input is detected above keyboard
- * while keyboard has focus.
- *
- * @param resId
- */
- public void setExtension(int resId) {
- mExtensionResId = resId;
- }
-
- /**
- * Get current extesion resource id.
- *
- * @return resource id, 0 if not set.
- */
- public int getExtension() {
- return mExtensionResId;
- }
-
- private void updateSpaceBarForLocale() {
- if (mLocale != null) {
- // Create the graphic for spacebar
- Bitmap buffer = Bitmap.createBitmap(mSpaceKey.width, mSpaceIcon.getIntrinsicHeight(),
- Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(buffer);
- canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
- Paint paint = new Paint();
- paint.setAntiAlias(true);
- // TODO: Make the text size a customizable attribute
- paint.setTextSize(22);
- paint.setTextAlign(Align.CENTER);
- // Draw a drop shadow for the text
- paint.setShadowLayer(1f, 0, 0, 0xFF000000);
- paint.setColor(0x80C0C0C0);
- canvas.drawText(mLocale.getDisplayLanguage(mLocale),
- buffer.getWidth() / 2, - paint.ascent() + 2, paint);
- int x = (buffer.getWidth() - mSpaceIcon.getIntrinsicWidth()) / 2;
- int y = buffer.getHeight() - mSpaceIcon.getIntrinsicHeight();
- mSpaceIcon.setBounds(x, y,
- x + mSpaceIcon.getIntrinsicWidth(), y + mSpaceIcon.getIntrinsicHeight());
- mSpaceIcon.draw(canvas);
- mSpaceKey.icon = new BitmapDrawable(mRes, buffer);
- mSpaceKey.repeatable = false;
- } else {
- mSpaceKey.icon = mRes.getDrawable(R.drawable.sym_keyboard_space);
- mSpaceKey.repeatable = true;
- }
- }
-
- public void setLanguage(Locale locale) {
- if (mLocale != null && mLocale.equals(locale)) return;
- mLocale = locale;
- updateSpaceBarForLocale();
- }
-
static class LatinKey extends Keyboard.Key {
private boolean mShiftLockEnabled;
private boolean mEnabled = true;
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
index b809afc..c2862b0 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
@@ -22,15 +22,11 @@
import android.inputmethodservice.KeyboardView.OnKeyboardActionListener;
import android.os.Handler;
import android.os.SystemClock;
-import android.text.Editable;
-import android.text.Selection;
-import android.util.Log;
+import android.provider.Settings;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewRoot;
-import android.view.inputmethod.InputConnection;
-import android.widget.EditText;
import com.android.internal.R;
public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener {
@@ -40,7 +36,6 @@
private static final int KEYBOARD_STATE_NORMAL = 0;
private static final int KEYBOARD_STATE_SHIFTED = 1;
private static final int KEYBOARD_STATE_CAPSLOCK = 2;
- private static final String TAG = "PasswordEntryKeyboardHelper";
private int mKeyboardMode = KEYBOARD_MODE_ALPHA;
private int mKeyboardState = KEYBOARD_STATE_NORMAL;
private PasswordEntryKeyboard mQwertyKeyboard;
@@ -90,10 +85,15 @@
case KEYBOARD_MODE_ALPHA:
mKeyboardView.setKeyboard(mQwertyKeyboard);
mKeyboardState = KEYBOARD_STATE_NORMAL;
+ final boolean visiblePassword = Settings.System.getInt(
+ mContext.getContentResolver(),
+ Settings.System.TEXT_SHOW_PASSWORD, 1) != 0;
+ mKeyboardView.setPreviewEnabled(visiblePassword);
break;
case KEYBOARD_MODE_NUMERIC:
mKeyboardView.setKeyboard(mNumericKeyboard);
mKeyboardState = KEYBOARD_STATE_NORMAL;
+ mKeyboardView.setPreviewEnabled(false); // never show popup for numeric keypad
break;
}
mKeyboardMode = mode;
@@ -122,7 +122,6 @@
}
public void onKey(int primaryCode, int[] keyCodes) {
- Log.v(TAG, "Key code = " + Integer.toHexString(primaryCode));
if (primaryCode == Keyboard.KEYCODE_DELETE) {
handleBackspace();
} else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
@@ -201,7 +200,7 @@
}
public void onPress(int primaryCode) {
-
+ // TODO: vibration support.
}
public void onRelease(int primaryCode) {
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardView.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardView.java
index 9b93fc2..3e6f6f3 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboardView.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardView.java
@@ -17,27 +17,17 @@
package com.android.internal.widget;
import android.content.Context;
-import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.widget.PopupWindow;
-import com.android.internal.R;
public class PasswordEntryKeyboardView extends KeyboardView {
- public static final int KEYCODE_OPTIONS = -100;
+ static final int KEYCODE_OPTIONS = -100;
static final int KEYCODE_SHIFT_LONGPRESS = -101;
static final int KEYCODE_VOICE = -102;
static final int KEYCODE_F1 = -103;
static final int KEYCODE_NEXT_LANGUAGE = -104;
- private boolean mExtensionVisible;
- private PasswordEntryKeyboardView mExtension;
- private PopupWindow mExtensionPopup;
- private boolean mFirstEvent;
-
public PasswordEntryKeyboardView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -46,107 +36,4 @@
super(context, attrs, defStyle);
}
- @Override
- public boolean onTouchEvent(MotionEvent me) {
- if (((PasswordEntryKeyboard) getKeyboard()).getExtension() == 0) {
- return super.onTouchEvent(me);
- }
- if (me.getY() < 0) {
- if (mExtensionVisible) {
- int action = me.getAction();
- if (mFirstEvent) action = MotionEvent.ACTION_DOWN;
- mFirstEvent = false;
- MotionEvent translated = MotionEvent.obtain(me.getEventTime(), me.getEventTime(),
- action,
- me.getX(), me.getY() + mExtension.getHeight(), me.getMetaState());
- boolean result = mExtension.onTouchEvent(translated);
- translated.recycle();
- if (me.getAction() == MotionEvent.ACTION_UP
- || me.getAction() == MotionEvent.ACTION_CANCEL) {
- closeExtension();
- }
- return result;
- } else {
- if (openExtension()) {
- MotionEvent cancel = MotionEvent.obtain(me.getDownTime(), me.getEventTime(),
- MotionEvent.ACTION_CANCEL, me.getX() - 100, me.getY() - 100, 0);
- super.onTouchEvent(cancel);
- cancel.recycle();
- if (mExtension.getHeight() > 0) {
- MotionEvent translated = MotionEvent.obtain(me.getEventTime(),
- me.getEventTime(),
- MotionEvent.ACTION_DOWN,
- me.getX(), me.getY() + mExtension.getHeight(),
- me.getMetaState());
- mExtension.onTouchEvent(translated);
- translated.recycle();
- } else {
- mFirstEvent = true;
- }
- }
- return true;
- }
- } else if (mExtensionVisible) {
- closeExtension();
- // Send a down event into the main keyboard first
- MotionEvent down = MotionEvent.obtain(me.getEventTime(), me.getEventTime(),
- MotionEvent.ACTION_DOWN, me.getX(), me.getY(), me.getMetaState());
- super.onTouchEvent(down);
- down.recycle();
- // Send the actual event
- return super.onTouchEvent(me);
- } else {
- return super.onTouchEvent(me);
- }
- }
-
- private boolean openExtension() {
- if (((PasswordEntryKeyboard) getKeyboard()).getExtension() == 0) return false;
- makePopupWindow();
- mExtensionVisible = true;
- return true;
- }
-
- private void makePopupWindow() {
- if (mExtensionPopup == null) {
- int[] windowLocation = new int[2];
- mExtensionPopup = new PopupWindow(getContext());
- mExtensionPopup.setBackgroundDrawable(null);
- LayoutInflater li = (LayoutInflater) getContext().getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- mExtension = (PasswordEntryKeyboardView) li.inflate(
- R.layout.password_keyboard_input, null);
- mExtension.setOnKeyboardActionListener(getOnKeyboardActionListener());
- mExtension.setPopupParent(this);
- mExtension.setPopupOffset(0, -windowLocation[1]);
- Keyboard keyboard;
- mExtension.setKeyboard(keyboard = new PasswordEntryKeyboard(getContext(),
- ((PasswordEntryKeyboard) getKeyboard()).getExtension()));
- mExtensionPopup.setContentView(mExtension);
- mExtensionPopup.setWidth(getWidth());
- mExtensionPopup.setHeight(keyboard.getHeight());
- getLocationInWindow(windowLocation);
- // TODO: Fix the "- 30".
- mExtension.setPopupOffset(0, -windowLocation[1] - 30);
- mExtensionPopup.showAtLocation(this, 0, 0, -keyboard.getHeight()
- + windowLocation[1]);
- } else {
- mExtension.setVisibility(VISIBLE);
- }
- }
-
- @Override
- public void closing() {
- super.closing();
- if (mExtensionPopup != null && mExtensionPopup.isShowing()) {
- mExtensionPopup.dismiss();
- mExtensionPopup = null;
- }
- }
-
- private void closeExtension() {
- mExtension.setVisibility(INVISIBLE);
- mExtension.closing();
- mExtensionVisible = false;
- }
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 713e7258..a57c71b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1249,11 +1249,7 @@
android:theme="@style/Theme.Dialog.Alert"
android:excludeFromRecents="true">
</activity>
- <activity android:name="com.android.internal.app.UsbStorageActivity"
- android:excludeFromRecents="true">
- </activity>
- <activity android:name="com.android.internal.app.UsbStorageStopActivity"
- android:theme="@style/Theme.Dialog.Alert"
+ <activity android:name="com.android.server.status.UsbStorageActivity"
android:excludeFromRecents="true">
</activity>
<activity android:name="com.android.internal.app.ExternalMediaFormatActivity"
diff --git a/core/res/res/layout/keyguard_screen_password_landscape.xml b/core/res/res/layout/keyguard_screen_password_landscape.xml
index b089df6..ab675c7 100644
--- a/core/res/res/layout/keyguard_screen_password_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_password_landscape.xml
@@ -37,7 +37,7 @@
android:layout_marginLeft="6dip"
android:layout_marginTop="10dip"
android:layout_marginBottom="10dip"
- android:gravity="center"
+ android:gravity="left"
android:ellipsize="marquee"
android:text="@android:string/keyguard_password_enter_password_code"
android:textAppearance="?android:attr/textAppearanceLarge"
@@ -53,7 +53,7 @@
android:inputType="textPassword"
android:gravity="center"
android:layout_gravity="center"
- android:textSize="32sp"
+ android:textSize="24sp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:background="@drawable/password_field_default"
android:textColor="#ffffffff"
diff --git a/core/res/res/layout/password_keyboard_input.xml b/core/res/res/layout/password_keyboard_input.xml
deleted file mode 100755
index e40b69e..0000000
--- a/core/res/res/layout/password_keyboard_input.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<com.android.passwordunlockdemo.LatinKeyboardView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/keyboardView"
- android:layout_alignParentBottom="true"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="#00000000"
- android:keyBackground="@drawable/btn_keyboard_key_fulltrans"
- />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 54781e3..70bc000 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -215,6 +215,10 @@
running on a device that is running in user mode. -->
<attr name="debuggable" format="boolean" />
+ <!-- Flag indicating whether the application requests the VM to operate in
+ the safe mode. -->
+ <attr name="safeMode" format="boolean" />
+
<!-- Flag indicating whether the given application component is available
to other applications. If false, it can only be accessed by
applications with its same user id (which usually means only by
@@ -600,6 +604,20 @@
Application class to avoid interference with application logic. -->
<attr name="restoreNeedsApplication" format="boolean" />
+ <!-- The default install location defined by an application. -->
+ <attr name="installLocation">
+ <!-- Let the system decide ideal install location -->
+ <enum name="auto" value="0" />
+ <!-- Explicitly request to be installed on internal phone storate
+ only. -->
+ <enum name="internalOnly" value="1" />
+ <!-- Prefer to be installed on sdcard. There is no guarantee that
+ the system will honour this request. The application might end
+ up being installed on internal storage if external media
+ is unavailable or too full. -->
+ <enum name="preferExternal" value="2" />
+ </attr>
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -624,6 +642,7 @@
<attr name="versionName" />
<attr name="sharedUserId" />
<attr name="sharedUserLabel" />
+ <attr name="installLocation" />
</declare-styleable>
<!-- The <code>application</code> tag describes application-level components
@@ -670,6 +689,7 @@
override the component specific values). -->
<attr name="enabled" />
<attr name="debuggable" />
+ <attr name="safeMode" />
<!-- Name of activity to be launched for managing the application's space on the device. -->
<attr name="manageSpaceActivity" />
<attr name="allowClearUserData" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index bd4a3eb..7706f30 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1224,9 +1224,11 @@
<public type="attr" name="expandableListViewWhiteStyle" id="0x010102b6" />
<!-- ===============================================================
- Resources proposed for Flan.
+ Resources proposed for Froyo.
=============================================================== -->
<eat-comment />
<public type="attr" name="neverEncrypt" id="0x010102b7" />
+ <public type="attr" name="installLocation" id="0x010102b8" />
+ <public type="attr" name="safeMode" id="0x010102b9" />
</resources>
diff --git a/core/res/res/xml-land/password_kbd_qwerty.xml b/core/res/res/xml-land/password_kbd_qwerty.xml
index a3d4e88..8245cc1 100755
--- a/core/res/res/xml-land/password_kbd_qwerty.xml
+++ b/core/res/res/xml-land/password_kbd_qwerty.xml
@@ -26,29 +26,28 @@
>
<Row>
- <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
- <Key android:codes="119" android:keyLabel="w"/>
- <Key android:codes="101" android:keyLabel="e"/>
- <Key android:codes="114" android:keyLabel="r"/>
- <Key android:codes="116" android:keyLabel="t"/>
- <Key android:codes="121" android:keyLabel="y"/>
- <Key android:codes="117" android:keyLabel="u"/>
- <Key android:codes="105" android:keyLabel="i"/>
- <Key android:codes="111" android:keyLabel="o"/>
- <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
+ <Key android:keyLabel="q" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="w"/>
+ <Key android:keyLabel="e"/>
+ <Key android:keyLabel="r"/>
+ <Key android:keyLabel="t"/>
+ <Key android:keyLabel="y"/>
+ <Key android:keyLabel="u"/>
+ <Key android:keyLabel="i"/>
+ <Key android:keyLabel="o"/>
+ <Key android:keyLabel="p" android:keyEdgeFlags="right"/>
</Row>
<Row>
- <Key android:codes="97" android:keyLabel="a" android:horizontalGap="5%p"
- android:keyEdgeFlags="left"/>
- <Key android:codes="115" android:keyLabel="s"/>
- <Key android:codes="100" android:keyLabel="d"/>
- <Key android:codes="102" android:keyLabel="f"/>
- <Key android:codes="103" android:keyLabel="g"/>
- <Key android:codes="104" android:keyLabel="h"/>
- <Key android:codes="106" android:keyLabel="j"/>
- <Key android:codes="107" android:keyLabel="k"/>
- <Key android:codes="108" android:keyLabel="l" android:keyEdgeFlags="right"/>
+ <Key android:keyLabel="a" android:horizontalGap="5%p" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="s"/>
+ <Key android:keyLabel="d"/>
+ <Key android:keyLabel="f"/>
+ <Key android:keyLabel="g"/>
+ <Key android:keyLabel="h"/>
+ <Key android:keyLabel="j"/>
+ <Key android:keyLabel="k"/>
+ <Key android:keyLabel="l" android:keyEdgeFlags="right"/>
</Row>
<Row>
@@ -56,13 +55,13 @@
android:keyWidth="15%p" android:isModifier="true"
android:iconPreview="@drawable/sym_keyboard_feedback_shift"
android:isSticky="true" android:keyEdgeFlags="left"/>
- <Key android:codes="122" android:keyLabel="z"/>
- <Key android:codes="120" android:keyLabel="x"/>
- <Key android:codes="99" android:keyLabel="c"/>
- <Key android:codes="118" android:keyLabel="v"/>
- <Key android:codes="98" android:keyLabel="b"/>
- <Key android:codes="110" android:keyLabel="n"/>
- <Key android:codes="109" android:keyLabel="m"/>
+ <Key android:keyLabel="z"/>
+ <Key android:keyLabel="x"/>
+ <Key android:keyLabel="c"/>
+ <Key android:keyLabel="v"/>
+ <Key android:keyLabel="b"/>
+ <Key android:keyLabel="n"/>
+ <Key android:keyLabel="m"/>
<Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
android:keyWidth="15%p" android:keyEdgeFlags="right"
android:iconPreview="@drawable/sym_keyboard_feedback_delete"
@@ -76,9 +75,9 @@
<Key android:keyLabel="-" />
<Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
android:iconPreview="@drawable/sym_keyboard_feedback_space"
- android:keyWidth="20%p" android:isRepeatable="true"/>
+ android:keyWidth="20%p"/>
<Key android:keyLabel="=" />
- <Key android:codes="46" android:keyLabel="."
+ <Key android:keyLabel="."
android:keyWidth="10%p"/>
<Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
android:iconPreview="@drawable/sym_keyboard_feedback_return"
diff --git a/core/res/res/xml-land/password_kbd_qwerty_shifted.xml b/core/res/res/xml-land/password_kbd_qwerty_shifted.xml
index 2285d91..6117e78 100755
--- a/core/res/res/xml-land/password_kbd_qwerty_shifted.xml
+++ b/core/res/res/xml-land/password_kbd_qwerty_shifted.xml
@@ -26,29 +26,29 @@
>
<Row>
- <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
- <Key android:codes="119" android:keyLabel="w"/>
- <Key android:codes="101" android:keyLabel="e"/>
- <Key android:codes="114" android:keyLabel="r"/>
- <Key android:codes="116" android:keyLabel="t"/>
- <Key android:codes="121" android:keyLabel="y"/>
- <Key android:codes="117" android:keyLabel="u"/>
- <Key android:codes="105" android:keyLabel="i"/>
- <Key android:codes="111" android:keyLabel="o"/>
- <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
+ <Key android:keyLabel="q" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="w"/>
+ <Key android:keyLabel="e"/>
+ <Key android:keyLabel="r"/>
+ <Key android:keyLabel="t"/>
+ <Key android:keyLabel="y"/>
+ <Key android:keyLabel="u"/>
+ <Key android:keyLabel="i"/>
+ <Key android:keyLabel="o"/>
+ <Key android:keyLabel="p" android:keyEdgeFlags="right"/>
</Row>
<Row>
- <Key android:codes="97" android:keyLabel="a" android:horizontalGap="5%p"
+ <Key android:keyLabel="a" android:horizontalGap="5%p"
android:keyEdgeFlags="left"/>
- <Key android:codes="115" android:keyLabel="s"/>
- <Key android:codes="100" android:keyLabel="d"/>
- <Key android:codes="102" android:keyLabel="f"/>
- <Key android:codes="103" android:keyLabel="g"/>
- <Key android:codes="104" android:keyLabel="h"/>
- <Key android:codes="106" android:keyLabel="j"/>
- <Key android:codes="107" android:keyLabel="k"/>
- <Key android:codes="108" android:keyLabel="l" android:keyEdgeFlags="right"/>
+ <Key android:keyLabel="s"/>
+ <Key android:keyLabel="d"/>
+ <Key android:keyLabel="f"/>
+ <Key android:keyLabel="g"/>
+ <Key android:keyLabel="h"/>
+ <Key android:keyLabel="j"/>
+ <Key android:keyLabel="k"/>
+ <Key android:keyLabel="l" android:keyEdgeFlags="right"/>
</Row>
<Row>
@@ -56,13 +56,13 @@
android:keyWidth="15%p" android:isModifier="true"
android:iconPreview="@drawable/sym_keyboard_feedback_shift"
android:isSticky="true" android:keyEdgeFlags="left"/>
- <Key android:codes="122" android:keyLabel="z"/>
- <Key android:codes="120" android:keyLabel="x"/>
- <Key android:codes="99" android:keyLabel="c"/>
- <Key android:codes="118" android:keyLabel="v"/>
- <Key android:codes="98" android:keyLabel="b"/>
- <Key android:codes="110" android:keyLabel="n"/>
- <Key android:codes="109" android:keyLabel="m"/>
+ <Key android:keyLabel="z"/>
+ <Key android:keyLabel="x"/>
+ <Key android:keyLabel="c"/>
+ <Key android:keyLabel="v"/>
+ <Key android:keyLabel="b"/>
+ <Key android:keyLabel="n"/>
+ <Key android:keyLabel="m"/>
<Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
android:keyWidth="15%p" android:keyEdgeFlags="right"
android:iconPreview="@drawable/sym_keyboard_feedback_delete"
@@ -76,10 +76,10 @@
<Key android:keyLabel="_" />
<Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
android:iconPreview="@drawable/sym_keyboard_feedback_space"
- android:keyWidth="20%p" android:isRepeatable="true"/>
+ android:keyWidth="20%p"/>
<Key android:keyLabel="+" />
- <Key android:codes="46" android:keyLabel="."/>
- <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ <Key android:keyLabel="."/>
+ <Key android:keyIcon="@drawable/sym_keyboard_return"
android:iconPreview="@drawable/sym_keyboard_feedback_return"
android:keyWidth="20%p" android:keyEdgeFlags="right"/>
</Row>
diff --git a/core/res/res/xml/password_kbd_extension.xml b/core/res/res/xml/password_kbd_extension.xml
index 354594e..28b7efe 100755
--- a/core/res/res/xml/password_kbd_extension.xml
+++ b/core/res/res/xml/password_kbd_extension.xml
@@ -40,22 +40,15 @@
</Row>
<Row android:rowEdgeFlags="bottom">
- <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"
- />
- <Key android:codes="50" android:keyLabel="2"
- />
- <Key android:codes="51" android:keyLabel="3"
- />
- <Key android:codes="52" android:keyLabel="4"
- />
- <Key android:codes="53" android:keyLabel="5"
- />
- <Key android:codes="54" android:keyLabel="6"/>
- <Key android:codes="55" android:keyLabel="7"
- />
- <Key android:codes="56" android:keyLabel="8"/>
- <Key android:codes="57" android:keyLabel="9"/>
- <Key android:codes="48" android:keyLabel="0"
- android:keyEdgeFlags="right"/>
+ <Key android:keyLabel="1" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="2"/>
+ <Key android:keyLabel="3"/>
+ <Key android:keyLabel="4"/>
+ <Key android:keyLabel="5"/>
+ <Key android:keyLabel="6"/>
+ <Key android:keyLabel="7"/>
+ <Key android:keyLabel="8"/>
+ <Key android:keyLabel="9"/>
+ <Key android:keyLabel="0" android:keyEdgeFlags="right"/>
</Row>
</Keyboard>
diff --git a/core/res/res/xml/password_kbd_qwerty.xml b/core/res/res/xml/password_kbd_qwerty.xml
index d4a454b..5fa9b8a 100755
--- a/core/res/res/xml/password_kbd_qwerty.xml
+++ b/core/res/res/xml/password_kbd_qwerty.xml
@@ -26,42 +26,42 @@
>
<Row android:rowEdgeFlags="top">
- <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/>
- <Key android:codes="50" android:keyLabel="2"/>
- <Key android:codes="51" android:keyLabel="3"/>
- <Key android:codes="52" android:keyLabel="4"/>
- <Key android:codes="53" android:keyLabel="5"/>
- <Key android:codes="54" android:keyLabel="6"/>
- <Key android:codes="55" android:keyLabel="7"/>
- <Key android:codes="56" android:keyLabel="8"/>
- <Key android:codes="57" android:keyLabel="9"/>
- <Key android:codes="48" android:keyLabel="0" android:keyEdgeFlags="right"/>
+ <Key android:keyLabel="1" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="2"/>
+ <Key android:keyLabel="3"/>
+ <Key android:keyLabel="4"/>
+ <Key android:keyLabel="5"/>
+ <Key android:keyLabel="6"/>
+ <Key android:keyLabel="7"/>
+ <Key android:keyLabel="8"/>
+ <Key android:keyLabel="9"/>
+ <Key android:keyLabel="0" android:keyEdgeFlags="right"/>
</Row>
<Row>
- <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
- <Key android:codes="119" android:keyLabel="w"/>
- <Key android:codes="101" android:keyLabel="e"/>
- <Key android:codes="114" android:keyLabel="r"/>
- <Key android:codes="116" android:keyLabel="t"/>
- <Key android:codes="121" android:keyLabel="y"/>
- <Key android:codes="117" android:keyLabel="u"/>
- <Key android:codes="105" android:keyLabel="i"/>
- <Key android:codes="111" android:keyLabel="o"/>
- <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
+ <Key android:keyLabel="q" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="w"/>
+ <Key android:keyLabel="e"/>
+ <Key android:keyLabel="r"/>
+ <Key android:keyLabel="t"/>
+ <Key android:keyLabel="y"/>
+ <Key android:keyLabel="u"/>
+ <Key android:keyLabel="i"/>
+ <Key android:keyLabel="o"/>
+ <Key android:keyLabel="p" android:keyEdgeFlags="right"/>
</Row>
<Row>
- <Key android:codes="97" android:keyLabel="a" android:horizontalGap="5%p"
+ <Key android:keyLabel="a" android:horizontalGap="5%p"
android:keyEdgeFlags="left"/>
- <Key android:codes="115" android:keyLabel="s"/>
- <Key android:codes="100" android:keyLabel="d"/>
- <Key android:codes="102" android:keyLabel="f"/>
- <Key android:codes="103" android:keyLabel="g"/>
- <Key android:codes="104" android:keyLabel="h"/>
- <Key android:codes="106" android:keyLabel="j"/>
- <Key android:codes="107" android:keyLabel="k"/>
- <Key android:codes="108" android:keyLabel="l" android:keyEdgeFlags="right"/>
+ <Key android:keyLabel="s"/>
+ <Key android:keyLabel="d"/>
+ <Key android:keyLabel="f"/>
+ <Key android:keyLabel="g"/>
+ <Key android:keyLabel="h"/>
+ <Key android:keyLabel="j"/>
+ <Key android:keyLabel="k"/>
+ <Key android:keyLabel="l" android:keyEdgeFlags="right"/>
</Row>
<Row>
@@ -69,13 +69,13 @@
android:keyWidth="15%p" android:isModifier="true"
android:iconPreview="@drawable/sym_keyboard_feedback_shift"
android:isSticky="true" android:keyEdgeFlags="left"/>
- <Key android:codes="122" android:keyLabel="z"/>
- <Key android:codes="120" android:keyLabel="x"/>
- <Key android:codes="99" android:keyLabel="c"/>
- <Key android:codes="118" android:keyLabel="v"/>
- <Key android:codes="98" android:keyLabel="b"/>
- <Key android:codes="110" android:keyLabel="n"/>
- <Key android:codes="109" android:keyLabel="m"/>
+ <Key android:keyLabel="z"/>
+ <Key android:keyLabel="x"/>
+ <Key android:keyLabel="c"/>
+ <Key android:keyLabel="v"/>
+ <Key android:keyLabel="b"/>
+ <Key android:keyLabel="n"/>
+ <Key android:keyLabel="m"/>
<Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
android:keyWidth="15%p" android:keyEdgeFlags="right"
android:iconPreview="@drawable/sym_keyboard_feedback_delete"
@@ -89,9 +89,9 @@
<Key android:keyLabel="-" />
<Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
android:iconPreview="@drawable/sym_keyboard_feedback_space"
- android:keyWidth="20%p" android:isRepeatable="true"/>
+ android:keyWidth="20%p"/>
<Key android:keyLabel="=" />
- <Key android:codes="46" android:keyLabel="."
+ <Key android:keyLabel="."
android:keyWidth="10%p"/>
<Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_ok"
android:iconPreview="@drawable/sym_keyboard_feedback_ok"
diff --git a/core/res/res/xml/password_kbd_qwerty_shifted.xml b/core/res/res/xml/password_kbd_qwerty_shifted.xml
index f341d9e..e491aff 100755
--- a/core/res/res/xml/password_kbd_qwerty_shifted.xml
+++ b/core/res/res/xml/password_kbd_qwerty_shifted.xml
@@ -26,42 +26,42 @@
>
<Row android:rowEdgeFlags="top">
- <Key android:codes="64" android:keyLabel="\@" android:keyEdgeFlags="left"/>
- <Key android:codes="35" android:keyLabel="\#"/>
- <Key android:codes="36" android:keyLabel="$"/>
- <Key android:codes="37" android:keyLabel="%"/>
- <Key android:codes="38" android:keyLabel="&"/>
- <Key android:codes="42" android:keyLabel="*"/>
- <Key android:codes="45" android:keyLabel="-"/>
+ <Key android:keyLabel="\@" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="\#"/>
+ <Key android:keyLabel="$"/>
+ <Key android:keyLabel="%"/>
+ <Key android:keyLabel="&"/>
+ <Key android:keyLabel="*"/>
+ <Key android:keyLabel="-"/>
<Key android:keyLabel="+"/>
- <Key android:codes="40" android:keyLabel="("/>
- <Key android:codes="41" android:keyLabel=")" android:keyEdgeFlags="right"/>
+ <Key android:keyLabel="("/>
+ <Key android:keyLabel=")" android:keyEdgeFlags="right"/>
</Row>
<Row>
- <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
- <Key android:codes="119" android:keyLabel="w"/>
- <Key android:codes="101" android:keyLabel="e"/>
- <Key android:codes="114" android:keyLabel="r"/>
- <Key android:codes="116" android:keyLabel="t"/>
- <Key android:codes="121" android:keyLabel="y"/>
- <Key android:codes="117" android:keyLabel="u"/>
- <Key android:codes="105" android:keyLabel="i"/>
- <Key android:codes="111" android:keyLabel="o"/>
- <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
+ <Key android:keyLabel="q" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="w"/>
+ <Key android:keyLabel="e"/>
+ <Key android:keyLabel="r"/>
+ <Key android:keyLabel="t"/>
+ <Key android:keyLabel="y"/>
+ <Key android:keyLabel="u"/>
+ <Key android:keyLabel="i"/>
+ <Key android:keyLabel="o"/>
+ <Key android:keyLabel="p" android:keyEdgeFlags="right"/>
</Row>
<Row>
- <Key android:codes="97" android:keyLabel="a" android:horizontalGap="5%p"
+ <Key android:keyLabel="a" android:horizontalGap="5%p"
android:keyEdgeFlags="left"/>
- <Key android:codes="115" android:keyLabel="s"/>
- <Key android:codes="100" android:keyLabel="d"/>
- <Key android:codes="102" android:keyLabel="f"/>
- <Key android:codes="103" android:keyLabel="g"/>
- <Key android:codes="104" android:keyLabel="h"/>
- <Key android:codes="106" android:keyLabel="j"/>
- <Key android:codes="107" android:keyLabel="k"/>
- <Key android:codes="108" android:keyLabel="l" android:keyEdgeFlags="right"/>
+ <Key android:keyLabel="s"/>
+ <Key android:keyLabel="d"/>
+ <Key android:keyLabel="f"/>
+ <Key android:keyLabel="g"/>
+ <Key android:keyLabel="h"/>
+ <Key android:keyLabel="j"/>
+ <Key android:keyLabel="k"/>
+ <Key android:keyLabel="l" android:keyEdgeFlags="right"/>
</Row>
<Row>
@@ -69,13 +69,13 @@
android:keyWidth="15%p" android:isModifier="true"
android:iconPreview="@drawable/sym_keyboard_feedback_shift"
android:isSticky="true" android:keyEdgeFlags="left"/>
- <Key android:codes="122" android:keyLabel="z"/>
- <Key android:codes="120" android:keyLabel="x"/>
- <Key android:codes="99" android:keyLabel="c"/>
- <Key android:codes="118" android:keyLabel="v"/>
- <Key android:codes="98" android:keyLabel="b"/>
- <Key android:codes="110" android:keyLabel="n"/>
- <Key android:codes="109" android:keyLabel="m"/>
+ <Key android:keyLabel="z"/>
+ <Key android:keyLabel="x"/>
+ <Key android:keyLabel="c"/>
+ <Key android:keyLabel="v"/>
+ <Key android:keyLabel="b"/>
+ <Key android:keyLabel="n"/>
+ <Key android:keyLabel="m"/>
<Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
android:keyWidth="15%p" android:keyEdgeFlags="right"
android:iconPreview="@drawable/sym_keyboard_feedback_delete"
@@ -89,9 +89,9 @@
<Key android:keyLabel="_" />
<Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
android:iconPreview="@drawable/sym_keyboard_feedback_space"
- android:keyWidth="20%p" android:isRepeatable="true"/>
+ android:keyWidth="20%p"/>
<Key android:keyLabel="+" />
- <Key android:codes="46" android:keyLabel="."/>
+ <Key android:keyLabel="."/>
<Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_ok"
android:iconPreview="@drawable/sym_keyboard_feedback_ok"
android:keyWidth="20%p" android:keyEdgeFlags="right"/>
diff --git a/core/res/res/xml/password_kbd_symbols.xml b/core/res/res/xml/password_kbd_symbols.xml
index c97e6ae..14a7ec8 100755
--- a/core/res/res/xml/password_kbd_symbols.xml
+++ b/core/res/res/xml/password_kbd_symbols.xml
@@ -26,32 +26,32 @@
>
<Row>
- <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/>
- <Key android:codes="50" android:keyLabel="2"/>
- <Key android:codes="51" android:keyLabel="3"/>
- <Key android:codes="52" android:keyLabel="4"/>
- <Key android:codes="53" android:keyLabel="5"/>
- <Key android:codes="54" android:keyLabel="6"/>
- <Key android:codes="55" android:keyLabel="7"/>
- <Key android:codes="56" android:keyLabel="8"/>
- <Key android:codes="57" android:keyLabel="9"/>
- <Key android:codes="48" android:keyLabel="0" android:keyEdgeFlags="right"/>
+ <Key android:keyLabel="1" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="2"/>
+ <Key android:keyLabel="3"/>
+ <Key android:keyLabel="4"/>
+ <Key android:keyLabel="5"/>
+ <Key android:keyLabel="6"/>
+ <Key android:keyLabel="7"/>
+ <Key android:keyLabel="8"/>
+ <Key android:keyLabel="9"/>
+ <Key android:keyLabel="0" android:keyEdgeFlags="right"/>
</Row>
<Row>
- <Key android:codes="64" android:keyLabel="\@" android:keyEdgeFlags="left"/>
- <Key android:codes="35" android:keyLabel="\#"/>
- <Key android:codes="36" android:keyLabel="$"/>
- <Key android:codes="37" android:keyLabel="%"/>
- <Key android:codes="38" android:keyLabel="&"/>
- <Key android:codes="42" android:keyLabel="*"/>
- <Key android:codes="45" android:keyLabel="-"/>
+ <Key android:keyLabel="\@" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="\#"/>
+ <Key android:keyLabel="$"/>
+ <Key android:keyLabel="%"/>
+ <Key android:keyLabel="&"/>
+ <Key android:keyLabel="*"/>
+ <Key android:keyLabel="-"/>
<Key android:keyLabel="+"/>
- <Key android:codes="40" android:keyLabel="("
+ <Key android:keyLabel="("
android:popupKeyboard="@xml/password_kbd_popup_template"
android:popupCharacters="[{<"
/>
- <Key android:codes="41" android:keyLabel=")" android:keyEdgeFlags="right"
+ <Key android:keyLabel=")" android:keyEdgeFlags="right"
android:popupKeyboard="@xml/password_kbd_popup_template"
android:popupCharacters="]}>"
/>
@@ -61,13 +61,13 @@
<Key android:codes="-1" android:keyLabel="@string/password_keyboard_label_alt_key"
android:keyWidth="15%p" android:isModifier="true"
android:isSticky="true" android:keyEdgeFlags="left"/>
- <Key android:codes="33" android:keyLabel="!"/>
- <Key android:codes="34" android:keyLabel="""/>
- <Key android:codes="39" android:keyLabel="\'"/>
- <Key android:codes="58" android:keyLabel=":"/>
- <Key android:codes="59" android:keyLabel=";"/>
- <Key android:codes="47" android:keyLabel="/" />
- <Key android:codes="63" android:keyLabel="\?"/>
+ <Key android:keyLabel="!"/>
+ <Key android:keyLabel="""/>
+ <Key android:keyLabel="\'"/>
+ <Key android:keyLabel=":"/>
+ <Key android:keyLabel=";"/>
+ <Key android:keyLabel="/" />
+ <Key android:keyLabel="\?"/>
<Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
android:keyWidth="15%p" android:keyEdgeFlags="right"
android:iconPreview="@drawable/sym_keyboard_feedback_delete"
@@ -80,8 +80,7 @@
<Key android:keyLabel="," android:keyWidth="10%p"/>
<Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
android:keyWidth="40%p"
- android:iconPreview="@drawable/sym_keyboard_feedback_space"
- android:isRepeatable="true"/>
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"/>
<Key android:keyLabel="." android:keyWidth="10%p" />
<Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_ok"
android:keyWidth="20%p" android:keyEdgeFlags="right"
diff --git a/core/res/res/xml/password_kbd_symbols_shift.xml b/core/res/res/xml/password_kbd_symbols_shift.xml
index 97ec3c5f..4b84f4b 100755
--- a/core/res/res/xml/password_kbd_symbols_shift.xml
+++ b/core/res/res/xml/password_kbd_symbols_shift.xml
@@ -76,8 +76,7 @@
<Key android:keyLabel="„" android:keyWidth="10%p" />
<Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
android:keyWidth="40%p"
- android:iconPreview="@drawable/sym_keyboard_feedback_space"
- android:isRepeatable="true"/>
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"/>
<Key android:keyLabel="…" android:keyWidth="10%p" />
<Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_ok"
android:keyWidth="20%p" android:keyEdgeFlags="right"
diff --git a/core/tests/coretests/src/android/database/DatabaseCursorTest.java b/core/tests/coretests/src/android/database/DatabaseCursorTest.java
index fad4349..fb5a36f 100644
--- a/core/tests/coretests/src/android/database/DatabaseCursorTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseCursorTest.java
@@ -16,6 +16,7 @@
package android.database;
+import dalvik.annotation.BrokenTest;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
@@ -373,7 +374,9 @@
c.close();
}
- @LargeTest
+ //@LargeTest
+ @BrokenTest("Consistently times out")
+ @Suppress
public void testLoadingThread() throws Exception {
mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);");
@@ -398,7 +401,9 @@
c.close();
}
- @LargeTest
+ //@LargeTest
+ @BrokenTest("Consistently times out")
+ @Suppress
public void testLoadingThreadClose() throws Exception {
mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);");
@@ -450,9 +455,11 @@
mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);");
final int count = 36799;
+ mDatabase.execSQL("BEGIN Transaction;");
for (int i = 0; i < count; i++) {
mDatabase.execSQL("INSERT INTO test (data) VALUES (" + i + ");");
}
+ mDatabase.execSQL("COMMIT;");
Cursor c = mDatabase.query("test", new String[]{"data"}, null, null, null, null, null);
assertNotNull(c);
@@ -484,9 +491,11 @@
// if cursor window size changed, adjust this value too
final int count = 600; // more than two fillWindow needed
+ mDatabase.execSQL("BEGIN Transaction;");
for (int i = 0; i < count; i++) {
mDatabase.execSQL(sql.toString());
}
+ mDatabase.execSQL("COMMIT;");
Cursor c = mDatabase.query("test", new String[]{"data"}, null, null, null, null, null);
assertNotNull(c);
@@ -513,6 +522,7 @@
// if cursor window size changed, adjust this value too
final int count = 600;
+ mDatabase.execSQL("BEGIN Transaction;");
for (int i = 0; i < count; i++) {
StringBuilder sql = new StringBuilder(2100);
sql.append("INSERT INTO test (txt, data) VALUES ('");
@@ -522,6 +532,7 @@
sql.append("');");
mDatabase.execSQL(sql.toString());
}
+ mDatabase.execSQL("COMMIT;");
Cursor c = mDatabase.query("test", new String[]{"txt", "data"}, null, null, null, null, null);
assertNotNull(c);
diff --git a/data/fonts/DroidSansFallback.ttf b/data/fonts/DroidSansFallback.ttf
old mode 100755
new mode 100644
index 61460b1..a935f16
--- a/data/fonts/DroidSansFallback.ttf
+++ b/data/fonts/DroidSansFallback.ttf
Binary files differ
diff --git a/data/fonts/DroidSansFallbackLegacy.ttf b/data/fonts/DroidSansFallbackLegacy.ttf
new file mode 100644
index 0000000..61460b1
--- /dev/null
+++ b/data/fonts/DroidSansFallbackLegacy.ttf
Binary files differ
diff --git a/docs/html/resources/articles/images/live_wallpapers_small.png b/docs/html/resources/articles/images/live_wallpapers_small.png
new file mode 100644
index 0000000..3b49b24
--- /dev/null
+++ b/docs/html/resources/articles/images/live_wallpapers_small.png
Binary files differ
diff --git a/docs/html/resources/articles/index.jd b/docs/html/resources/articles/index.jd
index 4fda6d7..d2f0996 100644
--- a/docs/html/resources/articles/index.jd
+++ b/docs/html/resources/articles/index.jd
@@ -77,6 +77,11 @@
</dl>
<dl>
+ <dt><a href="{@docRoot}resources/articles/live-wallpapers.html">Live Wallpapers</a></dt>
+ <dd>Live wallpapers are richer, animated, interactive backgrounds that users can display in their home screens. Learn how to create a live wallpaper and bundle it in an application that users can install on their devices.</dd>
+</dl>
+
+<dl>
<dt><a href="{@docRoot}resources/articles/on-screen-inputs.html">Onscreen Input Methods</a></dt>
<dd>The Input Method Framework (IMF) allows users to take advantage of on-screen input methods, such as software keyboards. This article provides an overview of Input Method Editors (IMEs) and how applications interact with them.</dd>
</dl>
diff --git a/docs/html/resources/articles/live-wallpapers.jd b/docs/html/resources/articles/live-wallpapers.jd
new file mode 100644
index 0000000..8dda879
--- /dev/null
+++ b/docs/html/resources/articles/live-wallpapers.jd
@@ -0,0 +1,84 @@
+page.title=Live Wallpapers
+@jd:body
+
+<p>Starting with Android 2.1 (API Level 7), users can now enjoy <em>live
+wallpapers</em> — richer, animated, interactive backgrounds — on
+their home screens. A live wallpaper is very similar to a normal Android
+application and has access to all the facilities of the platform: SGL (2D
+drawing), OpenGL (3D drawing), GPS, accelerometers, network access, etc. The
+live wallpapers included on Nexus One demonstrate the use of some of these APIs
+to create fun and interesting user experiences. For instance, the Grass
+wallpaper uses the phone's location to compute sunrise and sunset times in order
+to display the appropriate sky.</p>
+
+<img src="images/live_wallpapers_small.png" style="align:center" />
+
+<p>Creating your own live wallpaper is easy, especially if you have had
+previous experience with <a
+href="../../../reference/android/view/SurfaceView.html"><code>SurfaceView</code></a> or <a
+href="../../../reference/android/graphics/Canvas.html"><code>Canvas</code></a>.
+To learn how to create a live wallpaper, you should check out the <a
+href="../samples/CubeLiveWallpaper/index.html">CubeLiveWallpaper sample code</a>.</p>
+
+<p>In terms of implementation, a live wallpaper is very similar to a regular
+Android <a href="../../../reference/android/app/Service.html">service</a>. The
+only difference is the addition of a new method, <a
+href="../../../reference/android/service/wallpaper/WallpaperService.
+html#onCreateEngine()"><code>onCreateEngine()</code></a>, whose goal is to create a <a
+href="../../../reference/android/service/wallpaper/WallpaperService.Engine.html">
+<code>WallpaperService.Engine</code></a>. The engine is responsible for
+handling the lifecycle and drawing of a wallpaper. The system provides a surface
+on which you can draw, just like you would with a <code>SurfaceView</code></a>.
+Drawing a wallpaper can be very expensive so you should optimize your code
+as much as possible to avoid using too much CPU, not only for battery life
+but also to avoid slowing down the rest of the system. That is also why the
+most important part of the lifecycle of a wallpaper is <a href="../../../reference/android/service/wallpaper/WallpaperService.Engine.html#onVisibilityChanged%28boolean%29">when it becomes invisible</a>.
+When invisible, such as when the user launches an application that covers
+the home screen, a wallpaper must stop all activity.</p>
+
+<p>The engine can also implement several methods to interact with the user
+or the home application. For instance, if you want your wallpaper to scroll
+along when the user swipes from one home screen to another, you can use <a href="../../../reference/android/service/wallpaper/WallpaperService.Engine.html#onOffsetsChanged%28float,%20float,%20float,%20float,%20int,%20int%29"><code>onOffsetsChanged()</code></a>.
+To react to touch events, simply implement <a href="../../../reference/android/service/wallpaper/WallpaperService.Engine.html#onTouchEvent%28android.view.MotionEvent%29"><code>onTouchEvent(MotionEvent)</code></a>.
+Finally, applications can send arbitrary commands to the live wallpaper.
+Currently, only the standard home application sends commands to the <a
+href="../../../reference/android/service/wallpaper/WallpaperService.Engine.html#onCommand%28java.lang.String,%20int,%20int,%20int,%20android.os.Bundle,%20boolean%29"><code>onCommand()</code></a>
+method of the live wallpaper:</p>
+
+<ul>
+<li><code>android.wallpaper.tap</code>: When the user taps an empty space
+on the workspace. This command is interpreted by the Nexus and Water live
+wallpapers to make the wallpaper react to user interaction. For instance,
+if you tap an empty space on the Water live wallpaper, new ripples appear
+under your finger.</li>
+<li><code>android.home.drop</code>: When the user drops an icon or a widget
+on the workspace. This command is also interpreted by the Nexus and Water
+live wallpapers.</li>
+</ul>
+
+<p>If you are developing a live wallpaper, remember that the feature is
+supported only on Android 2.1 (API level 7) and higher versions of the platform.
+To ensure that your application can only be installed on devices that support
+live wallpapers, remember to add the following to the application's manifest
+before publishing to Android Market:</p>
+
+<ul>
+<li><code><uses-sdk android:minSdkVersion="7" /></code>, which indicates
+to Android Market and the platform that your application requires Android 2.1 or
+higher. For more information, see the <a href="../../../guide/appendix/api-levels.html">API
+Levels</a> and the documentation for the
+<a href="../../../guide/topics/manifest/uses-sdk-element.html"><code><uses-sdk></code></a>
+element.</li>
+<li><code><uses-feature android:name="android.software.live_wallpaper" /></code>,
+which tells Android Market that your application includes a live wallpaper
+Android Market uses this feature as a filter, when presenting users lists of
+available applications. When you declaring this feature, Android Market
+displays your application only to users whose devices support live wallpapers,
+while hiding it from other devices on which it would not be able to run. For
+more information, see the documentation for the
+<a href="../../../guide/topics/manifest/uses-feature-element.html"><code><uses-feature></code></a>
+element.</li>
+</ul>
+
+<p>Many great live wallpapers are already available on Android Market and
+we can't wait to see more!</p>
diff --git a/docs/html/resources/resources_toc.cs b/docs/html/resources/resources_toc.cs
index e337e38..0972029 100644
--- a/docs/html/resources/resources_toc.cs
+++ b/docs/html/resources/resources_toc.cs
@@ -83,6 +83,9 @@
<li><a href="<?cs var:toroot ?>resources/articles/live-folders.html">
<span class="en">Live Folders</span>
</a></li>
+ <li><a href="<?cs var:toroot ?>resources/articles/live-wallpapers.html">
+ <span class="en">Live Wallpapers</span>
+ </a> <span class="new">new!</span></li>
<li><a href="<?cs var:toroot ?>resources/articles/on-screen-inputs.html">
<span class="en">Onscreen Input Methods</span>
</a></li>
@@ -178,28 +181,34 @@
</a></li>
<li><a href="<?cs var:toroot ?>resources/samples/BluetoothChat/index.html">
<span class="en">Bluetooth Chat</span>
- </a> <span class="new">new!</span></li>
+ </a></li>
<li><a href="<?cs var:toroot ?>resources/samples/BusinessCard/index.html">
<span class="en">Business Card</span>
- </a> <span class="new">new!</span></li>
+ </a></li>
<li><a href="<?cs var:toroot ?>resources/samples/ContactManager/index.html">
<span class="en">Contact Manager</span>
- </a> <span class="new">new!</span></li>
+ </a></li>
<li><a href="<?cs var:toroot ?>resources/samples/Home/index.html">
<span class="en">Home</span>
</a></li>
<li><a href="<?cs var:toroot ?>resources/samples/JetBoy/index.html">
<span class="en">JetBoy</span>
</a></li>
+ <li><a href="<?cs var:toroot ?>resources/samples/CubeLiveWallpaper/index.html">
+ <span class="en">Live Wallpaper</span>
+ </a> <span class="new">new!</span></li>
<li><a href="<?cs var:toroot ?>resources/samples/LunarLander/index.html">
<span class="en">Lunar Lander</span>
</a></li>
<li><a href="<?cs var:toroot ?>resources/samples/MultiResolution/index.html">
<span class="en">Multiple Resolutions</span>
- </a> <span class="new">new!</span></li>
+ </a></li>
<li><a href="<?cs var:toroot ?>resources/samples/NotePad/index.html">
<span class="en">Note Pad</span>
</a></li>
+ <li><a href="<?cs var:toroot ?>resources/samples/SampleSyncAdapter/index.html">
+ <span class="en">Sample Sync Adapter</span>
+ </a> <span class="new">new!</span></li>
<li><a href="<?cs var:toroot ?>resources/samples/SearchableDictionary/index.html">
<span class="en">Searchable Dictionary</span>
</a></li>
@@ -211,10 +220,10 @@
</a></li>
<li><a href="<?cs var:toroot ?>resources/samples/Wiktionary/index.html">
<span class="en">Wiktionary</span>
- </a> <span class="new">new!</span></li>
+ </a></li>
<li><a href="<?cs var:toroot ?>resources/samples/WiktionarySimple/index.html">
<span class="en">Wiktionary (Simplified)</span>
- </a> <span class="new">new!</span></li>
+ </a></li>
</ul>
</li>
</ul>
diff --git a/docs/html/resources/samples/images/CubeLiveWallpaper1.png b/docs/html/resources/samples/images/CubeLiveWallpaper1.png
new file mode 100644
index 0000000..55bc1e9
--- /dev/null
+++ b/docs/html/resources/samples/images/CubeLiveWallpaper1.png
Binary files differ
diff --git a/docs/html/resources/samples/images/CubeLiveWallpaper3.png b/docs/html/resources/samples/images/CubeLiveWallpaper3.png
new file mode 100644
index 0000000..2747a88
--- /dev/null
+++ b/docs/html/resources/samples/images/CubeLiveWallpaper3.png
Binary files differ
diff --git a/docs/html/resources/samples/index.jd b/docs/html/resources/samples/index.jd
index 0beb781..5ebf41c 100644
--- a/docs/html/resources/samples/index.jd
+++ b/docs/html/resources/samples/index.jd
@@ -27,10 +27,10 @@
platforms) and allow you to view the source files in your browser. </p>
<div class="special">
- <p>Some of the samples in this listing are not yet available in the
- SDK. While we work to update the SDK, you can
- <a href="{@docRoot}shareables/latest_samples.zip">download the latest samples</a> as a ZIP
- archive.</p>
+ <p>Some of the samples in this listing may not yet be available in the
+ SDK. To ensure that you have the latest versions of the samples, you can
+ <a href="{@docRoot}shareables/latest_samples.zip">download the samples pack</a>
+ as a .zip archive.</p>
</div>
<dl>
@@ -55,11 +55,15 @@
<dt><a href="Home/index.html">Home</a></dt>
<dd>A home screen replacement application.</dd>
-
+
<dt><a href="JetBoy/index.html">JetBoy</a></dt>
<dd>A game that demonstrates the SONiVOX JET interactive music technology,
with {@link android.media.JetPlayer}.</dd>
-
+
+ <dt><a href="CubeLiveWallpaper/index.html">Live Wallpaper</a></dt>
+ <dd>An application that demonstrates how to create a live wallpaper and
+ bundle it in an application that users can install on their devices.</dd>
+
<dt><a href="LunarLander/index.html">Lunar Lander</a></dt>
<dd>A classic Lunar Lander game.</dd>
@@ -70,14 +74,21 @@
<dt><a href="NotePad/index.html">Note Pad</a></dt>
<dd>An application for saving notes. Similar (but not identical) to the
<a href="{@docRoot}resources/tutorials/notepad/index.html">Notepad tutorial</a>.</dd>
-
+
+ <dt><a href="SampleSyncAdapter/index.html">SampleSyncAdapter</a></dt>
+ <dd>Demonstrates how an application can communicate with a
+cloud-based service and synchronize its data with data stored locally in a
+content provider. The sample uses two related parts of the Android framework
+— the account manager and the synchronization manager (through a sync
+adapter).</dd>
+
<dt><a href="SearchableDictionary/index.html">Searchable Dictionary</a></dt>
<dd>A sample application that demonstrates Android's search framework,
including how to provide search suggestions for Quick Search Box.</dd>
-
+
<dt><a href="Snake/index.html">Snake</a></dt>
<dd>An implementation of the classic game "Snake."</dd>
-
+
<dt><a href="SoftKeyboard/index.html">Soft Keyboard</a></dt>
<dd>An example of writing an input method for a software keyboard.</dd>
diff --git a/docs/html/shareables/latest_samples.zip b/docs/html/shareables/latest_samples.zip
index 42fad99..34102c5 100644
--- a/docs/html/shareables/latest_samples.zip
+++ b/docs/html/shareables/latest_samples.zip
Binary files differ
diff --git a/graphics/java/android/graphics/YuvImage.java b/graphics/java/android/graphics/YuvImage.java
index 09b4bf4..5a4531b 100644
--- a/graphics/java/android/graphics/YuvImage.java
+++ b/graphics/java/android/graphics/YuvImage.java
@@ -21,13 +21,11 @@
/**
* 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. The stride of each
- * image plane should be provided as well.
+ * array irrespective of the number of image planes in it.
+ * Currently only PixelFormat.YCbCr_420_SP and PixelFormat.YCbCr_422_I are supported.
*
- * To compress a rectangle region in the YUV data, users have to specify a
- * region by width, height and offsets, where each image plane has a
- * corresponding offset. All offsets are measured as a displacement in bytes
- * from yuv[0], where yuv[0] is the beginning of the yuv data.
+ * To compress a rectangle region in the YUV data, users have to specify the
+ * region by left, top, width and height.
*/
public class YuvImage {
@@ -55,21 +53,56 @@
private int[] mStrides;
/**
+ * The width of the image.
+ */
+ private int mWidth;
+
+ /**
+ * The height of the the image.
+ */
+ private int mHeight;
+
+ /**
* Construct an YuvImage.
*
- * @param yuv The YUV data. In the case of more than one image plane, all the planes must be
- * concatenated into a single byte array.
- * @param format The YUV data format as defined in {@link PixelFormat}.
- * @param strides Row bytes of each image plane.
+ * @param yuv The YUV data. In the case of more than one image plane, all the planes must be
+ * concatenated into a single byte array.
+ * @param format The YUV data format as defined in {@link PixelFormat}.
+ * @param width The width of the YuvImage.
+ * @param height The height of the YuvImage.
+ * @param strides (Optional) Row bytes of each image plane. If yuv contains padding, the stride
+ * of each image must be provided. If strides is null, the method assumes no
+ * padding and derives the row bytes by format and width itself.
+ * @throws IllegalArgumentException if format is not support; width or height <= 0; or yuv is
+ * null.
*/
- public YuvImage(byte[] yuv, int format, int[] strides) {
- if ((yuv == null) || (strides == null)) {
+ public YuvImage(byte[] yuv, int format, int width, int height, int[] strides) {
+ if (format != PixelFormat.YCbCr_420_SP &&
+ format != PixelFormat.YCbCr_422_I) {
throw new IllegalArgumentException(
- "yuv or strides cannot be null");
+ "only support PixelFormat.YCbCr_420_SP " +
+ "and PixelFormat.YCbCr_422_I for now");
}
+
+ if (width <= 0 || height <= 0) {
+ throw new IllegalArgumentException(
+ "width and height must large than 0");
+ }
+
+ if (yuv == null) {
+ throw new IllegalArgumentException("yuv cannot be null");
+ }
+
+ if (strides == null) {
+ mStrides = calculateStrides(width, format);
+ } else {
+ mStrides = strides;
+ }
+
mData = yuv;
mFormat = format;
- mStrides = strides;
+ mWidth = width;
+ mHeight = height;
}
/**
@@ -77,22 +110,21 @@
* Only PixelFormat.YCbCr_420_SP and PixelFormat.YCbCr_422_I
* are supported for now.
*
- * @param width The width of the rectangle region.
- * @param height The height of the rectangle region.
- * @param offsets The offsets of the rectangle region in each image plane.
- * The offsets are measured as a displacement in bytes from
- * yuv[0], where yuv[0] is the beginning of the yuv data.
- * @param quality Hint to the compressor, 0-100. 0 meaning compress for
- * small size, 100 meaning compress for max quality.
- * @param stream The outputstream to write the compressed data.
- *
- * @return true if successfully compressed to the specified stream.
- *
+ * @param rectangle The rectangle region to be compressed. The medthod checks if rectangle is
+ * inside the image. Also, the method modifies rectangle if the chroma pixels
+ * in it are not matched with the luma pixels in it.
+ * @param quality Hint to the compressor, 0-100. 0 meaning compress for
+ * small size, 100 meaning compress for max quality.
+ * @param stream OutputStream to write the compressed data.
+ * @return True if the compression is successful.
+ * @throws IllegalArgumentException if rectangle is invalid; quality is not within [0,
+ * 100]; or stream is null.
*/
- public boolean compressToJpeg(int width, int height, int[] offsets, int quality,
- OutputStream stream) {
- if (!validate(mFormat, width, height, offsets)) {
- return false;
+ public boolean compressToJpeg(Rect rectangle, int quality, OutputStream stream) {
+ Rect wholeImage = new Rect(0, 0, mWidth, mHeight);
+ if (!wholeImage.contains(rectangle)) {
+ throw new IllegalArgumentException(
+ "rectangle is not inside the image");
}
if (quality < 0 || quality > 100) {
@@ -100,14 +132,19 @@
}
if (stream == null) {
- throw new NullPointerException();
+ throw new IllegalArgumentException("stream cannot be null");
}
- return nativeCompressToJpeg(mData, mFormat, width, height, offsets,
- mStrides, quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
+ adjustRectangle(rectangle);
+ int[] offsets = calculateOffsets(rectangle.left, rectangle.top);
+
+ return nativeCompressToJpeg(mData, mFormat, rectangle.width(),
+ rectangle.height(), offsets, mStrides, quality, stream,
+ new byte[WORKING_COMPRESS_STORAGE]);
}
- /**
+
+ /**
* @return the YUV data.
*/
public byte[] getYuvData() {
@@ -128,37 +165,71 @@
return mStrides;
}
- protected boolean validate(int format, int width, int height, int[] offsets) {
- if (format != PixelFormat.YCbCr_420_SP &&
- format != PixelFormat.YCbCr_422_I) {
- throw new IllegalArgumentException(
- "only support PixelFormat.YCbCr_420_SP " +
- "and PixelFormat.YCbCr_422_I for now");
+ /**
+ * @return the width of the image.
+ */
+ public int getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * @return the height of the image.
+ */
+ public int getHeight() {
+ return mHeight;
+ }
+
+ int[] calculateOffsets(int left, int top) {
+ int[] offsets = null;
+ if (mFormat == PixelFormat.YCbCr_420_SP) {
+ offsets = new int[] {top * mStrides[0] + left,
+ mHeight * mStrides[0] + top / 2 * mStrides[1]
+ + left / 2 * 2 };
+ return offsets;
}
- if (offsets.length != mStrides.length) {
- throw new IllegalArgumentException(
- "the number of image planes are mismatched");
+ if (mFormat == PixelFormat.YCbCr_422_I) {
+ offsets = new int[] {top * mStrides[0] + left / 2 * 4};
+ return offsets;
}
- if (width <= 0 || height <= 0) {
- throw new IllegalArgumentException(
- "width and height must large than 0");
- }
+ return offsets;
+ }
- int requiredSize;
+ private int[] calculateStrides(int width, int format) {
+ int[] strides = null;
if (format == PixelFormat.YCbCr_420_SP) {
- requiredSize = height * mStrides[0] +(height >> 1) * mStrides[1];
- } else {
- requiredSize = height * mStrides[0];
+ strides = new int[] {width, width};
+ return strides;
}
- if (requiredSize > mData.length) {
- throw new IllegalArgumentException(
- "width or/and height is larger than the yuv data");
+ if (format == PixelFormat.YCbCr_422_I) {
+ strides = new int[] {width * 2};
+ return strides;
}
- return true;
+ return strides;
+ }
+
+ private void adjustRectangle(Rect rect) {
+ int width = rect.width();
+ int height = rect.height();
+ if (mFormat == PixelFormat.YCbCr_420_SP) {
+ // Make sure left, top, width and height are all even.
+ width &= ~1;
+ height &= ~1;
+ rect.left &= ~1;
+ rect.top &= ~1;
+ rect.right = rect.left + width;
+ rect.bottom = rect.top + height;
+ }
+
+ if (mFormat == PixelFormat.YCbCr_422_I) {
+ // Make sure left and width are both even.
+ width &= ~1;
+ rect.left &= ~1;
+ rect.right = rect.left + width;
+ }
}
//////////// native methods
diff --git a/graphics/java/android/renderscript/RSSurfaceView.java b/graphics/java/android/renderscript/RSSurfaceView.java
index ad1bb54..1d3f82d 100644
--- a/graphics/java/android/renderscript/RSSurfaceView.java
+++ b/graphics/java/android/renderscript/RSSurfaceView.java
@@ -36,7 +36,7 @@
**/
public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mSurfaceHolder;
- private RenderScript mRS;
+ private RenderScriptGL mRS;
/**
* Standard View constructor. In order to render something, you
@@ -146,13 +146,13 @@
// ----------------------------------------------------------------------
- public RenderScript createRenderScript(boolean useDepth, boolean forceSW) {
+ public RenderScriptGL createRenderScript(boolean useDepth, boolean forceSW) {
Log.v(RenderScript.LOG_TAG, "createRenderScript");
- mRS = new RenderScript(useDepth, forceSW);
+ mRS = new RenderScriptGL(useDepth, forceSW);
return mRS;
}
- public RenderScript createRenderScript(boolean useDepth) {
+ public RenderScriptGL createRenderScript(boolean useDepth) {
return createRenderScript(useDepth, false);
}
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 29361af..84b1a70 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -31,11 +31,9 @@
**/
public class RenderScript {
static final String LOG_TAG = "RenderScript_jni";
- private static final boolean DEBUG = false;
+ protected static final boolean DEBUG = false;
@SuppressWarnings({"UnusedDeclaration", "deprecation"})
- private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
- int mWidth;
- int mHeight;
+ protected static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
@@ -44,8 +42,8 @@
* field offsets.
*/
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
- private static boolean sInitialized;
- native private static void _nInit();
+ protected static boolean sInitialized;
+ native protected static void _nInit();
static {
@@ -64,7 +62,8 @@
native int nDeviceCreate();
native void nDeviceDestroy(int dev);
native void nDeviceSetConfig(int dev, int param, int value);
- native int nContextCreate(int dev, int ver, boolean useDepth);
+ native int nContextCreateGL(int dev, int ver, boolean useDepth);
+ native int nContextCreate(int dev, int ver);
native void nContextDestroy(int con);
native void nContextSetSurface(int w, int h, Surface sur);
native void nContextSetPriority(int p);
@@ -190,11 +189,10 @@
native void nAnimationAdd(float time, float[] attribs);
native int nAnimationCreate();
- private int mDev;
- private int mContext;
+ protected int mDev;
+ protected int mContext;
@SuppressWarnings({"FieldCanBeLocal"})
- private Surface mSurface;
- private MessageThread mMessageThread;
+ protected MessageThread mMessageThread;
Element mElement_USER_U8;
Element mElement_USER_I8;
@@ -251,7 +249,7 @@
nContextSetPriority(p.mID);
}
- private static class MessageThread extends Thread {
+ protected static class MessageThread extends Thread {
RenderScript mRS;
boolean mRun = true;
@@ -289,26 +287,18 @@
}
}
- public RenderScript(boolean useDepth, boolean forceSW) {
- mSurface = null;
- mWidth = 0;
- mHeight = 0;
- mDev = nDeviceCreate();
- if(forceSW) {
- nDeviceSetConfig(mDev, 0, 1);
- }
- mContext = nContextCreate(mDev, 0, useDepth);
- mMessageThread = new MessageThread(this);
- mMessageThread.start();
- Element.initPredefined(this);
+ protected RenderScript() {
}
- public void contextSetSurface(int w, int h, Surface sur) {
- mSurface = sur;
- mWidth = w;
- mHeight = h;
- validate();
- nContextSetSurface(w, h, mSurface);
+ public static RenderScript create() {
+ RenderScript rs = new RenderScript();
+
+ rs.mDev = rs.nDeviceCreate();
+ rs.mContext = rs.nContextCreate(rs.mDev, 0);
+ rs.mMessageThread = new MessageThread(rs);
+ rs.mMessageThread.start();
+ Element.initPredefined(rs);
+ return rs;
}
public void contextDump(int bits) {
@@ -332,77 +322,15 @@
return mContext != 0;
}
- void pause() {
- validate();
- nContextPause();
- }
-
- void resume() {
- validate();
- nContextResume();
- }
-
- //////////////////////////////////////////////////////////////////////////////////
- // File
-
- public class File extends BaseObj {
- File(int id) {
- super(RenderScript.this);
- mID = id;
- }
- }
-
- public File fileOpen(String s) throws IllegalStateException, IllegalArgumentException
- {
- if(s.length() < 1) {
- throw new IllegalArgumentException("fileOpen does not accept a zero length string.");
- }
-
- try {
- byte[] bytes = s.getBytes("UTF-8");
- int id = nFileOpen(bytes);
- return new File(id);
- } catch (java.io.UnsupportedEncodingException e) {
- throw new RuntimeException(e);
- }
- }
-
-
///////////////////////////////////////////////////////////////////////////////////
// Root state
- private int safeID(BaseObj o) {
+ protected int safeID(BaseObj o) {
if(o != null) {
return o.mID;
}
return 0;
}
-
- public void contextBindRootScript(Script s) {
- validate();
- nContextBindRootScript(safeID(s));
- }
-
- public void contextBindProgramFragmentStore(ProgramStore p) {
- validate();
- nContextBindProgramFragmentStore(safeID(p));
- }
-
- public void contextBindProgramFragment(ProgramFragment p) {
- validate();
- nContextBindProgramFragment(safeID(p));
- }
-
- public void contextBindProgramRaster(ProgramRaster p) {
- validate();
- nContextBindProgramRaster(safeID(p));
- }
-
- public void contextBindProgramVertex(ProgramVertex p) {
- validate();
- nContextBindProgramVertex(safeID(p));
- }
-
}
diff --git a/graphics/java/android/renderscript/RenderScriptGL.java b/graphics/java/android/renderscript/RenderScriptGL.java
new file mode 100644
index 0000000..d1df23d
--- /dev/null
+++ b/graphics/java/android/renderscript/RenderScriptGL.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import java.lang.reflect.Field;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.util.Config;
+import android.util.Log;
+import android.view.Surface;
+
+
+/**
+ * @hide
+ *
+ **/
+public class RenderScriptGL extends RenderScript {
+ private Surface mSurface;
+ int mWidth;
+ int mHeight;
+
+
+ public RenderScriptGL(boolean useDepth, boolean forceSW) {
+ mSurface = null;
+ mWidth = 0;
+ mHeight = 0;
+ mDev = nDeviceCreate();
+ if(forceSW) {
+ nDeviceSetConfig(mDev, 0, 1);
+ }
+ mContext = nContextCreateGL(mDev, 0, useDepth);
+ mMessageThread = new MessageThread(this);
+ mMessageThread.start();
+ Element.initPredefined(this);
+ }
+
+ public void contextSetSurface(int w, int h, Surface sur) {
+ mSurface = sur;
+ mWidth = w;
+ mHeight = h;
+ validate();
+ nContextSetSurface(w, h, mSurface);
+ }
+
+
+ void pause() {
+ validate();
+ nContextPause();
+ }
+
+ void resume() {
+ validate();
+ nContextResume();
+ }
+
+
+ public void contextBindRootScript(Script s) {
+ validate();
+ nContextBindRootScript(safeID(s));
+ }
+
+ public void contextBindProgramFragmentStore(ProgramStore p) {
+ validate();
+ nContextBindProgramFragmentStore(safeID(p));
+ }
+
+ public void contextBindProgramFragment(ProgramFragment p) {
+ validate();
+ nContextBindProgramFragment(safeID(p));
+ }
+
+ public void contextBindProgramRaster(ProgramRaster p) {
+ validate();
+ nContextBindProgramRaster(safeID(p));
+ }
+
+ public void contextBindProgramVertex(ProgramVertex p) {
+ validate();
+ nContextBindProgramVertex(safeID(p));
+ }
+
+
+
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // File
+
+ public class File extends BaseObj {
+ File(int id) {
+ super(RenderScriptGL.this);
+ mID = id;
+ }
+ }
+
+ public File fileOpen(String s) throws IllegalStateException, IllegalArgumentException
+ {
+ if(s.length() < 1) {
+ throw new IllegalArgumentException("fileOpen does not accept a zero length string.");
+ }
+
+ try {
+ byte[] bytes = s.getBytes("UTF-8");
+ int id = nFileOpen(bytes);
+ return new File(id);
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
+
+
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 7ded133..4d35c37 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -151,10 +151,17 @@
}
static jint
-nContextCreate(JNIEnv *_env, jobject _this, jint dev, jint ver, jboolean useDepth)
+nContextCreate(JNIEnv *_env, jobject _this, jint dev, jint ver)
{
LOG_API("nContextCreate");
- return (jint)rsContextCreate((RsDevice)dev, ver, useDepth);
+ return (jint)rsContextCreate((RsDevice)dev, ver);
+}
+
+static jint
+nContextCreateGL(JNIEnv *_env, jobject _this, jint dev, jint ver, jboolean useDepth)
+{
+ LOG_API("nContextCreateGL");
+ return (jint)rsContextCreateGL((RsDevice)dev, ver, useDepth);
}
static void
@@ -260,7 +267,7 @@
{
int fieldCount = _env->GetArrayLength(_ids);
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nElementCreate, con(%p), type(%i), kind(%i), norm(%i), size(%i)", con, type, kind, norm, size);
+ LOG_API("nElementCreate2, con(%p)", con);
jint *ids = _env->GetIntArrayElements(_ids, NULL);
const char ** nameArray = (const char **)calloc(fieldCount, sizeof(char *));
@@ -1089,7 +1096,7 @@
jint *paramPtr = _env->GetIntArrayElements(params, NULL);
jint paramLen = _env->GetArrayLength(params);
- LOG_API("nProgramFragmentCreate, con(%p), paramLen(%i)", con, shaderLen, paramLen);
+ LOG_API("nProgramFragmentCreate, con(%p), paramLen(%i)", con, paramLen);
jint ret = (jint)rsProgramFragmentCreate(con, (uint32_t *)paramPtr, paramLen);
_env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
@@ -1332,7 +1339,8 @@
{"nDeviceCreate", "()I", (void*)nDeviceCreate },
{"nDeviceDestroy", "(I)V", (void*)nDeviceDestroy },
{"nDeviceSetConfig", "(III)V", (void*)nDeviceSetConfig },
-{"nContextCreate", "(IIZ)I", (void*)nContextCreate },
+{"nContextCreate", "(II)I", (void*)nContextCreate },
+{"nContextCreateGL", "(IIZ)I", (void*)nContextCreateGL },
{"nContextSetPriority", "(I)V", (void*)nContextSetPriority },
{"nContextSetSurface", "(IILandroid/view/Surface;)V", (void*)nContextSetSurface },
{"nContextDestroy", "(I)V", (void*)nContextDestroy },
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index a5a1bb8..be06e33 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -62,7 +62,8 @@
// AudioSink: abstraction layer for audio output
class AudioSink : public RefBase {
public:
- typedef void (*AudioCallback)(
+ // Callback returns the number of bytes actually written to the buffer.
+ typedef size_t (*AudioCallback)(
AudioSink *audioSink, void *buffer, size_t size, void *cookie);
virtual ~AudioSink() {}
@@ -77,8 +78,7 @@
virtual status_t getPosition(uint32_t *position) = 0;
// If no callback is specified, use the "write" API below to submit
- // audio data. Otherwise return a full buffer of audio data on each
- // callback.
+ // audio data.
virtual status_t open(
uint32_t sampleRate, int channelCount,
int format=AudioSystem::PCM_16_BIT,
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 843e051..8e5f05f 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -90,11 +90,11 @@
static void AudioCallback(int event, void *user, void *info);
void AudioCallback(int event, void *info);
- static void AudioSinkCallback(
+ static size_t AudioSinkCallback(
MediaPlayerBase::AudioSink *audioSink,
void *data, size_t size, void *me);
- void fillBuffer(void *data, size_t size);
+ size_t fillBuffer(void *data, size_t size);
int64_t getRealTimeUsLocked() const;
diff --git a/include/ui/CameraParameters.h b/include/ui/CameraParameters.h
index 2c29bfb..e328f33 100644
--- a/include/ui/CameraParameters.h
+++ b/include/ui/CameraParameters.h
@@ -187,6 +187,13 @@
// Vertical angle of view in degrees.
// Example value: "42.5". Read only.
static const char KEY_VERTICAL_VIEW_ANGLE[];
+ // Exposure compensation. The value is multiplied by 100. -100 means -1 EV.
+ // 130 means +1.3 EV.
+ // Example value: "0" or "133". Read/write.
+ static const char KEY_EXPOSURE_COMPENSATION[];
+ // Supported exposure compensation.
+ // Example value: "-100,-66,-33,0,33,66,100". Read only.
+ static const char KEY_SUPPORTED_EXPOSURE_COMPENSATION[];
// Values for white balance settings.
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index 6662333..02667d8 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -55,7 +55,8 @@
void rsDeviceDestroy(RsDevice);
void rsDeviceSetConfig(RsDevice, RsDeviceParam, int32_t value);
-RsContext rsContextCreate(RsDevice, uint32_t version, bool useDepth);
+RsContext rsContextCreate(RsDevice, uint32_t version);
+RsContext rsContextCreateGL(RsDevice, uint32_t version, bool useDepth);
void rsContextDestroy(RsContext);
void rsObjDestroyOOB(RsContext, void *);
diff --git a/libs/rs/java/Film/src/com/android/film/FilmRS.java b/libs/rs/java/Film/src/com/android/film/FilmRS.java
index b80e619..7d04502 100644
--- a/libs/rs/java/Film/src/com/android/film/FilmRS.java
+++ b/libs/rs/java/Film/src/com/android/film/FilmRS.java
@@ -40,7 +40,7 @@
public FilmRS() {
}
- public void init(RenderScript rs, Resources res, int width, int height) {
+ public void init(RenderScriptGL rs, Resources res, int width, int height) {
mRS = rs;
mRes = res;
initRS();
@@ -65,7 +65,7 @@
private Resources mRes;
- private RenderScript mRS;
+ private RenderScriptGL mRS;
private Script mScriptStrip;
private Script mScriptImage;
private Sampler mSampler;
diff --git a/libs/rs/java/Film/src/com/android/film/FilmView.java b/libs/rs/java/Film/src/com/android/film/FilmView.java
index 4a201fd..5bc2811 100644
--- a/libs/rs/java/Film/src/com/android/film/FilmView.java
+++ b/libs/rs/java/Film/src/com/android/film/FilmView.java
@@ -22,6 +22,7 @@
import android.renderscript.RSSurfaceView;
import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
import android.content.Context;
import android.content.res.Resources;
@@ -45,7 +46,7 @@
//setFocusable(true);
}
- private RenderScript mRS;
+ private RenderScriptGL mRS;
private FilmRS mRender;
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
index 71f95a7..9356579 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -37,7 +37,7 @@
public FountainRS() {
}
- public void init(RenderScript rs, Resources res, int width, int height) {
+ public void init(RenderScriptGL rs, Resources res, int width, int height) {
mRS = rs;
mRes = res;
initRS();
@@ -65,7 +65,7 @@
private Resources mRes;
- private RenderScript mRS;
+ private RenderScriptGL mRS;
private Allocation mIntAlloc;
private SimpleMesh mSM;
private SomeData mSD;
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
index fcb93f4..dfd6a49 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
@@ -22,6 +22,7 @@
import android.renderscript.RSSurfaceView;
import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
import android.content.Context;
import android.content.res.Resources;
@@ -45,7 +46,7 @@
//setFocusable(true);
}
- private RenderScript mRS;
+ private RenderScriptGL mRS;
private FountainRS mRender;
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
diff --git a/libs/rs/java/ImageProcessing/res/raw/threshold.rs b/libs/rs/java/ImageProcessing/res/raw/threshold.rs
index dec5587..ad4dbd5 100644
--- a/libs/rs/java/ImageProcessing/res/raw/threshold.rs
+++ b/libs/rs/java/ImageProcessing/res/raw/threshold.rs
@@ -5,8 +5,8 @@
char a;
};
-void filter(struct color_s *in, struct color_s *out, struct vec3_s *luminanceVector) {
- struct vec3_s pixel;
+void filter(struct color_s *in, struct color_s *out, struct vecF32_3_s *luminanceVector) {
+ struct vecF32_3_s pixel;
pixel.x = (in->r & 0xFF) / 255.0f;
pixel.y = (in->g & 0xFF) / 255.0f;
pixel.z = (in->b & 0xFF) / 255.0f;
@@ -22,10 +22,12 @@
}
void main() {
+ int t = uptimeMillis();
+
struct color_s *in = (struct color_s *) InPixel;
struct color_s *out = (struct color_s *) OutPixel;
-
- struct vec3_s luminanceVector;
+
+ struct vecF32_3_s luminanceVector;
luminanceVector.x = 0.2125f;
luminanceVector.y = 0.7154f;
luminanceVector.z = 0.0721f;
@@ -40,5 +42,8 @@
out++;
}
+ t= uptimeMillis() - t;
+ debugI32("Filter time", t);
+
sendToClient(&count, 1, 4, 0);
}
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 0ca00b3..568d3ab 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -126,14 +126,13 @@
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- mRS.contextSetSurface(width, height, holder.getSurface());
}
public void surfaceDestroyed(SurfaceHolder holder) {
}
private Script.Invokable createScript() {
- mRS = new RenderScript(false, false);
+ mRS = RenderScript.create();
mRS.mMessageCallback = new FilterCallback();
mParamsType = Type.createFromClass(mRS, Params.class, 1, "Parameters");
@@ -164,7 +163,7 @@
sb.setType(true, 2);
Script.Invokable invokable = sb.addInvokable("main");
sb.setScript(getResources(), R.raw.threshold);
- sb.setRoot(true);
+ //sb.setRoot(true);
ScriptC script = sb.create();
script.bindAllocation(mParamsAllocation, 0);
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 261b827..2e47ea3 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -289,15 +289,17 @@
LOGE("pthread_setspecific %i", status);
}
- rsc->mStateRaster.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
- rsc->setRaster(NULL);
- rsc->mStateVertex.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
- rsc->setVertex(NULL);
- rsc->mStateFragment.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
- rsc->setFragment(NULL);
- rsc->mStateFragmentStore.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
- rsc->setFragmentStore(NULL);
- rsc->mStateVertexArray.init(rsc);
+ if (rsc->mIsGraphicsContext) {
+ rsc->mStateRaster.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
+ rsc->setRaster(NULL);
+ rsc->mStateVertex.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
+ rsc->setVertex(NULL);
+ rsc->mStateFragment.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
+ rsc->setFragment(NULL);
+ rsc->mStateFragmentStore.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
+ rsc->setFragmentStore(NULL);
+ rsc->mStateVertexArray.init(rsc);
+ }
rsc->mRunning = true;
bool mDraw = true;
@@ -307,7 +309,7 @@
mDraw &= (rsc->mWndSurface != NULL);
uint32_t targetTime = 0;
- if (mDraw) {
+ if (mDraw && rsc->mIsGraphicsContext) {
targetTime = rsc->runRootScript();
mDraw = targetTime && !rsc->mPaused;
rsc->timerSet(RS_TIMER_CLEAR_SWAP);
@@ -329,23 +331,27 @@
}
LOGV("RS Thread exiting");
- rsc->mRaster.clear();
- rsc->mFragment.clear();
- rsc->mVertex.clear();
- rsc->mFragmentStore.clear();
- rsc->mRootScript.clear();
- rsc->mStateRaster.deinit(rsc);
- rsc->mStateVertex.deinit(rsc);
- rsc->mStateFragment.deinit(rsc);
- rsc->mStateFragmentStore.deinit(rsc);
+ if (rsc->mIsGraphicsContext) {
+ rsc->mRaster.clear();
+ rsc->mFragment.clear();
+ rsc->mVertex.clear();
+ rsc->mFragmentStore.clear();
+ rsc->mRootScript.clear();
+ rsc->mStateRaster.deinit(rsc);
+ rsc->mStateVertex.deinit(rsc);
+ rsc->mStateFragment.deinit(rsc);
+ rsc->mStateFragmentStore.deinit(rsc);
+ }
ObjectBase::zeroAllUserRef(rsc);
rsc->mObjDestroy.mNeedToEmpty = true;
rsc->objDestroyOOBRun();
- pthread_mutex_lock(&gInitMutex);
- rsc->deinitEGL();
- pthread_mutex_unlock(&gInitMutex);
+ if (rsc->mIsGraphicsContext) {
+ pthread_mutex_lock(&gInitMutex);
+ rsc->deinitEGL();
+ pthread_mutex_unlock(&gInitMutex);
+ }
LOGV("RS Thread exited");
return NULL;
@@ -371,7 +377,7 @@
#endif
}
-Context::Context(Device *dev, bool useDepth)
+Context::Context(Device *dev, bool isGraphics, bool useDepth)
{
pthread_mutex_lock(&gInitMutex);
@@ -383,6 +389,8 @@
mPaused = false;
mObjHead = NULL;
memset(&mEGL, 0, sizeof(mEGL));
+ memset(&mGL, 0, sizeof(mGL));
+ mIsGraphicsContext = isGraphics;
int status;
pthread_attr_t threadAttr;
@@ -454,7 +462,7 @@
void Context::setSurface(uint32_t w, uint32_t h, Surface *sur)
{
- LOGV("setSurface %i %i %p", w, h, sur);
+ rsAssert(mIsGraphicsContext);
EGLBoolean ret;
if (mEGL.mSurface != NULL) {
@@ -544,21 +552,25 @@
void Context::pause()
{
+ rsAssert(mIsGraphicsContext);
mPaused = true;
}
void Context::resume()
{
+ rsAssert(mIsGraphicsContext);
mPaused = false;
}
void Context::setRootScript(Script *s)
{
+ rsAssert(mIsGraphicsContext);
mRootScript.set(s);
}
void Context::setFragmentStore(ProgramFragmentStore *pfs)
{
+ rsAssert(mIsGraphicsContext);
if (pfs == NULL) {
mFragmentStore.set(mStateFragmentStore.mDefault);
} else {
@@ -568,6 +580,7 @@
void Context::setFragment(ProgramFragment *pf)
{
+ rsAssert(mIsGraphicsContext);
if (pf == NULL) {
mFragment.set(mStateFragment.mDefault);
} else {
@@ -577,6 +590,7 @@
void Context::setRaster(ProgramRaster *pr)
{
+ rsAssert(mIsGraphicsContext);
if (pr == NULL) {
mRaster.set(mStateRaster.mDefault);
} else {
@@ -586,6 +600,7 @@
void Context::setVertex(ProgramVertex *pv)
{
+ rsAssert(mIsGraphicsContext);
if (pv == NULL) {
mVertex.set(mStateVertex.mDefault);
} else {
@@ -860,10 +875,19 @@
}
-RsContext rsContextCreate(RsDevice vdev, uint32_t version, bool useDepth)
+RsContext rsContextCreate(RsDevice vdev, uint32_t version)
{
+ LOGV("rsContextCreate %p", vdev);
Device * dev = static_cast<Device *>(vdev);
- Context *rsc = new Context(dev, useDepth);
+ Context *rsc = new Context(dev, false, false);
+ return rsc;
+}
+
+RsContext rsContextCreateGL(RsDevice vdev, uint32_t version, bool useDepth)
+{
+ LOGV("rsContextCreateGL %p, %i", vdev, useDepth);
+ Device * dev = static_cast<Device *>(vdev);
+ Context *rsc = new Context(dev, true, useDepth);
return rsc;
}
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 2edd16d..31d8cc8 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -51,7 +51,7 @@
class Context
{
public:
- Context(Device *, bool useDepth);
+ Context(Device *, bool isGraphics, bool useDepth);
~Context();
static pthread_key_t gThreadTLSKey;
@@ -201,6 +201,7 @@
uint32_t mWidth;
uint32_t mHeight;
int32_t mThreadPriority;
+ bool mIsGraphicsContext;
bool mRunning;
bool mExit;
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 965b7dd..2d6152e 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -39,7 +39,6 @@
#include <ui/GraphicBufferAllocator.h>
#include <ui/PixelFormat.h>
-#include <ui/DisplayInfo.h>
#include <pixelflinger/pixelflinger.h>
#include <GLES/gl.h>
@@ -350,8 +349,8 @@
mServerCblk->connected |= 1<<dpy;
display_cblk_t* dcblk = mServerCblk->displays + dpy;
memset(dcblk, 0, sizeof(display_cblk_t));
- dcblk->w = w;
- dcblk->h = h;
+ dcblk->w = plane.getWidth();
+ dcblk->h = plane.getHeight();
dcblk->format = f;
dcblk->orientation = ISurfaceComposer::eOrientationDefault;
dcblk->xdpi = hw.getDpiX();
@@ -621,14 +620,8 @@
const DisplayHardware& hw(plane.displayHardware());
volatile display_cblk_t* dcblk = mServerCblk->displays + dpy;
dcblk->orientation = orientation;
- if (orientation & eOrientationSwapMask) {
- // 90 or 270 degrees orientation
- dcblk->w = hw.getHeight();
- dcblk->h = hw.getWidth();
- } else {
- dcblk->w = hw.getWidth();
- dcblk->h = hw.getHeight();
- }
+ dcblk->w = plane.getWidth();
+ dcblk->h = plane.getHeight();
mVisibleRegionsDirty = true;
mDirtyRegion.set(hw.bounds());
@@ -1795,13 +1788,47 @@
return mHw ? true : false;
}
-void GraphicPlane::setDisplayHardware(DisplayHardware *hw) {
- mHw = hw;
+int GraphicPlane::getWidth() const {
+ return mWidth;
}
-void GraphicPlane::setTransform(const Transform& tr) {
- mTransform = tr;
- mGlobalTransform = mOrientationTransform * mTransform;
+int GraphicPlane::getHeight() const {
+ return mHeight;
+}
+
+void GraphicPlane::setDisplayHardware(DisplayHardware *hw)
+{
+ mHw = hw;
+
+ // initialize the display orientation transform.
+ // it's a constant that should come from the display driver.
+ int displayOrientation = ISurfaceComposer::eOrientationDefault;
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("ro.sf.hwrotation", property, NULL) > 0) {
+ //displayOrientation
+ switch (atoi(property)) {
+ case 90:
+ displayOrientation = ISurfaceComposer::eOrientation90;
+ break;
+ case 270:
+ displayOrientation = ISurfaceComposer::eOrientation270;
+ break;
+ }
+ }
+
+ const float w = hw->getWidth();
+ const float h = hw->getHeight();
+ GraphicPlane::orientationToTransfrom(displayOrientation, w, h,
+ &mDisplayTransform);
+ if (displayOrientation & ISurfaceComposer::eOrientationSwapMask) {
+ mDisplayWidth = h;
+ mDisplayHeight = w;
+ } else {
+ mDisplayWidth = w;
+ mDisplayHeight = h;
+ }
+
+ setOrientation(ISurfaceComposer::eOrientationDefault);
}
status_t GraphicPlane::orientationToTransfrom(
@@ -1810,8 +1837,9 @@
float a, b, c, d, x, y;
switch (orientation) {
case ISurfaceComposer::eOrientationDefault:
- a=1; b=0; c=0; d=1; x=0; y=0;
- break;
+ // make sure the default orientation is optimal
+ tr->reset();
+ return NO_ERROR;
case ISurfaceComposer::eOrientation90:
a=0; b=-1; c=1; d=0; x=w; y=0;
break;
@@ -1831,20 +1859,16 @@
status_t GraphicPlane::setOrientation(int orientation)
{
- const DisplayHardware& hw(displayHardware());
- const float w = hw.getWidth();
- const float h = hw.getHeight();
-
- if (orientation == ISurfaceComposer::eOrientationDefault) {
- // make sure the default orientation is optimal
- mOrientationTransform.reset();
- mOrientation = orientation;
- mGlobalTransform = mTransform;
- return NO_ERROR;
- }
-
// If the rotation can be handled in hardware, this is where
// the magic should happen.
+
+ const DisplayHardware& hw(displayHardware());
+ const float w = mDisplayWidth;
+ const float h = mDisplayHeight;
+ mWidth = int(w);
+ mHeight = int(h);
+
+ Transform orientationTransform;
if (UNLIKELY(orientation == 42)) {
float a, b, c, d, x, y;
const float r = (3.14159265f / 180.0f) * 42.0f;
@@ -1853,14 +1877,18 @@
a=co; b=-si; c=si; d=co;
x = si*(h*0.5f) + (1-co)*(w*0.5f);
y =-si*(w*0.5f) + (1-co)*(h*0.5f);
- mOrientationTransform.set(a, b, c, d);
- mOrientationTransform.set(x, y);
+ orientationTransform.set(a, b, c, d);
+ orientationTransform.set(x, y);
} else {
GraphicPlane::orientationToTransfrom(orientation, w, h,
- &mOrientationTransform);
+ &orientationTransform);
+ if (orientation & ISurfaceComposer::eOrientationSwapMask) {
+ mWidth = int(h);
+ mHeight = int(w);
+ }
}
mOrientation = orientation;
- mGlobalTransform = mOrientationTransform * mTransform;
+ mGlobalTransform = mDisplayTransform * orientationTransform;
return NO_ERROR;
}
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index c0ab73d..2b7820c 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -116,9 +116,10 @@
bool initialized() const;
void setDisplayHardware(DisplayHardware *);
- void setTransform(const Transform& tr);
status_t setOrientation(int orientation);
int getOrientation() const { return mOrientation; }
+ int getWidth() const;
+ int getHeight() const;
const DisplayHardware& displayHardware() const;
const Transform& transform() const;
@@ -129,10 +130,13 @@
GraphicPlane operator = (const GraphicPlane&);
DisplayHardware* mHw;
- Transform mTransform;
- Transform mOrientationTransform;
Transform mGlobalTransform;
+ Transform mDisplayTransform;
int mOrientation;
+ float mDisplayWidth;
+ float mDisplayHeight;
+ int mWidth;
+ int mHeight;
};
// ---------------------------------------------------------------------------
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 09a36f1..f374fbc 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -281,7 +281,7 @@
// send command to camera driver
status_t Camera::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
{
- LOGD("sendCommand");
+ LOGV("sendCommand");
sp <ICamera> c = mCamera;
if (c == 0) return NO_INIT;
return c->sendCommand(cmd, arg1, arg2);
diff --git a/libs/ui/CameraParameters.cpp b/libs/ui/CameraParameters.cpp
index c4958a0..493b9c1 100644
--- a/libs/ui/CameraParameters.cpp
+++ b/libs/ui/CameraParameters.cpp
@@ -59,6 +59,8 @@
const char CameraParameters::KEY_FOCAL_LENGTH[] = "focal-length";
const char CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE[] = "horizontal-view-angle";
const char CameraParameters::KEY_VERTICAL_VIEW_ANGLE[] = "vertical-view-angle";
+const char CameraParameters::KEY_EXPOSURE_COMPENSATION[] = "exposure-compensation";
+const char CameraParameters::KEY_SUPPORTED_EXPOSURE_COMPENSATION[] = "exposure-compensation-values";
// Values for white balance settings.
const char CameraParameters::WHITE_BALANCE_AUTO[] = "auto";
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
index e1b3ec7..4154b05a 100644
--- a/libs/ui/ICamera.cpp
+++ b/libs/ui/ICamera.cpp
@@ -344,7 +344,7 @@
return NO_ERROR;
} break;
case SEND_COMMAND: {
- LOGD("SEND_COMMAND");
+ LOGV("SEND_COMMAND");
CHECK_INTERFACE(ICamera, data, reply);
int command = data.readInt32();
int arg1 = data.readInt32();
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 628cb6b7..8c24ee1 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -22,7 +22,6 @@
import android.location.IGeocodeProvider;
import android.location.IGpsStatusListener;
import android.location.ILocationListener;
-import android.location.ILocationProvider;
import android.location.Location;
import android.os.Bundle;
diff --git a/location/java/android/location/ILocationProvider.aidl b/location/java/android/location/ILocationProvider.aidl
index 9fe6ab4..5529b11 100644
--- a/location/java/android/location/ILocationProvider.aidl
+++ b/location/java/android/location/ILocationProvider.aidl
@@ -21,7 +21,7 @@
import android.os.Bundle;
/**
- * Binder interface for location providers.
+ * Binder interface for services that implement location providers.
*
* {@hide}
*/
diff --git a/location/java/android/location/LocationProviderInterface.java b/location/java/android/location/LocationProviderInterface.java
new file mode 100644
index 0000000..98beffe
--- /dev/null
+++ b/location/java/android/location/LocationProviderInterface.java
@@ -0,0 +1,51 @@
+/*
+ * 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.location;
+
+import android.location.Location;
+import android.net.NetworkInfo;
+import android.os.Bundle;
+
+/**
+ * Location Manager's interface for location providers.
+ *
+ * {@hide}
+ */
+public interface LocationProviderInterface {
+ String getName();
+ boolean requiresNetwork();
+ boolean requiresSatellite();
+ boolean requiresCell();
+ boolean hasMonetaryCost();
+ boolean supportsAltitude();
+ boolean supportsSpeed();
+ boolean supportsBearing();
+ int getPowerRequirement();
+ int getAccuracy();
+ boolean isEnabled();
+ void enable();
+ void disable();
+ int getStatus(Bundle extras);
+ long getStatusUpdateTime();
+ void enableLocationTracking(boolean enable);
+ void setMinTime(long minTime);
+ void updateNetworkState(int state, NetworkInfo info);
+ void updateLocation(Location location);
+ boolean sendExtraCommand(String command, Bundle extras);
+ void addListener(int uid);
+ void removeListener(int uid);
+}
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 8b5f702..dce3b27 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -26,11 +26,11 @@
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
import android.location.ILocationManager;
-import android.location.ILocationProvider;
import android.location.INetInitiatedListener;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
+import android.location.LocationProviderInterface;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.SntpClient;
@@ -65,7 +65,7 @@
*
* {@hide}
*/
-public class GpsLocationProvider extends ILocationProvider.Stub {
+public class GpsLocationProvider implements LocationProviderInterface {
private static final String TAG = "GpsLocationProvider";
@@ -374,6 +374,13 @@
}
/**
+ * Returns the name of this provider.
+ */
+ public String getName() {
+ return LocationManager.GPS_PROVIDER;
+ }
+
+ /**
* Returns true if the provider requires access to a
* data network (e.g., the Internet), false otherwise.
*/
@@ -576,6 +583,10 @@
}
}
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+
public int getStatus(Bundle extras) {
if (extras != null) {
extras.putInt("satellites", mSvCount);
diff --git a/location/java/com/android/internal/location/LocationProviderProxy.java b/location/java/com/android/internal/location/LocationProviderProxy.java
index 361104f..abb90b7 100644
--- a/location/java/com/android/internal/location/LocationProviderProxy.java
+++ b/location/java/com/android/internal/location/LocationProviderProxy.java
@@ -22,6 +22,7 @@
import android.content.ServiceConnection;
import android.location.ILocationProvider;
import android.location.Location;
+import android.location.LocationProviderInterface;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
@@ -31,18 +32,17 @@
import android.util.Log;
/**
- * A class for proxying ILocationProvider implementations.
+ * A class for proxying location providers implemented as services.
*
* {@hide}
*/
-public class LocationProviderProxy {
+public class LocationProviderProxy implements LocationProviderInterface {
private static final String TAG = "LocationProviderProxy";
private final Context mContext;
private final String mName;
private ILocationProvider mProvider;
- private Intent mIntent;
private Handler mHandler;
private final Connection mServiceConnection = new Connection();
@@ -56,21 +56,13 @@
// for caching requiresNetwork, requiresSatellite, etc.
private DummyLocationProvider mCachedAttributes;
- // constructor for proxying built-in location providers
- public LocationProviderProxy(Context context, String name, ILocationProvider provider) {
- mContext = context;
- mName = name;
- mProvider = provider;
- }
-
// constructor for proxying location providers implemented in a separate service
public LocationProviderProxy(Context context, String name, String serviceName,
Handler handler) {
mContext = context;
mName = name;
- mIntent = new Intent(serviceName);
mHandler = handler;
- mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+ mContext.bindService(new Intent(serviceName), mServiceConnection, Context.BIND_AUTO_CREATE);
}
private class Connection implements ServiceConnection {
diff --git a/location/java/com/android/internal/location/MockProvider.java b/location/java/com/android/internal/location/MockProvider.java
index 7d9e86ca..2f6fdee 100644
--- a/location/java/com/android/internal/location/MockProvider.java
+++ b/location/java/com/android/internal/location/MockProvider.java
@@ -17,9 +17,9 @@
package com.android.internal.location;
import android.location.ILocationManager;
-import android.location.ILocationProvider;
import android.location.Location;
import android.location.LocationProvider;
+import android.location.LocationProviderInterface;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.RemoteException;
@@ -33,7 +33,7 @@
*
* {@hide}
*/
-public class MockProvider extends ILocationProvider.Stub {
+public class MockProvider implements LocationProviderInterface {
private final String mName;
private final ILocationManager mLocationManager;
private final boolean mRequiresNetwork;
@@ -73,6 +73,10 @@
mLocation = new Location(name);
}
+ public String getName() {
+ return mName;
+ }
+
public void disable() {
mEnabled = false;
}
@@ -81,6 +85,10 @@
mEnabled = true;
}
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+
public int getStatus(Bundle extras) {
if (mHasStatus) {
extras.clear();
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 8c1b0ea..34252ab 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -16,10 +16,14 @@
package android.media;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.IContentProvider;
-import android.content.ContentUris;
import android.database.Cursor;
import android.database.SQLException;
import android.graphics.BitmapFactory;
@@ -42,11 +46,12 @@
import android.util.Log;
import android.util.Xml;
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -586,6 +591,9 @@
}
if (genreCode >= 0 && genreCode < ID3_GENRES.length) {
value = ID3_GENRES[genreCode];
+ } else if (genreCode == 255) {
+ // 255 is defined to be unknown
+ value = null;
}
}
mGenre = value;
diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java
index d2596b8..65b67a1 100644
--- a/media/java/android/media/MediaScannerConnection.java
+++ b/media/java/android/media/MediaScannerConnection.java
@@ -57,17 +57,32 @@
};
/**
+ * Interface for notifying clients of the result of scanning a
+ * requested media file.
+ */
+ public interface ScanResultListener {
+ /**
+ * Called to notify the client when the media scanner has finished
+ * scanning a file.
+ * @param path the path to the file that has been scanned.
+ * @param uri the Uri for the file if the scanning operation succeeded
+ * and the file was added to the media database, or null if scanning failed.
+ */
+ public void onScanCompleted(String path, Uri uri);
+ }
+
+ /**
* An interface for notifying clients of MediaScannerConnection
* when a connection to the MediaScanner service has been established
* and when the scanning of a file has completed.
*/
- public interface MediaScannerConnectionClient {
+ public interface MediaScannerConnectionClient extends ScanResultListener {
/**
* Called to notify the client when a connection to the
* MediaScanner service has been established.
*/
public void onMediaScannerConnected();
-
+
/**
* Called to notify the client when the media scanner has finished
* scanning a file.
@@ -136,11 +151,12 @@
/**
* Requests the media scanner to scan a file.
+ * Success or failure of the scanning operation cannot be determined until
+ * {@link MediaScannerConnectionClient#onScanCompleted(String, Uri)} is called.
+ *
* @param path the path to the file to be scanned.
* @param mimeType an optional mimeType for the file.
* If mimeType is null, then the mimeType will be inferred from the file extension.
- * Success or failure of the scanning operation cannot be determined until
- * {@link MediaScannerConnectionClient#onScanCompleted(String, Uri)} is called.
*/
public void scanFile(String path, String mimeType) {
synchronized (this) {
@@ -159,7 +175,67 @@
}
}
}
-
+
+ static class ClientProxy implements MediaScannerConnectionClient {
+ final String[] mPaths;
+ final String[] mMimeTypes;
+ final ScanResultListener mClient;
+ MediaScannerConnection mConnection;
+ int mNextPath;
+
+ ClientProxy(String[] paths, String[] mimeTypes, ScanResultListener client) {
+ mPaths = paths;
+ mMimeTypes = mimeTypes;
+ mClient = client;
+ }
+
+ public void onMediaScannerConnected() {
+ scanNextPath();
+ }
+
+ public void onScanCompleted(String path, Uri uri) {
+ if (mClient != null) {
+ mClient.onScanCompleted(path, uri);
+ }
+ scanNextPath();
+ }
+
+ void scanNextPath() {
+ if (mNextPath >= mPaths.length) {
+ mConnection.disconnect();
+ return;
+ }
+ String mimeType = mMimeTypes != null ? mMimeTypes[mNextPath] : null;
+ mConnection.scanFile(mPaths[mNextPath], mimeType);
+ mNextPath++;
+ }
+ }
+
+ /**
+ * Convenience for constructing a {@link MediaScannerConnection}, calling
+ * {@link #connect} on it, and calling {@link #scanFile} with the given
+ * <var>path</var> and <var>mimeType</var> when the connection is
+ * established.
+ * @param context The caller's Context, required for establishing a connection to
+ * the media scanner service.
+ * Success or failure of the scanning operation cannot be determined until
+ * {@link MediaScannerConnectionClient#onScanCompleted(String, Uri)} is called.
+ * @param paths Array of paths to be scanned.
+ * @param mimeTypes Optional array of MIME types for each path.
+ * If mimeType is null, then the mimeType will be inferred from the file extension.
+ * @param callback Optional callback through which you can receive the
+ * scanned URI and MIME type; If null, the file will be scanned but
+ * you will not get a result back.
+ * @see scanFile(String, String)
+ */
+ public static void scanFile(Context context, String[] paths, String[] mimeTypes,
+ ScanResultListener callback) {
+ ClientProxy client = new ClientProxy(paths, mimeTypes, callback);
+ MediaScannerConnection connection = new MediaScannerConnection(context, client);
+ client.mConnection = connection;
+ connection.connect();
+ }
+
/**
* Part of the ServiceConnection interface. Do not call.
*/
diff --git a/media/libmedia/MediaScannerClient.cpp b/media/libmedia/MediaScannerClient.cpp
index bd3596e..bb3717f 100644
--- a/media/libmedia/MediaScannerClient.cpp
+++ b/media/libmedia/MediaScannerClient.cpp
@@ -64,29 +64,27 @@
bool MediaScannerClient::addStringTag(const char* name, const char* value)
{
- if (mLocaleEncoding != kEncodingNone) {
- // don't bother caching strings that are all ASCII.
- // call handleStringTag directly instead.
- // check to see if value (which should be utf8) has any non-ASCII characters
- bool nonAscii = false;
- const char* chp = value;
- char ch;
- while ((ch = *chp++)) {
- if (ch & 0x80) {
- nonAscii = true;
- break;
- }
+ // don't bother caching strings that are all ASCII.
+ // call handleStringTag directly instead.
+ // check to see if value (which should be utf8) has any non-ASCII characters
+ bool nonAscii = false;
+ const char* chp = value;
+ char ch;
+ while ((ch = *chp++)) {
+ if (ch & 0x80) {
+ nonAscii = true;
+ break;
}
-
- if (nonAscii) {
- // save the strings for later so they can be used for native encoding detection
- mNames->push_back(name);
- mValues->push_back(value);
- return true;
- }
- // else fall through
}
+ if (nonAscii) {
+ // save the strings for later so they can be used for native encoding detection
+ mNames->push_back(name);
+ mValues->push_back(value);
+ return true;
+ }
+ // else fall through
+
// autodetection is not necessary, so no need to cache the values
// pass directly to the client instead
return handleStringTag(name, value);
@@ -198,23 +196,29 @@
void MediaScannerClient::endFile()
{
- if (mLocaleEncoding != kEncodingNone) {
- int size = mNames->size();
- uint32_t encoding = kEncodingAll;
+ int size = mNames->size();
+ uint32_t encoding = kEncodingAll;
- // compute a bit mask containing all possible encodings
- for (int i = 0; i < mNames->size(); i++)
- encoding &= possibleEncodings(mValues->getEntry(i));
+ // compute a bit mask containing all possible encodings
+ for (int i = 0; i < mNames->size(); i++)
+ encoding &= possibleEncodings(mValues->getEntry(i));
- // if the locale encoding matches, then assume we have a native encoding.
- if (encoding & mLocaleEncoding)
- convertValues(mLocaleEncoding);
+ // If one of the possible encodings matches the locale encoding, use that.
+ // Otherwise, if there is only one possible encoding, use that.
+ if (encoding & mLocaleEncoding)
+ convertValues(mLocaleEncoding);
+ else if ((encoding & (encoding - 1)) == 0)
+ convertValues(encoding);
+ else {
+ // TODO: try harder to disambiguate the encoding, perhaps by looking at
+ // other files by same artist, or even the user's entire collection.
+ // For now, fall through and insert the strings as they are.
+ }
- // finally, push all name/value pairs to the client
- for (int i = 0; i < mNames->size(); i++) {
- if (!handleStringTag(mNames->getEntry(i), mValues->getEntry(i)))
- break;
- }
+ // finally, push all name/value pairs to the client
+ for (int i = 0; i < mNames->size(); i++) {
+ if (!handleStringTag(mNames->getEntry(i), mValues->getEntry(i)))
+ break;
}
// else addStringTag() has done all the work so we have nothing to do
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 8e61011..55b06f4 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1597,9 +1597,12 @@
AudioOutput *me = (AudioOutput *)cookie;
AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
- (*me->mCallback)(
+ size_t actualSize = (*me->mCallback)(
me, buffer->raw, buffer->size, me->mCallbackCookie);
- me->snoopWrite(buffer->raw, buffer->size);
+
+ if (actualSize > 0) {
+ me->snoopWrite(buffer->raw, actualSize);
+ }
}
#undef LOG_TAG
@@ -1629,14 +1632,75 @@
return NO_ERROR;
}
+////////////////////////////////////////////////////////////////////////////////
+
+struct CallbackThread : public Thread {
+ CallbackThread(const wp<MediaPlayerBase::AudioSink> &sink,
+ MediaPlayerBase::AudioSink::AudioCallback cb,
+ void *cookie);
+
+protected:
+ virtual ~CallbackThread();
+
+ virtual bool threadLoop();
+
+private:
+ wp<MediaPlayerBase::AudioSink> mSink;
+ MediaPlayerBase::AudioSink::AudioCallback mCallback;
+ void *mCookie;
+ void *mBuffer;
+ size_t mBufferSize;
+
+ CallbackThread(const CallbackThread &);
+ CallbackThread &operator=(const CallbackThread &);
+};
+
+CallbackThread::CallbackThread(
+ const wp<MediaPlayerBase::AudioSink> &sink,
+ MediaPlayerBase::AudioSink::AudioCallback cb,
+ void *cookie)
+ : mSink(sink),
+ mCallback(cb),
+ mCookie(cookie),
+ mBuffer(NULL),
+ mBufferSize(0) {
+}
+
+CallbackThread::~CallbackThread() {
+ if (mBuffer) {
+ free(mBuffer);
+ mBuffer = NULL;
+ }
+}
+
+bool CallbackThread::threadLoop() {
+ sp<MediaPlayerBase::AudioSink> sink = mSink.promote();
+ if (sink == NULL) {
+ return false;
+ }
+
+ if (mBuffer == NULL) {
+ mBufferSize = sink->bufferSize();
+ mBuffer = malloc(mBufferSize);
+ }
+
+ size_t actualSize =
+ (*mCallback)(sink.get(), mBuffer, mBufferSize, mCookie);
+
+ if (actualSize > 0) {
+ sink->write(mBuffer, actualSize);
+ }
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
status_t MediaPlayerService::AudioCache::open(
uint32_t sampleRate, int channelCount, int format, int bufferCount,
AudioCallback cb, void *cookie)
{
LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
- if (cb != NULL) {
- return UNKNOWN_ERROR; // TODO: implement this.
- }
if (mHeap->getHeapID() < 0) {
return NO_INIT;
}
@@ -1645,9 +1709,25 @@
mChannelCount = (uint16_t)channelCount;
mFormat = (uint16_t)format;
mMsecsPerFrame = 1.e3 / (float) sampleRate;
+
+ if (cb != NULL) {
+ mCallbackThread = new CallbackThread(this, cb, cookie);
+ }
return NO_ERROR;
}
+void MediaPlayerService::AudioCache::start() {
+ if (mCallbackThread != NULL) {
+ mCallbackThread->run("AudioCache callback");
+ }
+}
+
+void MediaPlayerService::AudioCache::stop() {
+ if (mCallbackThread != NULL) {
+ mCallbackThread->requestExitAndWait();
+ }
+}
+
ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size)
{
LOGV("write(%p, %u)", buffer, size);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index ffe1ba0..5c03e47 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -139,9 +139,9 @@
int bufferCount = 1,
AudioCallback cb = NULL, void *cookie = NULL);
- virtual void start() {}
+ virtual void start();
virtual ssize_t write(const void* buffer, size_t size);
- virtual void stop() {}
+ virtual void stop();
virtual void flush() {}
virtual void pause() {}
virtual void close() {}
@@ -171,6 +171,8 @@
uint32_t mSize;
int mError;
bool mCommandComplete;
+
+ sp<Thread> mCallbackThread;
};
public:
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 6383f0c..1a8109c 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -185,6 +185,11 @@
mAudioEncoder == AUDIO_ENCODER_AMR_NB
? MEDIA_MIMETYPE_AUDIO_AMR_NB : MEDIA_MIMETYPE_AUDIO_AMR_WB);
+ int32_t maxInputSize;
+ CHECK(audioSource->getFormat()->findInt32(
+ kKeyMaxInputSize, &maxInputSize));
+
+ encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
encMeta->setInt32(kKeyChannelCount, 1);
encMeta->setInt32(kKeySampleRate, sampleRate);
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index caff452..bf4424b 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -173,12 +173,15 @@
buffer->range_length(),
mFile);
- buffer->release();
- buffer = NULL;
-
if (n < (ssize_t)buffer->range_length()) {
+ buffer->release();
+ buffer = NULL;
+
break;
}
+
+ buffer->release();
+ buffer = NULL;
}
Mutex::Autolock autoLock(mLock);
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 4926920..12d7ee2 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -187,12 +187,12 @@
}
// static
-void AudioPlayer::AudioSinkCallback(
+size_t AudioPlayer::AudioSinkCallback(
MediaPlayerBase::AudioSink *audioSink,
void *buffer, size_t size, void *cookie) {
AudioPlayer *me = (AudioPlayer *)cookie;
- me->fillBuffer(buffer, size);
+ return me->fillBuffer(buffer, size);
}
void AudioPlayer::AudioCallback(int event, void *info) {
@@ -201,17 +201,18 @@
}
AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
- fillBuffer(buffer->raw, buffer->size);
+ size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size);
+
+ buffer->size = numBytesWritten;
}
-void AudioPlayer::fillBuffer(void *data, size_t size) {
+size_t AudioPlayer::fillBuffer(void *data, size_t size) {
if (mNumFramesPlayed == 0) {
LOGV("AudioCallback");
}
if (mReachedEOS) {
- memset(data, 0, size);
- return;
+ return 0;
}
size_t size_done = 0;
@@ -244,7 +245,6 @@
if (err != OK) {
mReachedEOS = true;
- memset((char *)data + size_done, 0, size_remaining);
break;
}
@@ -285,7 +285,9 @@
}
Mutex::Autolock autoLock(mLock);
- mNumFramesPlayed += size / mFrameSize;
+ mNumFramesPlayed += size_done / mFrameSize;
+
+ return size_done;
}
int64_t AudioPlayer::getRealTimeUs() {
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index c0a2f5b..a13b242 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -111,6 +111,7 @@
AwesomePlayer::AwesomePlayer()
: mTimeSource(NULL),
mAudioPlayer(NULL),
+ mFlags(0),
mLastVideoBuffer(NULL),
mVideoBuffer(NULL) {
CHECK_EQ(mClient.connect(), OK);
@@ -167,23 +168,17 @@
reset_l();
- sp<DataSource> dataSource = DataSource::CreateFromURI(uri, headers);
+ mUri = uri;
- if (dataSource == NULL) {
- return UNKNOWN_ERROR;
+ if (headers) {
+ mUriHeaders = *headers;
}
- sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+ // The actual work will be done during preparation in the call to
+ // ::finishSetDataSource_l to avoid blocking the calling thread in
+ // setDataSource for any significant time.
- if (extractor == NULL) {
- return UNKNOWN_ERROR;
- }
-
- if (dataSource->flags() & DataSource::kWantsPrefetching) {
- mPrefetcher = new Prefetcher;
- }
-
- return setDataSource_l(extractor);
+ return OK;
}
status_t AwesomePlayer::setDataSource(
@@ -242,6 +237,10 @@
}
void AwesomePlayer::reset_l() {
+ while (mFlags & PREPARING) {
+ mPreparedCondition.wait(mLock);
+ }
+
cancelPlayerEvents();
mVideoRenderer.clear();
@@ -290,6 +289,9 @@
mSeekTimeUs = 0;
mPrefetcher.clear();
+
+ mUri.setTo("");
+ mUriHeaders.clear();
}
void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
@@ -350,6 +352,14 @@
return OK;
}
+ if (!(mFlags & PREPARED)) {
+ status_t err = prepare_l();
+
+ if (err != OK) {
+ return err;
+ }
+ }
+
mFlags |= PLAYING;
mFlags |= FIRST_FRAME;
@@ -815,30 +825,49 @@
status_t AwesomePlayer::prepare() {
Mutex::Autolock autoLock(mLock);
+ return prepare_l();
+}
+status_t AwesomePlayer::prepare_l() {
+ if (mFlags & PREPARED) {
+ return OK;
+ }
+
+ if (mFlags & PREPARING) {
+ return UNKNOWN_ERROR;
+ }
+
+ mIsAsyncPrepare = false;
status_t err = prepareAsync_l();
if (err != OK) {
return err;
}
- while (mAsyncPrepareEvent != NULL) {
+ while (mFlags & PREPARING) {
mPreparedCondition.wait(mLock);
}
- return OK;
+ return mPrepareResult;
}
status_t AwesomePlayer::prepareAsync() {
Mutex::Autolock autoLock(mLock);
+
+ if (mFlags & PREPARING) {
+ return UNKNOWN_ERROR; // async prepare already pending
+ }
+
+ mIsAsyncPrepare = true;
return prepareAsync_l();
}
status_t AwesomePlayer::prepareAsync_l() {
- if (mAsyncPrepareEvent != NULL) {
- return UNKNOWN_ERROR; // async prepare already pending.
+ if (mFlags & PREPARING) {
+ return UNKNOWN_ERROR; // async prepare already pending
}
+ mFlags |= PREPARING;
mAsyncPrepareEvent = new AwesomeEvent(
this, &AwesomePlayer::onPrepareAsyncEvent);
@@ -847,7 +876,49 @@
return OK;
}
+status_t AwesomePlayer::finishSetDataSource_l() {
+ sp<DataSource> dataSource =
+ DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
+
+ if (dataSource == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+
+ if (extractor == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (dataSource->flags() & DataSource::kWantsPrefetching) {
+ mPrefetcher = new Prefetcher;
+ }
+
+ return setDataSource_l(extractor);
+}
+
void AwesomePlayer::onPrepareAsyncEvent() {
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mUri.size() > 0) {
+ status_t err = finishSetDataSource_l();
+
+ if (err != OK) {
+ if (mIsAsyncPrepare) {
+ notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
+ }
+
+ mPrepareResult = err;
+ mFlags &= ~PREPARING;
+ mAsyncPrepareEvent = NULL;
+ mPreparedCondition.broadcast();
+
+ return;
+ }
+ }
+ }
+
sp<Prefetcher> prefetcher;
{
@@ -861,16 +932,21 @@
Mutex::Autolock autoLock(mLock);
- if (mVideoWidth < 0 || mVideoHeight < 0) {
- notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
- } else {
- notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
+ if (mIsAsyncPrepare) {
+ if (mVideoWidth < 0 || mVideoHeight < 0) {
+ notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
+ } else {
+ notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
+ }
+
+ notifyListener_l(MEDIA_PREPARED);
}
- notifyListener_l(MEDIA_PREPARED);
-
+ mPrepareResult = OK;
+ mFlags &= ~PREPARING;
+ mFlags |= PREPARED;
mAsyncPrepareEvent = NULL;
- mPreparedCondition.signal();
+ mPreparedCondition.broadcast();
}
} // namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index e41b366..1ff38ee 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1070,6 +1070,11 @@
metadataKey = kKeyGenre;
break;
}
+ case FOURCC(0xa9, 'g', 'e', 'n'):
+ {
+ metadataKey = kKeyGenre;
+ break;
+ }
case FOURCC('t', 'r', 'k', 'n'):
{
if (size == 16 && flags == 0) {
@@ -1077,11 +1082,22 @@
sprintf(tmp, "%d/%d",
(int)buffer[size - 5], (int)buffer[size - 3]);
- printf("track: %s\n", tmp);
mFileMetaData->setCString(kKeyCDTrackNumber, tmp);
}
break;
}
+ case FOURCC('d', 'i', 's', 'k'):
+ {
+ if (size == 14 && flags == 0) {
+ char tmp[16];
+ sprintf(tmp, "%d/%d",
+ (int)buffer[size - 3], (int)buffer[size - 1]);
+
+ mFileMetaData->setCString(kKeyDiscNumber, tmp);
+ }
+ break;
+ }
+
default:
break;
}
@@ -1093,11 +1109,25 @@
buffer + 8, size - 8);
} else if (metadataKey == kKeyGenre) {
if (flags == 0) {
- // uint8_t
+ // uint8_t genre code, iTunes genre codes are
+ // the standard id3 codes, except they start
+ // at 1 instead of 0 (e.g. Pop is 14, not 13)
+ // We use standard id3 numbering, so subtract 1.
+ int genrecode = (int)buffer[size - 1];
+ genrecode--;
+ if (genrecode < 0) {
+ genrecode = 255; // reserved for 'unknown genre'
+ }
char genre[10];
- sprintf(genre, "%d", (int)buffer[size - 1]);
+ sprintf(genre, "%d", genrecode);
mFileMetaData->setCString(metadataKey, genre);
+ } else if (flags == 1) {
+ // custom genre string
+ buffer[size] = '\0';
+
+ mFileMetaData->setCString(
+ metadataKey, (const char *)buffer + 8);
}
} else {
buffer[size] = '\0';
@@ -1510,7 +1540,7 @@
if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
|| !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)
- || !memcmp(header, "ftypM4A ", 8)) {
+ || !memcmp(header, "ftypM4A ", 8) || !memcmp(header, "ftypf4v ", 8)) {
*mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
*confidence = 0.1;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 7c7c9e2..75b7b6f 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -112,7 +112,6 @@
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Decoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
- { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.Decoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Decoder" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
@@ -139,6 +138,7 @@
#define CODEC_LOGI(x, ...) LOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
#define CODEC_LOGV(x, ...) LOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
+#define CODEC_LOGE(x, ...) LOGE("[%s] "x, mComponentName, ##__VA_ARGS__)
struct OMXCodecObserver : public BnOMXObserver {
OMXCodecObserver() {
@@ -1931,10 +1931,17 @@
srcLength = srcBuffer->range_length();
if (info->mSize < srcLength) {
- LOGE("info->mSize = %d, srcLength = %d",
+ CODEC_LOGE(
+ "Codec's input buffers are too small to accomodate "
+ "buffer read from source (info->mSize = %d, srcLength = %d)",
info->mSize, srcLength);
+
+ srcBuffer->release();
+ srcBuffer = NULL;
+
+ setState(ERROR);
+ return;
}
- CHECK(info->mSize >= srcLength);
memcpy(info->mData,
(const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
srcLength);
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 651b910..a19784b 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -58,6 +58,7 @@
void reset();
status_t prepare();
+ status_t prepare_l();
status_t prepareAsync();
status_t prepareAsync_l();
@@ -84,6 +85,8 @@
PLAYING = 1,
LOOPING = 2,
FIRST_FRAME = 4,
+ PREPARING = 8,
+ PREPARED = 16,
};
mutable Mutex mLock;
@@ -97,6 +100,9 @@
TimeSource *mTimeSource;
+ String8 mUri;
+ KeyedVector<String8, String8> mUriHeaders;
+
sp<MediaSource> mVideoSource;
sp<AwesomeRenderer> mVideoRenderer;
@@ -127,6 +133,8 @@
sp<TimedEventQueue::Event> mAsyncPrepareEvent;
Condition mPreparedCondition;
+ bool mIsAsyncPrepare;
+ status_t mPrepareResult;
void postVideoEvent_l(int64_t delayUs = -1);
void postBufferingEvent_l();
@@ -158,6 +166,7 @@
void onBufferingUpdate();
void onCheckAudioStatus();
void onPrepareAsyncEvent();
+ status_t finishSetDataSource_l();
AwesomePlayer(const AwesomePlayer &);
AwesomePlayer &operator=(const AwesomePlayer &);
diff --git a/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java b/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
index 6b3093f..1434d3f 100644
--- a/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
+++ b/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
@@ -43,10 +43,9 @@
private TestThread mThread;
private static final int[] mTestFiles = new int[] {
- // FIXME: Restore when Stagefright bug is fixed
R.raw.organ441,
R.raw.sine441,
- //R.raw.test1,
+ R.raw.test1,
R.raw.test2,
R.raw.test3,
R.raw.test4,
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index 3d72017..5ec72df 100755
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -5,9 +5,9 @@
<uses-permission android:name="android.permission.ASEC_CREATE"/>
<uses-permission android:name="android.permission.ASEC_DESTROY"/>
<uses-permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <application android:process="def.container.service"
- android:label="@string/service_name">
+ <application android:label="@string/service_name">
<service android:name=".DefaultContainerService"
android:enabled="true"
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index fecd366..c418ccb 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -3,8 +3,11 @@
import com.android.internal.app.IMediaContainerService;
import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Debug;
+import android.os.Environment;
import android.os.IBinder;
import android.os.storage.IMountService;
import android.os.storage.StorageResultCode;
@@ -12,6 +15,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.app.IntentService;
import android.app.Service;
import android.util.Log;
@@ -25,7 +29,6 @@
import android.os.FileUtils;
-
/*
* This service copies a downloaded apk to a file passed in as
* a ParcelFileDescriptor or to a newly created container specified
@@ -33,7 +36,7 @@
* based on its uid. This process also needs the ACCESS_DOWNLOAD_MANAGER
* permission to access apks downloaded via the download manager.
*/
-public class DefaultContainerService extends Service {
+public class DefaultContainerService extends IntentService {
private static final String TAG = "DefContainer";
private static final boolean localLOGV = false;
@@ -78,6 +81,40 @@
}
};
+ public DefaultContainerService() {
+ super("DefaultContainerService");
+ setIntentRedelivery(true);
+ }
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+ if (PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE.equals(intent.getAction())) {
+ IPackageManager pm = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ String pkg = null;
+ try {
+ while ((pkg=pm.nextPackageToClean(pkg)) != null) {
+ eraseFiles(Environment.getExternalStorageAppDataDirectory(pkg));
+ eraseFiles(Environment.getExternalStorageAppMediaDirectory(pkg));
+ }
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ void eraseFiles(File path) {
+ if (path.isDirectory()) {
+ String[] files = path.list();
+ if (files != null) {
+ for (String file : files) {
+ eraseFiles(new File(path, file));
+ }
+ }
+ }
+ //Log.i(TAG, "Deleting: " + path);
+ path.delete();
+ }
+
public IBinder onBind(Intent intent) {
return mBinder;
}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 7686aa0..ba6024f 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -56,5 +56,6 @@
<bool name="def_mount_ums_autostart">false</bool>
<bool name="def_mount_ums_prompt">true</bool>
<bool name="def_mount_ums_notify_enabled">true</bool>
+ <bool name="set_install_location">true</bool>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 015b487..8b75b61 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.Cursor;
@@ -864,6 +865,9 @@
loadBooleanSetting(stmt, Settings.System.NOTIFICATION_LIGHT_PULSE,
R.bool.def_notification_pulse);
+ loadBooleanSetting(stmt, Settings.System.SET_INSTALL_LOCATION, R.bool.set_install_location);
+ loadSetting(stmt, Settings.System.DEFAULT_INSTALL_LOCATION,
+ PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
stmt.close();
}
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index e4ee4ae..1625d9f 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -320,14 +320,18 @@
}
tag = parser.getName();
if ("admin".equals(tag)) {
- DeviceAdminInfo dai = findAdmin(
- ComponentName.unflattenFromString(
- parser.getAttributeValue(null, "name")));
- if (dai != null) {
- ActiveAdmin ap = new ActiveAdmin(dai);
- ap.readFromXml(parser);
- mAdminMap.put(ap.info.getComponent(), ap);
- mAdminList.add(ap);
+ String name = parser.getAttributeValue(null, "name");
+ try {
+ DeviceAdminInfo dai = findAdmin(
+ ComponentName.unflattenFromString(name));
+ if (dai != null) {
+ ActiveAdmin ap = new ActiveAdmin(dai);
+ ap.readFromXml(parser);
+ mAdminMap.put(ap.info.getComponent(), ap);
+ mAdminList.add(ap);
+ }
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Failed loading admin " + name, e);
}
} else if ("failed-password-attempts".equals(tag)) {
mFailedPasswordAttempts = Integer.parseInt(
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index fff6c54..e12f2e1 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -45,11 +45,11 @@
import android.location.IGpsStatusProvider;
import android.location.ILocationListener;
import android.location.ILocationManager;
-import android.location.ILocationProvider;
import android.location.INetInitiatedListener;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
+import android.location.LocationProviderInterface;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
@@ -114,8 +114,8 @@
private LocationWorkerHandler mLocationHandler;
// Cache the real providers for use in addTestProvider() and removeTestProvider()
- LocationProviderProxy mNetworkLocationProvider;
- LocationProviderProxy mGpsLocationProvider;
+ LocationProviderInterface mNetworkLocationProvider;
+ LocationProviderInterface mGpsLocationProvider;
// Handler messages
private static final int MESSAGE_LOCATION_CHANGED = 1;
@@ -134,10 +134,10 @@
/**
* List of location providers.
*/
- private final ArrayList<LocationProviderProxy> mProviders =
- new ArrayList<LocationProviderProxy>();
- private final HashMap<String, LocationProviderProxy> mProvidersByName
- = new HashMap<String, LocationProviderProxy>();
+ private final ArrayList<LocationProviderInterface> mProviders =
+ new ArrayList<LocationProviderInterface>();
+ private final HashMap<String, LocationProviderInterface> mProvidersByName
+ = new HashMap<String, LocationProviderInterface>();
/**
* Object used internally for synchronization
@@ -411,12 +411,12 @@
}
}
- private void addProvider(LocationProviderProxy provider) {
+ private void addProvider(LocationProviderInterface provider) {
mProviders.add(provider);
mProvidersByName.put(provider.getName(), provider);
}
- private void removeProvider(LocationProviderProxy provider) {
+ private void removeProvider(LocationProviderInterface provider) {
mProviders.remove(provider);
mProvidersByName.remove(provider.getName());
}
@@ -445,13 +445,11 @@
// Attempt to load "real" providers first
if (GpsLocationProvider.isSupported()) {
// Create a gps location provider
- GpsLocationProvider provider = new GpsLocationProvider(mContext, this);
- mGpsStatusProvider = provider.getGpsStatusProvider();
- mNetInitiatedListener = provider.getNetInitiatedListener();
- LocationProviderProxy proxy =
- new LocationProviderProxy(mContext, LocationManager.GPS_PROVIDER, provider);
- addProvider(proxy);
- mGpsLocationProvider = proxy;
+ GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
+ mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
+ mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
+ addProvider(gpsProvider);
+ mGpsLocationProvider = gpsProvider;
}
// initialize external network location and geocoder services
@@ -591,7 +589,7 @@
}
ArrayList<String> out = new ArrayList<String>(mProviders.size());
for (int i = mProviders.size() - 1; i >= 0; i--) {
- LocationProviderProxy p = mProviders.get(i);
+ LocationProviderInterface p = mProviders.get(i);
out.add(p.getName());
}
return out;
@@ -616,7 +614,7 @@
}
ArrayList<String> out = new ArrayList<String>(mProviders.size());
for (int i = mProviders.size() - 1; i >= 0; i--) {
- LocationProviderProxy p = mProviders.get(i);
+ LocationProviderInterface p = mProviders.get(i);
String name = p.getName();
if (isAllowedProviderSafe(name)) {
if (enabledOnly && !isAllowedBySettingsLocked(name)) {
@@ -630,7 +628,7 @@
private void updateProvidersLocked() {
for (int i = mProviders.size() - 1; i >= 0; i--) {
- LocationProviderProxy p = mProviders.get(i);
+ LocationProviderInterface p = mProviders.get(i);
boolean isEnabled = p.isEnabled();
String name = p.getName();
boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
@@ -647,7 +645,7 @@
private void updateProviderListenersLocked(String provider, boolean enabled) {
int listeners = 0;
- LocationProviderProxy p = mProvidersByName.get(provider);
+ LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
return;
}
@@ -837,8 +835,8 @@
Log.v(TAG, "_requestLocationUpdates: listener = " + receiver);
}
- LocationProviderProxy proxy = mProvidersByName.get(provider);
- if (proxy == null) {
+ LocationProviderInterface p = mProvidersByName.get(provider);
+ if (p == null) {
throw new IllegalArgumentException("provider=" + provider);
}
@@ -856,14 +854,14 @@
}
if (newUid) {
- proxy.addListener(callingUid);
+ p.addListener(callingUid);
}
boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
if (isProviderEnabled) {
long minTimeForProvider = getMinTimeLocked(provider);
- proxy.setMinTime(minTimeForProvider);
- proxy.enableLocationTracking(true);
+ p.setMinTime(minTimeForProvider);
+ p.enableLocationTracking(true);
} else {
// Notify the listener that updates are currently disabled
receiver.callProviderEnabledLocked(provider, false);
@@ -923,9 +921,9 @@
// Call dispose() on the obsolete update records.
for (UpdateRecord record : oldRecords.values()) {
if (!providerHasListener(record.mProvider, callingUid, receiver)) {
- LocationProviderProxy proxy = mProvidersByName.get(record.mProvider);
- if (proxy != null) {
- proxy.removeListener(callingUid);
+ LocationProviderInterface p = mProvidersByName.get(record.mProvider);
+ if (p != null) {
+ p.removeListener(callingUid);
}
}
record.disposeLocked();
@@ -949,7 +947,7 @@
hasOtherListener = true;
}
- LocationProviderProxy p = mProvidersByName.get(provider);
+ LocationProviderInterface p = mProvidersByName.get(provider);
if (p != null) {
if (hasOtherListener) {
p.setMinTime(getMinTimeLocked(provider));
@@ -1006,12 +1004,12 @@
}
synchronized (mLock) {
- LocationProviderProxy proxy = mProvidersByName.get(provider);
- if (proxy == null) {
+ LocationProviderInterface p = mProvidersByName.get(provider);
+ if (p == null) {
return false;
}
- return proxy.sendExtraCommand(command, extras);
+ return p.sendExtraCommand(command, extras);
}
}
@@ -1261,7 +1259,7 @@
mProximityReceiver = new Receiver(mProximityListener);
for (int i = mProviders.size() - 1; i >= 0; i--) {
- LocationProviderProxy provider = mProviders.get(i);
+ LocationProviderInterface provider = mProviders.get(i);
requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
}
}
@@ -1311,7 +1309,7 @@
}
private Bundle _getProviderInfoLocked(String provider) {
- LocationProviderProxy p = mProvidersByName.get(provider);
+ LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null || !p.isEnabled()) {
return null;
}
@@ -1359,7 +1357,7 @@
private boolean _isProviderEnabledLocked(String provider) {
checkPermissionsSafe(provider);
- LocationProviderProxy p = mProvidersByName.get(provider);
+ LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
throw new IllegalArgumentException("provider=" + provider);
}
@@ -1382,7 +1380,7 @@
private Location _getLastKnownLocationLocked(String provider) {
checkPermissionsSafe(provider);
- LocationProviderProxy p = mProvidersByName.get(provider);
+ LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
throw new IllegalArgumentException("provider=" + provider);
}
@@ -1424,7 +1422,7 @@
return;
}
- LocationProviderProxy p = mProvidersByName.get(provider);
+ LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
return;
}
@@ -1507,9 +1505,9 @@
// notify other providers of the new location
for (int i = mProviders.size() - 1; i >= 0; i--) {
- LocationProviderProxy proxy = mProviders.get(i);
- if (!provider.equals(proxy.getName())) {
- proxy.updateLocation(location);
+ LocationProviderInterface p = mProviders.get(i);
+ if (!provider.equals(p.getName())) {
+ p.updateLocation(location);
}
}
@@ -1597,7 +1595,7 @@
// Notify location providers of current network state
synchronized (mLock) {
for (int i = mProviders.size() - 1; i >= 0; i--) {
- LocationProviderProxy provider = mProviders.get(i);
+ LocationProviderInterface provider = mProviders.get(i);
if (provider.isEnabled() && provider.requiresNetwork()) {
provider.updateNetworkState(mNetworkState, info);
}
@@ -1698,16 +1696,16 @@
// remove the real provider if we are replacing GPS or network provider
if (LocationManager.GPS_PROVIDER.equals(name)
|| LocationManager.NETWORK_PROVIDER.equals(name)) {
- LocationProviderProxy proxy = mProvidersByName.get(name);
- if (proxy != null) {
- proxy.enableLocationTracking(false);
- removeProvider(proxy);
+ LocationProviderInterface p = mProvidersByName.get(name);
+ if (p != null) {
+ p.enableLocationTracking(false);
+ removeProvider(p);
}
}
if (mProvidersByName.get(name) != null) {
throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
}
- addProvider(new LocationProviderProxy(mContext, name, provider));
+ addProvider(provider);
mMockProviders.put(name, provider);
mLastKnownLocation.put(name, null);
updateProvidersLocked();
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 6de2eff..456244a 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -37,6 +37,7 @@
import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
+import java.util.HashSet;
import java.io.File;
import java.io.FileReader;
@@ -116,6 +117,11 @@
private boolean mBooted;
private boolean mReady;
+ /**
+ * Private hash of currently mounted secure containers.
+ */
+ private HashSet<String> mAsecMountSet = new HashSet<String>();
+
private void waitForReady() {
while (mReady == false) {
for (int retries = 5; retries > 0; retries--) {
@@ -177,8 +183,12 @@
String vs = getVolumeState(path);
if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
mUmsEnabling = enable; // Override for isUsbMassStorageEnabled()
- doUnmountVolume(path);
+ int rc = doUnmountVolume(path);
mUmsEnabling = false; // Clear override
+ if (rc != StorageResultCode.OperationSucceeded) {
+ Log.e(TAG, String.format("Failed to unmount before enabling UMS (%d)", rc));
+ return rc;
+ }
}
try {
@@ -517,7 +527,7 @@
}
private int doUnmountVolume(String path) {
- if (getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
+ if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
return VoldResponseCode.OpFailedVolNotMounted;
}
@@ -858,6 +868,12 @@
} catch (NativeDaemonConnectorException e) {
rc = StorageResultCode.OperationFailedInternalError;
}
+
+ if (rc == StorageResultCode.OperationSucceeded) {
+ synchronized (mAsecMountSet) {
+ mAsecMountSet.add(id);
+ }
+ }
return rc;
}
@@ -866,6 +882,12 @@
waitForReady();
warnOnNotMounted();
+ synchronized (mAsecMountSet) {
+ if (!mAsecMountSet.contains(id)) {
+ return StorageResultCode.OperationFailedVolumeNotMounted;
+ }
+ }
+
int rc = StorageResultCode.OperationSucceeded;
String cmd = String.format("asec unmount %s", id);
try {
@@ -873,9 +895,25 @@
} catch (NativeDaemonConnectorException e) {
rc = StorageResultCode.OperationFailedInternalError;
}
+
+ if (rc == StorageResultCode.OperationSucceeded) {
+ synchronized (mAsecMountSet) {
+ mAsecMountSet.remove(id);
+ }
+ }
return rc;
}
+ public boolean isSecureContainerMounted(String id) {
+ validatePermission(android.Manifest.permission.ASEC_ACCESS);
+ waitForReady();
+ warnOnNotMounted();
+
+ synchronized (mAsecMountSet) {
+ return mAsecMountSet.contains(id);
+ }
+ }
+
public int renameSecureContainer(String oldId, String newId) {
validatePermission(android.Manifest.permission.ASEC_RENAME);
waitForReady();
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index ad8ab84..3657133 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -50,7 +50,6 @@
import android.os.Power;
import android.os.Process;
import android.os.RemoteException;
-import android.os.storage.StorageManager;
import android.os.SystemProperties;
import android.os.Vibrator;
import android.provider.Settings;
@@ -408,9 +407,6 @@
mToastQueue = new ArrayList<ToastRecord>();
mHandler = new WorkerHandler();
- StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
- sm.registerListener(new com.android.internal.app.StorageNotification(context));
-
mStatusBarService = statusBar;
statusBar.setNotificationCallbacks(mNotificationCallbacks);
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index c99480f..1cda2ff 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -20,6 +20,7 @@
import com.android.internal.app.ResolverActivity;
import com.android.common.FastXmlSerializer;
import com.android.common.XmlUtils;
+import com.android.server.JournaledFile;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -148,6 +149,10 @@
static final int SCAN_NEW_INSTALL = 1<<4;
static final int SCAN_NO_PATHS = 1<<5;
+ static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
+ "com.android.defcontainer",
+ "com.android.defcontainer.DefaultContainerService");
+
final HandlerThread mHandlerThread = new HandlerThread("PackageManager",
Process.THREAD_PRIORITY_BACKGROUND);
final PackageHandler mHandler;
@@ -298,6 +303,7 @@
static final int END_COPY = 4;
static final int INIT_COPY = 5;
static final int MCS_UNBIND = 6;
+ static final int START_CLEANING_PACKAGE = 7;
// Delay time in millisecs
static final int BROADCAST_DELAY = 10 * 1000;
private ServiceConnection mDefContainerConn = new ServiceConnection() {
@@ -328,9 +334,7 @@
case INIT_COPY: {
InstallArgs args = (InstallArgs) msg.obj;
args.createCopyFile();
- Intent service = new Intent().setComponent(new ComponentName(
- "com.android.defcontainer",
- "com.android.defcontainer.DefaultContainerService"));
+ Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
if (mContainerService != null) {
// No need to add to pending list. Use remote stub directly
handleStartCopy(args);
@@ -405,6 +409,15 @@
}
break;
}
+ case START_CLEANING_PACKAGE: {
+ String packageName = (String)msg.obj;
+ synchronized (mPackages) {
+ if (!mSettings.mPackagesToBeCleaned.contains(packageName)) {
+ mSettings.mPackagesToBeCleaned.add(packageName);
+ }
+ }
+ startCleaningPackages();
+ } break;
}
}
@@ -2737,9 +2750,9 @@
+ pkgSetting.name;
reportSettingsProblem(Log.WARN, msg);
}
+ // And now uninstall the old package.
+ mInstaller.remove(pkgSetting.origPackage.name, useEncryptedFSDir);
}
- // And now uninstall the old package.
- mInstaller.remove(pkgSetting.origPackage.name, useEncryptedFSDir);
mSettings.removePackageLP(pkgSetting.origPackage.name);
}
}
@@ -2823,6 +2836,9 @@
mSettings.insertPackageSettingLP(pkgSetting, pkg);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);
+ // Make sure we don't accidentally delete its data.
+ mSettings.mPackagesToBeCleaned.remove(pkgName);
+
int N = pkg.providers.size();
StringBuilder r = null;
int i;
@@ -4018,7 +4034,47 @@
}
}
}
+
+ public String nextPackageToClean(String lastPackage) {
+ synchronized (mPackages) {
+ if (!mMediaMounted) {
+ // If the external storage is no longer mounted at this point,
+ // the caller may not have been able to delete all of this
+ // packages files and can not delete any more. Bail.
+ return null;
+ }
+ if (lastPackage != null) {
+ mSettings.mPackagesToBeCleaned.remove(lastPackage);
+ }
+ return mSettings.mPackagesToBeCleaned.size() > 0
+ ? mSettings.mPackagesToBeCleaned.get(0) : null;
+ }
+ }
+ void schedulePackageCleaning(String packageName) {
+ mHandler.sendMessage(mHandler.obtainMessage(START_CLEANING_PACKAGE, packageName));
+ }
+
+ void startCleaningPackages() {
+ synchronized (mPackages) {
+ if (!mMediaMounted) {
+ return;
+ }
+ if (mSettings.mPackagesToBeCleaned.size() <= 0) {
+ return;
+ }
+ }
+ Intent intent = new Intent(PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE);
+ intent.setComponent(DEFAULT_CONTAINER_COMPONENT);
+ IActivityManager am = ActivityManagerNative.getDefault();
+ if (am != null) {
+ try {
+ am.startService(null, intent, null);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
private final class AppDirObserver extends FileObserver {
public AppDirObserver(String path, int mask, boolean isrom) {
super(path, mask);
@@ -5224,7 +5280,6 @@
* persisting settings for later use
* sending a broadcast if necessary
*/
-
private boolean deletePackageX(String packageName, boolean sendBroadCast,
boolean deleteCodeAndResources, int flags) {
PackageRemovedInfo info = new PackageRemovedInfo();
@@ -5316,6 +5371,7 @@
File dataDir = new File(pkg.applicationInfo.dataDir);
dataDir.delete();
}
+ schedulePackageCleaning(packageName);
synchronized (mPackages) {
if (outInfo != null) {
outInfo.removedUid = mSettings.removePackageLP(packageName);
@@ -5328,7 +5384,7 @@
mSettings.updateSharedUserPermsLP(deletedPs, mGlobalGids);
}
// Save settings now
- mSettings.writeLP ();
+ mSettings.writeLP();
}
}
@@ -6771,6 +6827,7 @@
private static final class Settings {
private final File mSettingsFilename;
private final File mBackupSettingsFilename;
+ private final File mPackageListFilename;
private final HashMap<String, PackageSetting> mPackages =
new HashMap<String, PackageSetting>();
// List of replaced system applications
@@ -6817,6 +6874,10 @@
final HashMap<String, BasePermission> mPermissionTrees =
new HashMap<String, BasePermission>();
+ // Packages that have been uninstalled and still need their external
+ // storage data deleted.
+ final ArrayList<String> mPackagesToBeCleaned = new ArrayList<String>();
+
private final StringBuilder mReadMessages = new StringBuilder();
private static final class PendingPackage extends PackageSettingBase {
@@ -6848,6 +6909,7 @@
-1, -1);
mSettingsFilename = new File(systemDir, "packages.xml");
mBackupSettingsFilename = new File(systemDir, "packages-backup.xml");
+ mPackageListFilename = new File(systemDir, "packages.list");
}
PackageSetting getPackageLP(PackageParser.Package pkg, PackageSetting origPackage,
@@ -7380,6 +7442,14 @@
serializer.endTag(null, "shared-user");
}
+ if (mPackagesToBeCleaned.size() > 0) {
+ for (int i=0; i<mPackagesToBeCleaned.size(); i++) {
+ serializer.startTag(null, "cleaning-package");
+ serializer.attribute(null, "name", mPackagesToBeCleaned.get(i));
+ serializer.endTag(null, "cleaning-package");
+ }
+ }
+
serializer.endTag(null, "packages");
serializer.endDocument();
@@ -7395,6 +7465,61 @@
|FileUtils.S_IRGRP|FileUtils.S_IWGRP
|FileUtils.S_IROTH,
-1, -1);
+
+ // Write package list file now, use a JournaledFile.
+ //
+ File tempFile = new File(mPackageListFilename.toString() + ".tmp");
+ JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
+
+ str = new FileOutputStream(journal.chooseForWrite());
+ try {
+ StringBuilder sb = new StringBuilder();
+ for (PackageSetting pkg : mPackages.values()) {
+ ApplicationInfo ai = pkg.pkg.applicationInfo;
+ String dataPath = ai.dataDir;
+ boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+
+ // Avoid any application that has a space in its path
+ // or that is handled by the system.
+ if (dataPath.indexOf(" ") >= 0 || ai.uid <= Process.FIRST_APPLICATION_UID)
+ continue;
+
+ // we store on each line the following information for now:
+ //
+ // pkgName - package name
+ // userId - application-specific user id
+ // debugFlag - 0 or 1 if the package is debuggable.
+ // dataPath - path to package's data path
+ //
+ // NOTE: We prefer not to expose all ApplicationInfo flags for now.
+ //
+ // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
+ // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
+ // system/core/run-as/run-as.c
+ //
+ sb.setLength(0);
+ sb.append(ai.packageName);
+ sb.append(" ");
+ sb.append((int)ai.uid);
+ sb.append(isDebug ? " 1 " : " 0 ");
+ sb.append(dataPath);
+ sb.append("\n");
+ str.write(sb.toString().getBytes());
+ }
+ str.flush();
+ str.close();
+ journal.commit();
+ }
+ catch (Exception e) {
+ journal.rollback();
+ }
+
+ FileUtils.setPermissions(mPackageListFilename.toString(),
+ FileUtils.S_IRUSR|FileUtils.S_IWUSR
+ |FileUtils.S_IRGRP|FileUtils.S_IWGRP
+ |FileUtils.S_IROTH,
+ -1, -1);
+
return;
} catch(XmlPullParserException e) {
@@ -7402,7 +7527,7 @@
} catch(java.io.IOException e) {
Log.w(TAG, "Unable to write package manager settings, current changes will be lost at reboot", e);
}
- // Clean up partially written file
+ // Clean up partially written files
if (mSettingsFilename.exists()) {
if (!mSettingsFilename.delete()) {
Log.i(TAG, "Failed to clean up mangled file: " + mSettingsFilename);
@@ -7412,7 +7537,7 @@
}
void writeDisabledSysPackage(XmlSerializer serializer, final PackageSetting pkg)
- throws java.io.IOException {
+ throws java.io.IOException {
serializer.startTag(null, "updated-package");
serializer.attribute(null, "name", pkg.name);
serializer.attribute(null, "codePath", pkg.codePathString);
@@ -7450,7 +7575,7 @@
}
void writePackage(XmlSerializer serializer, final PackageSetting pkg)
- throws java.io.IOException {
+ throws java.io.IOException {
serializer.startTag(null, "package");
serializer.attribute(null, "name", pkg.name);
serializer.attribute(null, "codePath", pkg.codePathString);
@@ -7640,6 +7765,11 @@
readPreferredActivitiesLP(parser);
} else if(tagName.equals("updated-package")) {
readDisabledSysPackageLP(parser);
+ } else if (tagName.equals("cleaning-package")) {
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ mPackagesToBeCleaned.add(name);
+ }
} else {
Log.w(TAG, "Unknown element under <packages>: "
+ parser.getName());
@@ -7765,7 +7895,7 @@
}
private void readDisabledSysPackageLP(XmlPullParser parser)
- throws XmlPullParserException, IOException {
+ throws XmlPullParserException, IOException {
String name = parser.getAttributeValue(null, "name");
String codePathStr = parser.getAttributeValue(null, "codePath");
String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
@@ -8435,19 +8565,21 @@
}
public void updateExternalMediaStatus(final boolean mediaStatus) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
- mediaStatus+", mMediaMounted=" + mMediaMounted);
- if (mediaStatus == mMediaMounted) {
- return;
- }
- mMediaMounted = mediaStatus;
- // Queue up an async operation since the package installation may take a little while.
- mHandler.post(new Runnable() {
- public void run() {
- mHandler.removeCallbacks(this);
- updateExternalMediaStatusInner(mediaStatus);
+ synchronized (mPackages) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
+ mediaStatus+", mMediaMounted=" + mMediaMounted);
+ if (mediaStatus == mMediaMounted) {
+ return;
}
- });
+ mMediaMounted = mediaStatus;
+ // Queue up an async operation since the package installation may take a little while.
+ mHandler.post(new Runnable() {
+ public void run() {
+ mHandler.removeCallbacks(this);
+ updateExternalMediaStatusInner(mediaStatus);
+ }
+ });
+ }
}
void updateExternalMediaStatusInner(boolean mediaStatus) {
@@ -8505,6 +8637,7 @@
if (mediaStatus) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
loadMediaPackages(processCids, uidArr);
+ startCleaningPackages();
} else {
if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
unloadMediaPackages(processCids, uidArr);
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 7951fb7..60cf5a2 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -373,8 +373,11 @@
failedToStopSupplicantOrUnloadDriver = true;
}
- // We must reset the interface before we unload the driver
- mWifiStateTracker.resetInterface(false);
+ /**
+ * Reset connections and disable interface
+ * before we unload the driver
+ */
+ mWifiStateTracker.resetConnections(true);
if (!WifiNative.unloadDriver()) {
Log.e(TAG, "Failed to unload Wi-Fi driver.");
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 88aadbd..b57e543 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -5465,7 +5465,6 @@
curFocus = mCurrentFocus;
// cache the paused state at ctor time as well
if (theFocus == null || theFocus.mToken == null) {
- Log.i(TAG, "focus " + theFocus + " mToken is null at event dispatch!");
focusPaused = false;
} else {
focusPaused = theFocus.mToken.paused;
@@ -5478,7 +5477,7 @@
+ " fin=" + finished + " gfw=" + gotFirstWindow
+ " ed=" + eventDispatching + " tts=" + timeToSwitch
+ " wf=" + wasFrozen + " fp=" + focusPaused
- + " mcf=" + mCurrentFocus + "}}";
+ + " mcf=" + curFocus + "}}";
}
};
private DispatchState mDispatchState = null;
@@ -5651,10 +5650,11 @@
synchronized (this) {
Log.w(TAG, "Key dispatching timed out sending to " +
(targetWin != null ? targetWin.mAttrs.getTitle()
- : "<null>"));
+ : "<null>: no window ready for key dispatch"));
// NOSHIP debugging
- Log.w(TAG, "Dispatch state: " + mDispatchState);
- Log.w(TAG, "Current state: " + new DispatchState(nextKey, targetWin));
+ Log.w(TAG, "Previous dispatch state: " + mDispatchState);
+ Log.w(TAG, "Current dispatch state: " +
+ new DispatchState(nextKey, targetWin));
// END NOSHIP
//dump();
if (targetWin != null) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 98ded37..87ed252 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1949,6 +1949,9 @@
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
}
+ if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0) {
+ debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
+ }
if ("1".equals(SystemProperties.get("debug.checkjni"))) {
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index f5aeaf0..20209e4 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -37,6 +37,7 @@
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
+import android.os.storage.StorageManager;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
@@ -93,6 +94,9 @@
private IBinder mClockIcon;
private IconData mClockData;
+ // storage
+ private StorageManager mStorageManager;
+
// battery
private IBinder mBatteryIcon;
private IconData mBatteryData;
@@ -407,6 +411,11 @@
mClockIcon = service.addIcon(mClockData, null);
updateClock();
+ // storage
+ mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
+ mStorageManager.registerListener(
+ new com.android.server.status.StorageNotification(context));
+
// battery
mBatteryData = IconData.makeIcon("battery",
null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0);
diff --git a/core/java/com/android/internal/app/StorageNotification.java b/services/java/com/android/server/status/StorageNotification.java
similarity index 97%
rename from core/java/com/android/internal/app/StorageNotification.java
rename to services/java/com/android/server/status/StorageNotification.java
index 8876612..3b79049 100644
--- a/core/java/com/android/internal/app/StorageNotification.java
+++ b/services/java/com/android/server/status/StorageNotification.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.app;
+package com.android.server.status;
import android.app.Activity;
import android.app.Notification;
@@ -119,7 +119,7 @@
* for stopping UMS.
*/
Intent intent = new Intent();
- intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
+ intent.setClass(mContext, com.android.server.status.UsbStorageActivity.class);
PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
setUsbStorageNotification(
com.android.internal.R.string.usb_storage_stop_notification_title,
@@ -237,7 +237,7 @@
if (available) {
Intent intent = new Intent();
- intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
+ intent.setClass(mContext, com.android.server.status.UsbStorageActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
setUsbStorageNotification(
@@ -253,8 +253,8 @@
/**
* Sets the USB storage notification.
*/
- private synchronized void setUsbStorageNotification(int titleId, int messageId, int icon, boolean sound, boolean visible,
- PendingIntent pi) {
+ private synchronized void setUsbStorageNotification(int titleId, int messageId, int icon,
+ boolean sound, boolean visible, PendingIntent pi) {
if (!visible && mUsbStorageNotification == null) {
return;
diff --git a/core/java/com/android/internal/app/UsbStorageActivity.java b/services/java/com/android/server/status/UsbStorageActivity.java
similarity index 98%
rename from core/java/com/android/internal/app/UsbStorageActivity.java
rename to services/java/com/android/server/status/UsbStorageActivity.java
index 991f04b..7a2a2d6 100644
--- a/core/java/com/android/internal/app/UsbStorageActivity.java
+++ b/services/java/com/android/server/status/UsbStorageActivity.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.app;
+package com.android.server.status;
import android.app.Activity;
import android.content.BroadcastReceiver;
diff --git a/test-runner/android/test/TestLocationProvider.java b/test-runner/android/test/TestLocationProvider.java
deleted file mode 100644
index dc07585..0000000
--- a/test-runner/android/test/TestLocationProvider.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2007 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.test;
-
-
-import android.location.Criteria;
-import android.location.ILocationManager;
-import android.location.ILocationProvider;
-import android.location.Location;
-import android.location.LocationProvider;
-import android.net.NetworkInfo;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.util.Log;
-
-/**
- * @hide - This is part of a framework that is under development and should not be used for
- * active development.
- */
-public class TestLocationProvider extends ILocationProvider.Stub {
-
- public static final String PROVIDER_NAME = "test";
- public static final double LAT = 0;
- public static final double LON = 1;
- public static final double ALTITUDE = 10000;
- public static final float SPEED = 10;
- public static final float BEARING = 1;
- public static final int STATUS = LocationProvider.AVAILABLE;
- private static final long LOCATION_INTERVAL = 1000;
-
- private static final String TAG = "TestLocationProvider";
-
- private final ILocationManager mLocationManager;
- private Location mLocation;
- private boolean mEnabled;
- private TestLocationProviderThread mThread;
-
- private class TestLocationProviderThread extends Thread {
-
- private boolean mDone = false;
-
- public TestLocationProviderThread() {
- super("TestLocationProviderThread");
- }
-
- public void run() {
- // thread exits after disable() is called
- synchronized (this) {
- while (!mDone) {
- try {
- wait(LOCATION_INTERVAL);
- } catch (InterruptedException e) {
- }
-
- if (!mDone) {
- TestLocationProvider.this.updateLocation();
- }
- }
- }
- }
-
- synchronized void setDone() {
- mDone = true;
- notify();
- }
- }
-
- public TestLocationProvider(ILocationManager locationManager) {
- mLocationManager = locationManager;
- mLocation = new Location(PROVIDER_NAME);
- }
-
- public int getAccuracy() {
- return Criteria.ACCURACY_COARSE;
- }
-
- public int getPowerRequirement() {
- return Criteria.NO_REQUIREMENT;
- }
-
- public boolean hasMonetaryCost() {
- return false;
- }
-
- public boolean requiresCell() {
- return false;
- }
-
- public boolean requiresNetwork() {
- return false;
- }
-
- public boolean requiresSatellite() {
- return false;
- }
-
- public boolean supportsAltitude() {
- return true;
- }
-
- public boolean supportsBearing() {
- return true;
- }
-
- public boolean supportsSpeed() {
- return true;
- }
-
- public synchronized void disable() {
- mEnabled = false;
- if (mThread != null) {
- mThread.setDone();
- try {
- mThread.join();
- } catch (InterruptedException e) {
- }
- mThread = null;
- }
- }
-
- public synchronized void enable() {
- mEnabled = true;
- mThread = new TestLocationProviderThread();
- mThread.start();
- }
-
- public boolean isEnabled() {
- return mEnabled;
- }
-
- public int getStatus(Bundle extras) {
- return STATUS;
- }
-
- public long getStatusUpdateTime() {
- return 0;
- }
-
- public void enableLocationTracking(boolean enable) {
- }
-
- public void setMinTime(long minTime) {
- }
-
- public void updateNetworkState(int state, NetworkInfo info) {
- }
-
- public void updateLocation(Location location) {
- }
-
- public boolean sendExtraCommand(String command, Bundle extras) {
- return false;
- }
-
- public void addListener(int uid) {
- }
-
- public void removeListener(int uid) {
- }
-
- private void updateLocation() {
- long time = SystemClock.uptimeMillis();
- long multiplier = (time/5000)%500000;
- mLocation.setLatitude(LAT*multiplier);
- mLocation.setLongitude(LON*multiplier);
- mLocation.setAltitude(ALTITUDE);
- mLocation.setSpeed(SPEED);
- mLocation.setBearing(BEARING*multiplier);
-
- Bundle extras = new Bundle();
- extras.putInt("extraTest", 24);
- mLocation.setExtras(extras);
- mLocation.setTime(time);
- try {
- mLocationManager.reportLocation(mLocation);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException calling updateLocation");
- }
- }
-
-}
diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java
index 57b22f8..ffd757c 100644
--- a/test-runner/android/test/mock/MockContext.java
+++ b/test-runner/android/test/mock/MockContext.java
@@ -158,11 +158,21 @@
}
@Override
+ public File getExternalFilesDir(String type) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public File getCacheDir() {
throw new UnsupportedOperationException();
}
@Override
+ public File getExternalCacheDir() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public File getDir(String name, int mode) {
throw new UnsupportedOperationException();
}
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java
index cbe0253..c8339ed 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -30,6 +30,7 @@
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
@@ -443,7 +444,7 @@
* @hide
*/
@Override
- public int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI) {
+ public int recommendAppInstallLocation(PackageParser.Package pkg) {
throw new UnsupportedOperationException();
}
}
diff --git a/tests/AndroidTests/res/raw/install_loc_auto b/tests/AndroidTests/res/raw/install_loc_auto
new file mode 100644
index 0000000..60dda18
--- /dev/null
+++ b/tests/AndroidTests/res/raw/install_loc_auto
Binary files differ
diff --git a/tests/AndroidTests/res/raw/install_loc_internal b/tests/AndroidTests/res/raw/install_loc_internal
new file mode 100644
index 0000000..1bc33ca
--- /dev/null
+++ b/tests/AndroidTests/res/raw/install_loc_internal
Binary files differ
diff --git a/tests/AndroidTests/res/raw/install_loc_sdcard b/tests/AndroidTests/res/raw/install_loc_sdcard
new file mode 100644
index 0000000..6604e35
--- /dev/null
+++ b/tests/AndroidTests/res/raw/install_loc_sdcard
Binary files differ
diff --git a/tests/AndroidTests/res/raw/install_loc_unspecified b/tests/AndroidTests/res/raw/install_loc_unspecified
new file mode 100644
index 0000000..88bbace
--- /dev/null
+++ b/tests/AndroidTests/res/raw/install_loc_unspecified
Binary files differ
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index 3a4d38c..07bd489 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -37,6 +37,7 @@
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageStats;
@@ -59,6 +60,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StatFs;
+import android.provider.Settings;
public class PackageManagerTests extends AndroidTestCase {
private static final boolean localLOGV = true;
@@ -761,6 +763,170 @@
outFile.delete();
}
}
+
+ public void invokeRecommendAppInstallLocation(String outFileName,
+ int fileResId, int expected) {
+ int origSetting = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.SET_INSTALL_LOCATION, 0);
+ try {
+ // Make sure the set install location setting is diabled.
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SET_INSTALL_LOCATION, 0);
+ File filesDir = mContext.getFilesDir();
+ File outFile = new File(filesDir, outFileName);
+ Uri packageURI = getInstallablePackage(fileResId, outFile);
+ PackageParser.Package pkg = parsePackage(packageURI);
+ assertNotNull(pkg);
+ int installLoc = getPm().recommendAppInstallLocation(pkg);
+ Log.i(TAG, "expected=" + expected +", installLoc="+installLoc);
+ // Atleast one of the specified expected flags should be set.
+ boolean onFlash = (installLoc &
+ PackageManager.INSTALL_ON_INTERNAL_FLASH) != 0;
+ boolean onSd = (installLoc &
+ PackageManager.INSTALL_ON_SDCARD) != 0;
+ boolean expOnFlash = (expected &
+ PackageManager.INSTALL_ON_INTERNAL_FLASH) != 0;
+ boolean expOnSd = (expected &
+ PackageManager.INSTALL_ON_SDCARD) != 0;
+ assertTrue(expOnFlash == onFlash || expOnSd == onSd);
+ } finally {
+ // Restore original setting
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SET_INSTALL_LOCATION, origSetting);
+ }
+ }
+
+ /*
+ * Tests if an apk can be installed on internal flash by
+ * explicitly specifying in its manifest.
+ */
+ public void testInstallLocationInternal() {
+ invokeRecommendAppInstallLocation("install.apk",
+ R.raw.install_loc_internal, PackageManager.INSTALL_ON_INTERNAL_FLASH);
+ }
+
+ /*
+ * Tests if an apk can be installed on internal flash by
+ * explicitly specifying in its manifest and filling up
+ * internal flash. Should fail to install.
+ * TODO
+ */
+ public void xxxtestInstallLocationInternalFail() {
+ }
+
+ /*
+ * Tests if an apk can be installed on sdcard by
+ * explicitly specifying in its manifest.
+ */
+ public void testInstallLocationSdcard() {
+ // TODO No guarantee this will be on sdcard.
+ invokeRecommendAppInstallLocation("install.apk",
+ R.raw.install_loc_sdcard, PackageManager.INSTALL_ON_SDCARD
+ | PackageManager.INSTALL_ON_INTERNAL_FLASH);
+ }
+
+ /*
+ * Tests if an apk can be installed on sdcard by
+ * explicitly specifying in its manifest and filling up
+ * the sdcard. Should result in install failure
+ * TODO
+ */
+ public void xxxtestInstallLocationSdcardFail() {
+ }
+
+ /*
+ * Tests if an apk can be installed by specifying
+ * auto for install location
+ */
+ public void xxxtestInstallLocationAutoInternal() {
+ // TODO clear and make room on internal flash
+ invokeRecommendAppInstallLocation("install.apk",
+ R.raw.install_loc_auto, PackageManager.INSTALL_ON_INTERNAL_FLASH);
+ }
+
+ /*
+ * Tests if an apk can be installed by specifying
+ * auto for install location
+ */
+ public void testInstallLocationAutoSdcard() {
+ // TODO clear and make room on sdcard.
+ // Fill up internal
+ invokeRecommendAppInstallLocation("install.apk",
+ R.raw.install_loc_auto, PackageManager.INSTALL_ON_SDCARD |
+ PackageManager.INSTALL_ON_INTERNAL_FLASH);
+ }
+
+ /*
+ * Tests if an apk can be installed by specifying
+ * auto for install location
+ * fill up both internal and sdcard
+ * TODO
+ */
+ public void xxxtestInstallLocationAutoFail() {
+ }
+ /*
+ * Tests where an apk gets installed based
+ * on a not specifying anything in manifest.
+ */
+ public void testInstallLocationUnspecifiedInt() {
+ invokeRecommendAppInstallLocation("install.apk",
+ R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_INTERNAL_FLASH);
+ }
+
+ public void xxxtestInstallLocationUnspecifiedStorage() {
+ // TODO Fill up internal storage
+ invokeRecommendAppInstallLocation("install.apk",
+ R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_SDCARD
+ | PackageManager.INSTALL_ON_INTERNAL_FLASH);
+ }
+
+ /*
+ * Tests where an apk gets installed by expcitly setting
+ * the user specified install location
+ */
+ public void testInstallLocationUserSpecifiedInternal() {
+ // Enable user setting
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SET_INSTALL_LOCATION, 1);
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.DEFAULT_INSTALL_LOCATION, 1);
+ invokeRecommendAppInstallLocation("install.apk",
+ R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_INTERNAL_FLASH);
+ }
+
+ /*
+ * Tests where an apk gets installed by expcitly setting
+ * the user specified install location
+ */
+ public void testInstallLocationUserSpecifiedSdcard() {
+ // Enable user setting
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SET_INSTALL_LOCATION, 1);
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.DEFAULT_INSTALL_LOCATION, 2);
+ int i = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.DEFAULT_INSTALL_LOCATION, 0);
+ invokeRecommendAppInstallLocation("install.apk",
+ R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_SDCARD);
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SET_INSTALL_LOCATION, 0);
+ }
+ /*
+ * Tests where an apk gets installed by expcitly setting
+ * the user specified install location
+ */
+ public void testInstallLocationUserSpecifiedAuto() {
+ // Enable user setting
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SET_INSTALL_LOCATION, 1);
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.DEFAULT_INSTALL_LOCATION, 0);
+ invokeRecommendAppInstallLocation("install.apk",
+ R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_INTERNAL_FLASH);
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SET_INSTALL_LOCATION, 0);
+ }
+
/*
* TODO's
* check version numbers for upgrades
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
index b670eee..57b5d4e1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -928,6 +928,12 @@
}
@Override
+ public File getExternalCacheDir() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
public ContentResolver getContentResolver() {
if (mContentResolver == null) {
mContentResolver = new BridgeContentResolver(this);
@@ -960,6 +966,12 @@
}
@Override
+ public File getExternalFilesDir(String type) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
public String getPackageCodePath() {
// TODO Auto-generated method stub
return null;
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index cb615d2..afaed24 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -835,7 +835,7 @@
WifiNative.closeSupplicantConnection();
}
if (died) {
- resetInterface(false);
+ resetConnections(true);
}
// When supplicant dies, kill the DHCP thread
if (mDhcpTarget != null) {
@@ -1074,6 +1074,13 @@
DetailedState saveState = getNetworkInfo().getDetailedState();
handleDisconnectedState(DetailedState.DISCONNECTED);
setDetailedStateInternal(saveState);
+ } else {
+ /**
+ * stop DHCP to ensure there is a new IP address
+ * even if the supplicant transitions without disconnect
+ * COMPLETED -> ASSOCIATED -> COMPLETED
+ */
+ resetConnections(false);
}
configureInterface();
mLastBssid = result.BSSID;
@@ -1279,12 +1286,11 @@
* {@code DISCONNECTED} or {@code FAILED}.
*/
private void handleDisconnectedState(DetailedState newState) {
- if (LOCAL_LOGD) Log.d(TAG, "Deconfiguring interface and stopping DHCP");
if (mDisconnectPending) {
cancelDisconnect();
}
mDisconnectExpected = false;
- resetInterface(true);
+ resetConnections(true);
setDetailedState(newState);
sendNetworkStateChangeBroadcast(mLastBssid);
mWifiInfo.setBSSID(null);
@@ -1294,10 +1300,11 @@
}
/**
- * Resets the Wi-Fi interface by clearing any state, resetting any sockets
+ * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
* using the interface, stopping DHCP, and disabling the interface.
*/
- public void resetInterface(boolean reenable) {
+ public void resetConnections(boolean disableInterface) {
+ if (LOCAL_LOGD) Log.d(TAG, "Reset connections and stopping DHCP");
mHaveIpAddress = false;
mObtainingIpAddress = false;
mWifiInfo.setIpAddress(0);
@@ -1317,9 +1324,14 @@
Log.e(TAG, "Could not stop DHCP");
}
- NetworkUtils.disableInterface(mInterfaceName);
- // we no longer net to start the interface (driver does this for us)
- // and it led to problems - removed.
+ /**
+ * Interface is re-enabled in the supplicant
+ * when moving out of ASSOCIATING state
+ */
+ if(disableInterface) {
+ if (LOCAL_LOGD) Log.d(TAG, "Disabling interface");
+ NetworkUtils.disableInterface(mInterfaceName);
+ }
}
/**
@@ -1538,7 +1550,7 @@
public synchronized boolean restart() {
if (mRunState == RUN_STATE_STOPPED) {
mRunState = RUN_STATE_STARTING;
- resetInterface(true);
+ resetConnections(true);
return WifiNative.startDriverCommand();
} else if (mRunState == RUN_STATE_STOPPING) {
mRunState = RUN_STATE_STARTING;
@@ -1969,7 +1981,7 @@
oDns2 != mDhcpInfo.dns2));
if (changed) {
- resetInterface(true);
+ resetConnections(true);
configureInterface();
if (mUseStaticIp) {
mTarget.sendEmptyMessage(EVENT_CONFIGURATION_CHANGED);