Merge "fix an NPE in SyncManager's dump where it can get a null AuthorityInfo; instead create one if one doesn't exist yet"
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 b155c45..7169d0d 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"
@@ -32785,6 +32796,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 +34328,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"
@@ -66226,6 +66285,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 +66302,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 +66331,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 +66364,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"
@@ -72532,7 +72594,7 @@
type="float"
transient="false"
volatile="false"
- value="0.0010f"
+ value="0.001f"
static="true"
final="true"
deprecated="not deprecated"
@@ -83028,6 +83090,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 +83117,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.media.MediaScannerConnection.ScanResultListener">
+</implements>
<method name="onMediaScannerConnected"
return="void"
abstract="true"
@@ -83063,6 +83146,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"
@@ -112670,6 +112776,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 +112811,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 +135954,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 +144463,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"
@@ -181293,6 +181537,17 @@
<parameter name="t" type="android.view.animation.Transformation">
</parameter>
</method>
+<method name="cancel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="computeDurationHint"
return="long"
abstract="false"
@@ -210047,7 +210302,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
</parameter>
</method>
</interface>
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/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/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..5a295b4 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.
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 1b34320..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/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 bac55cc..0a6195f 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;
@@ -2138,7 +2142,7 @@
havePerm = true;
}
if (writePermission != null) {
- writePermission = readPermission.intern();
+ writePermission = writePermission.intern();
havePerm = true;
}
@@ -2610,6 +2614,8 @@
*/
public ArrayList<FeatureInfo> reqFeatures = null;
+ public int installLocation;
+
public Package(String _name) {
packageName = _name;
applicationInfo.packageName = _name;
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 540f4445..5d1e7cf 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1880,8 +1880,7 @@
*/
Log.w(TAG, "Reached MAX size for compiled-sql statement cache for database " +
getPath() + "; i.e., NO space for this sql statement in cache: " +
- sql + ". Make sure your sql " +
- "statements are using prepared-sql-statement syntax with '?' for " +
+ sql + ". Please change your sql statements to use '?' for " +
"bindargs, instead of using actual values");
/* increment the number of times this warnings has been printed.
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/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/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..c2cdcc0 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
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 f5c465e..fb19dcf 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8281,6 +8281,9 @@
* Cancels any animations for this view.
*/
public void clearAnimation() {
+ if (mCurrentAnimation != null) {
+ mCurrentAnimation.detach();
+ }
mCurrentAnimation = null;
}
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 000e4ce..349b7e5 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -256,6 +256,37 @@
}
/**
+ * Cancel the animation. Cancelling an animation invokes the animation
+ * listener, if set, to notify the end of the animation.
+ *
+ * If you cancel an animation manually, you must call {@link #reset()}
+ * before starting the animation again.
+ *
+ * @see #reset()
+ * @see #start()
+ * @see #startNow()
+ */
+ public void cancel() {
+ if (mStarted && !mEnded) {
+ if (mListener != null) mListener.onAnimationEnd(this);
+ mEnded = true;
+ }
+ // Make sure we move the animation to the end
+ mStartTime = Long.MIN_VALUE;
+ mMore = mOneMoreTime = false;
+ }
+
+ /**
+ * @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.
@@ -745,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/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/drawable-mdpi/ic_launcher_android.png b/core/res/res/drawable-mdpi/ic_launcher_android.png
index 855484a..6a97d5b 100644
--- a/core/res/res/drawable-mdpi/ic_launcher_android.png
+++ b/core/res/res/drawable-mdpi/ic_launcher_android.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_def_app_icon.png b/core/res/res/drawable-mdpi/sym_def_app_icon.png
index 8be3b54..9777d11 100644
--- a/core/res/res/drawable-mdpi/sym_def_app_icon.png
+++ b/core/res/res/drawable-mdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 54781e3..2da23eb 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -600,6 +600,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 +638,7 @@
<attr name="versionName" />
<attr name="sharedUserId" />
<attr name="sharedUserLabel" />
+ <attr name="installLocation" />
</declare-styleable>
<!-- The <code>application</code> tag describes application-level components
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index bd4a3eb..596e0b2 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1224,9 +1224,10 @@
<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" />
</resources>
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/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 7d9e86c..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/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/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 d25f7f6..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;
@@ -725,7 +735,7 @@
if (latenessUs > 40000) {
// We're more than 40ms late.
- LOGI("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
+ LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
mVideoBuffer->release();
mVideoBuffer = NULL;
@@ -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 6274a6c..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';
@@ -1198,7 +1228,7 @@
CHECK(mLastTrack->meta->findInt32(kKeySampleRate, &prevSampleRate));
if (prevSampleRate != sampleRate) {
- LOGW("mpeg4 audio sample rate different from previous setting. "
+ LOGV("mpeg4 audio sample rate different from previous setting. "
"was: %d, now: %d", prevSampleRate, sampleRate);
}
@@ -1208,7 +1238,7 @@
CHECK(mLastTrack->meta->findInt32(kKeyChannelCount, &prevChannelCount));
if (prevChannelCount != numChannels) {
- LOGW("mpeg4 audio channel count different from previous setting. "
+ LOGV("mpeg4 audio channel count different from previous setting. "
"was: %d, now: %d", prevChannelCount, numChannels);
}
@@ -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 0355a82..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() {
@@ -1284,7 +1284,8 @@
CHECK_EQ(err, OK);
buffers->removeAt(i);
- } else if (mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
+ } else if (mState != ERROR
+ && mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
CHECK_EQ(mPortStatus[kPortIndexInput], ENABLED);
drainInputBuffer(&buffers->editItemAt(i));
}
@@ -1930,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);
@@ -2250,7 +2258,7 @@
}
status_t OMXCodec::stop() {
- CODEC_LOGV("stop");
+ CODEC_LOGV("stop mState=%d", mState);
Mutex::Autolock autoLock(mLock);
@@ -2309,6 +2317,8 @@
mSource->stop();
+ CODEC_LOGV("stopped");
+
return OK;
}
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..ac20297 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -864,6 +864,8 @@
loadBooleanSetting(stmt, Settings.System.NOTIFICATION_LIGHT_PULSE,
R.bool.def_notification_pulse);
+ loadBooleanSetting(stmt, Settings.System.SET_INSTALL_LOCATION, R.bool.set_install_location);
+ loadIntegerSetting(stmt, Settings.System.DEFAULT_INSTALL_LOCATION, 0);
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..10bf851 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;
}
}
@@ -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/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/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..57b5d4e 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;