Merge "During shutdown, don't loop forever on a state transition to OMX_StateInvalid."
diff --git a/api/current.xml b/api/current.xml
index 16ed39b..e673f0f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -29824,6 +29824,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.lang.Cloneable">
+</implements>
<implements name="java.lang.Comparable">
</implements>
<implements name="android.os.Parcelable">
@@ -29874,6 +29876,17 @@
<parameter name="in" type="android.os.Parcel">
</parameter>
</constructor>
+<method name="clone"
+ return="android.content.ComponentName"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="compareTo"
return="int"
abstract="false"
@@ -31727,6 +31740,17 @@
visibility="public"
>
</field>
+<field name="SYNC_EXTRAS_DO_NOT_RETRY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""do_not_retry""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SYNC_EXTRAS_EXPEDITED"
type="java.lang.String"
transient="false"
@@ -31749,6 +31773,28 @@
visibility="public"
>
</field>
+<field name="SYNC_EXTRAS_IGNORE_BACKOFF"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""ignore_backoff""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SYNC_EXTRAS_IGNORE_SETTINGS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""ignore_settings""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SYNC_EXTRAS_INITIALIZE"
type="java.lang.String"
transient="false"
@@ -41850,17 +41896,6 @@
visibility="public"
>
</field>
-<field name="resourceDirs"
- type="java.lang.String[]"
- transient="false"
- volatile="false"
- value="null"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="sharedLibraryFiles"
type="java.lang.String[]"
transient="false"
@@ -53070,6 +53105,72 @@
<parameter name="sleepAfterYieldDelay" type="long">
</parameter>
</method>
+<field name="CONFLICT_ABORT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONFLICT_FAIL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONFLICT_IGNORE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONFLICT_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONFLICT_REPLACE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONFLICT_ROLLBACK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="CREATE_IF_NECESSARY"
type="int"
transient="false"
@@ -53126,81 +53227,6 @@
>
</field>
</class>
-<class name="SQLiteDatabase.ConflictAlgorithm"
- extends="java.lang.Object"
- abstract="false"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-<field name="ABORT"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="FAIL"
- type="int"
- transient="false"
- volatile="false"
- value="3"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="IGNORE"
- type="int"
- transient="false"
- volatile="false"
- value="4"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="NONE"
- type="int"
- transient="false"
- volatile="false"
- value="0"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="REPLACE"
- type="int"
- transient="false"
- volatile="false"
- value="5"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ROLLBACK"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-</class>
<interface name="SQLiteDatabase.CursorFactory"
abstract="true"
static="true"
@@ -77577,32 +77603,6 @@
<parameter name="enabledOnly" type="boolean">
</parameter>
</method>
-<method name="installGeocodeProvider"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="provider" type="android.location.LocationManager.GeocodeProvider">
-</parameter>
-</method>
-<method name="installLocationProvider"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="provider" type="android.location.LocationProviderImpl">
-</parameter>
-</method>
<method name="isProviderEnabled"
return="boolean"
abstract="false"
@@ -77694,19 +77694,6 @@
<parameter name="intent" type="android.app.PendingIntent">
</parameter>
</method>
-<method name="reportLocation"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="location" type="android.location.Location">
-</parameter>
-</method>
<method name="requestLocationUpdates"
return="void"
abstract="false"
@@ -77899,62 +77886,6 @@
>
</field>
</class>
-<interface name="LocationManager.GeocodeProvider"
- abstract="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="getFromLocation"
- return="java.lang.String"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="latitude" type="double">
-</parameter>
-<parameter name="longitude" type="double">
-</parameter>
-<parameter name="maxResults" type="int">
-</parameter>
-<parameter name="params" type="android.location.GeocoderParams">
-</parameter>
-<parameter name="addrs" type="java.util.List<android.location.Address>">
-</parameter>
-</method>
-<method name="getFromLocationName"
- return="java.lang.String"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="locationName" type="java.lang.String">
-</parameter>
-<parameter name="lowerLeftLatitude" type="double">
-</parameter>
-<parameter name="lowerLeftLongitude" type="double">
-</parameter>
-<parameter name="upperRightLatitude" type="double">
-</parameter>
-<parameter name="upperRightLongitude" type="double">
-</parameter>
-<parameter name="maxResults" type="int">
-</parameter>
-<parameter name="params" type="android.location.GeocoderParams">
-</parameter>
-<parameter name="addrs" type="java.util.List<android.location.Address>">
-</parameter>
-</method>
-</interface>
<class name="LocationProvider"
extends="java.lang.Object"
abstract="true"
@@ -78120,166 +78051,6 @@
>
</field>
</class>
-<class name="LocationProviderImpl"
- extends="android.location.LocationProvider"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="LocationProviderImpl"
- type="android.location.LocationProviderImpl"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="name" type="java.lang.String">
-</parameter>
-</constructor>
-<method name="addListener"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uid" type="int">
-</parameter>
-</method>
-<method name="disable"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="enable"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="enableLocationTracking"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="enable" type="boolean">
-</parameter>
-</method>
-<method name="getStatus"
- return="int"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="extras" type="android.os.Bundle">
-</parameter>
-</method>
-<method name="getStatusUpdateTime"
- return="long"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="removeListener"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uid" type="int">
-</parameter>
-</method>
-<method name="sendExtraCommand"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="command" type="java.lang.String">
-</parameter>
-<parameter name="extras" type="android.os.Bundle">
-</parameter>
-</method>
-<method name="setMinTime"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="minTime" type="long">
-</parameter>
-</method>
-<method name="updateLocation"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="location" type="android.location.Location">
-</parameter>
-</method>
-<method name="updateNetworkState"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="state" type="int">
-</parameter>
-<parameter name="info" type="android.net.NetworkInfo">
-</parameter>
-</method>
-</class>
</package>
<package name="android.media"
>
diff --git a/common/java/com/android/common/Base64.java b/common/java/com/android/common/Base64.java
index 0c8e7c1..771875c 100644
--- a/common/java/com/android/common/Base64.java
+++ b/common/java/com/android/common/Base64.java
@@ -22,6 +22,11 @@
*/
public class Base64 {
/**
+ * Default values for encoder/decoder flags.
+ */
+ public static final int DEFAULT = 0;
+
+ /**
* Encoder flag bit to indicate you want the padding '='
* characters at the end (if any) to be omitted.
*/
@@ -106,7 +111,7 @@
* @param input the input String to decode, which is converted to
* bytes using the default charset
* @param flags controls certain features of the decoded output.
- * Passing 0 to decode standard Base64.
+ * Pass {@code DEFAULT} to decode standard Base64.
*
* @throws IllegalArgumentException if the input contains
* incorrect padding
@@ -124,7 +129,7 @@
*
* @param input the input array to decode
* @param flags controls certain features of the decoded output.
- * Passing 0 to decode standard Base64.
+ * Pass {@code DEFAULT} to decode standard Base64.
*
* @throws IllegalArgumentException if the input contains
* incorrect padding
@@ -144,7 +149,7 @@
* @param offset the position within the input array at which to start
* @param len the number of bytes of input to decode
* @param flags controls certain features of the decoded output.
- * Passing 0 to decode standard Base64.
+ * Pass {@code DEFAULT} to decode standard Base64.
*
* @throws IllegalArgumentException if the input contains
* incorrect padding
@@ -362,8 +367,8 @@
*
* @param input the data to encode
* @param flags controls certain features of the encoded output.
- * Passing 0 results in output that adheres to RFC
- * 2045.
+ * Passing {@code DEFAULT} results in output that
+ * adheres to RFC 2045.
*/
public static String encodeToString(byte[] input, int flags) {
return new String(encode(input, flags));
@@ -378,8 +383,8 @@
* start
* @param len the number of bytes of input to encode
* @param flags controls certain features of the encoded output.
- * Passing 0 results in output that adheres to RFC
- * 2045.
+ * Passing {@code DEFAULT} results in output that
+ * adheres to RFC 2045.
*/
public static String encodeToString(byte[] input, int offset, int len, int flags) {
return new String(encode(input, offset, len, flags));
@@ -391,8 +396,8 @@
*
* @param input the data to encode
* @param flags controls certain features of the encoded output.
- * Passing 0 results in output that adheres to RFC
- * 2045.
+ * Passing {@code DEFAULT} results in output that
+ * adheres to RFC 2045.
*/
public static byte[] encode(byte[] input, int flags) {
return encode(input, 0, input.length, flags);
@@ -407,8 +412,8 @@
* start
* @param len the number of bytes of input to encode
* @param flags controls certain features of the encoded output.
- * Passing 0 results in output that adheres to RFC
- * 2045.
+ * Passing {@code DEFAULT} results in output that
+ * adheres to RFC 2045.
*/
public static byte[] encode(byte[] input, int offset, int len, int flags) {
final boolean do_padding = (flags & NO_PADDING) == 0;
@@ -494,4 +499,6 @@
assert op == output.length;
return output;
}
+
+ private Base64() { } // don't instantiate
}
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 19e741a..652f405 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -837,14 +837,11 @@
private void ensureNotOnMainThread() {
final Looper looper = Looper.myLooper();
if (looper != null && looper == mContext.getMainLooper()) {
- // We really want to throw an exception here, but GTalkService exercises this
- // path quite a bit and needs some serious rewrite in order to work properly.
- //noinspection ThrowableInstanceNeverThrow
-// Log.e(TAG, "calling this from your main thread can lead to deadlock and/or ANRs",
-// new Exception());
- // TODO remove the log and throw this exception when the callers are fixed
-// throw new IllegalStateException(
-// "calling this from your main thread can lead to deadlock");
+ final IllegalStateException exception = new IllegalStateException(
+ "calling this from your main thread can lead to deadlock");
+ Log.e(TAG, "calling this from your main thread can lead to deadlock and/or ANRs",
+ exception);
+ throw exception;
}
}
@@ -909,7 +906,9 @@
private Bundle internalGetResult(Long timeout, TimeUnit unit)
throws OperationCanceledException, IOException, AuthenticatorException {
- ensureNotOnMainThread();
+ if (!isDone()) {
+ ensureNotOnMainThread();
+ }
try {
if (timeout == null) {
return get();
@@ -1075,7 +1074,9 @@
private T internalGetResult(Long timeout, TimeUnit unit)
throws OperationCanceledException, IOException, AuthenticatorException {
- ensureNotOnMainThread();
+ if (!isDone()) {
+ ensureNotOnMainThread();
+ }
try {
if (timeout == null) {
return get();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 5f89496..45d7546 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2166,7 +2166,7 @@
filter, null, null, null);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
- sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiverInternal(sPackageRemovedReceiver,
sdFilter, null, null, null);
}
@@ -2189,7 +2189,7 @@
String pkgList[] = null;
String action = intent.getAction();
boolean immediateGc = false;
- if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+ if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
immediateGc = true;
} else {
diff --git a/core/java/android/app/DeviceAdmin.java b/core/java/android/app/DeviceAdmin.java
index ecbad01..af9c379 100644
--- a/core/java/android/app/DeviceAdmin.java
+++ b/core/java/android/app/DeviceAdmin.java
@@ -40,7 +40,7 @@
* to the device administrator, as parsed by the {@link DeviceAdminInfo} class.
* A typical file would be:</p>
*
- * {@sample development/samples/ApiDemos/res/xml/sample_device_admin.xml meta_data}
+ * {@sample development/samples/ApiDemos/res/xml/device_admin_sample.xml meta_data}
*/
public class DeviceAdmin extends BroadcastReceiver {
private static String TAG = "DevicePolicy";
diff --git a/core/java/android/app/DevicePolicyManager.java b/core/java/android/app/DevicePolicyManager.java
index 08cdd05..847e879 100644
--- a/core/java/android/app/DevicePolicyManager.java
+++ b/core/java/android/app/DevicePolicyManager.java
@@ -328,14 +328,20 @@
}
/**
- * Set the maximum number of failed password attempts that are allowed
- * before the device wipes its data. This is convenience for implementing
- * the corresponding functionality with a combination of watching failed
- * password attempts and calling {@link #wipeData} upon reaching a certain
- * count, and as such requires that you request both
- * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} and
+ * Setting this to a value greater than zero enables a built-in policy
+ * that will perform a device wipe after too many incorrect
+ * device-unlock passwords have been entered. This built-in policy combines
+ * watching for failed passwords and wiping the device, and requires
+ * that you request both {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} and
* {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}}.
*
+ * <p>To implement any other policy (e.g. wiping data for a particular
+ * application only, erasing or revoking credentials, or reporting the
+ * failure to a server), you should implement
+ * {@link DeviceAdmin#onPasswordFailed(Context, android.content.Intent)}
+ * instead. Do not use this API, because if the maximum count is reached,
+ * the device will be wiped immediately, and your callback will not be invoked.
+ *
* @param admin Which {@link DeviceAdmin} this request is associated with.
* @param num The number of failed password attempts at which point the
* device will wipe its data.
diff --git a/core/java/android/content/ComponentName.java b/core/java/android/content/ComponentName.java
index 0455202..c4ba05d 100644
--- a/core/java/android/content/ComponentName.java
+++ b/core/java/android/content/ComponentName.java
@@ -30,7 +30,7 @@
* name inside of that package.
*
*/
-public final class ComponentName implements Parcelable, Comparable<ComponentName> {
+public final class ComponentName implements Parcelable, Cloneable, Comparable<ComponentName> {
private final String mPackage;
private final String mClass;
@@ -76,6 +76,10 @@
mClass = cls.getName();
}
+ public ComponentName clone() {
+ return new ComponentName(mPackage, mClass);
+ }
+
/**
* Return the package name of this component.
*/
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index b5587ed..b33be23 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -42,7 +42,6 @@
import java.io.OutputStream;
import java.util.List;
import java.util.ArrayList;
-import java.util.Collection;
/**
@@ -62,7 +61,31 @@
*/
@Deprecated
public static final String SYNC_EXTRAS_FORCE = "force";
+
+ /**
+ * If this extra is set to true then the sync settings (like getSyncAutomatically())
+ * are ignored by the sync scheduler.
+ */
+ public static final String SYNC_EXTRAS_IGNORE_SETTINGS = "ignore_settings";
+
+ /**
+ * If this extra is set to true then any backoffs for the initial attempt (e.g. due to retries)
+ * are ignored by the sync scheduler. If this request fails and gets rescheduled then the
+ * retries will still honor the backoff.
+ */
+ public static final String SYNC_EXTRAS_IGNORE_BACKOFF = "ignore_backoff";
+
+ /**
+ * If this extra is set to true then the request will not be retried if it fails.
+ */
+ public static final String SYNC_EXTRAS_DO_NOT_RETRY = "do_not_retry";
+
+ /**
+ * Setting this extra is the equivalent of setting both {@link #SYNC_EXTRAS_IGNORE_SETTINGS}
+ * and {@link #SYNC_EXTRAS_IGNORE_BACKOFF}
+ */
public static final String SYNC_EXTRAS_MANUAL = "force";
+
public static final String SYNC_EXTRAS_UPLOAD = "upload";
public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
@@ -976,15 +999,38 @@
* Although these sync are scheduled at the specified frequency, it may take longer for it to
* actually be started if other syncs are ahead of it in the sync operation queue. This means
* that the actual start time may drift.
+ * <p>
+ * Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY},
+ * {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS},
+ * {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE},
+ * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true.
+ * If any are supplied then an {@link IllegalArgumentException} will be thrown.
*
* @param account the account to specify in the sync
* @param authority the provider to specify in the sync request
* @param extras extra parameters to go along with the sync request
* @param pollFrequency how frequently the sync should be performed, in seconds.
+ * @throws IllegalArgumentException if an illegal extra was set or if any of the parameters
+ * are null.
*/
public static void addPeriodicSync(Account account, String authority, Bundle extras,
long pollFrequency) {
validateSyncExtrasBundle(extras);
+ if (account == null) {
+ throw new IllegalArgumentException("account must not be null");
+ }
+ if (authority == null) {
+ throw new IllegalArgumentException("authority must not be null");
+ }
+ if (extras.getBoolean(SYNC_EXTRAS_MANUAL, false)
+ || extras.getBoolean(SYNC_EXTRAS_DO_NOT_RETRY, false)
+ || extras.getBoolean(SYNC_EXTRAS_IGNORE_BACKOFF, false)
+ || extras.getBoolean(SYNC_EXTRAS_IGNORE_SETTINGS, false)
+ || extras.getBoolean(SYNC_EXTRAS_INITIALIZE, false)
+ || extras.getBoolean(SYNC_EXTRAS_FORCE, false)
+ || extras.getBoolean(SYNC_EXTRAS_EXPEDITED, false)) {
+ throw new IllegalArgumentException("illegal extras were set");
+ }
try {
getContentService().addPeriodicSync(account, authority, extras, pollFrequency);
} catch (RemoteException e) {
@@ -1003,6 +1049,12 @@
*/
public static void removePeriodicSync(Account account, String authority, Bundle extras) {
validateSyncExtrasBundle(extras);
+ if (account == null) {
+ throw new IllegalArgumentException("account must not be null");
+ }
+ if (authority == null) {
+ throw new IllegalArgumentException("authority must not be null");
+ }
try {
getContentService().removePeriodicSync(account, authority, extras);
} catch (RemoteException e) {
@@ -1018,6 +1070,12 @@
* @return a list of PeriodicSync objects. This list may be empty but will never be null.
*/
public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) {
+ if (account == null) {
+ throw new IllegalArgumentException("account must not be null");
+ }
+ if (authority == null) {
+ throw new IllegalArgumentException("authority must not be null");
+ }
try {
return getContentService().getPeriodicSyncs(account, authority);
} catch (RemoteException e) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e957e20..c32999f 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1381,8 +1381,8 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_MEDIA_RESOURCES_AVAILABLE =
- "android.intent.action.MEDIA_RESOURCES_AVAILABILE";
+ public static final String ACTION_EXTERNAL_APPLICATIONS_AVAILABLE =
+ "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE";
/**
* Broadcast Action: Resources for a set of packages are currently
@@ -1406,8 +1406,8 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_MEDIA_RESOURCES_UNAVAILABLE =
- "android.intent.action.MEDIA_RESOURCES_UNAVAILABILE";
+ public static final String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE =
+ "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABILE";
/**
* Broadcast Action: The current system wallpaper has changed. See
@@ -2198,8 +2198,8 @@
/**
* This field is part of
- * {@link android.content.Intent#ACTION_MEDIA_RESOURCES_AVAILABLE},
- * {@link android.content.Intent#ACTION_MEDIA_RESOURCES_UNAVAILABLE}
+ * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_AVAILABLE},
+ * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE}
* and contains a string array of all of the components that have changed.
* @hide
*/
@@ -2208,8 +2208,8 @@
/**
* This field is part of
- * {@link android.content.Intent#ACTION_MEDIA_RESOURCES_AVAILABLE},
- * {@link android.content.Intent#ACTION_MEDIA_RESOURCES_UNAVAILABLE}
+ * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_AVAILABLE},
+ * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE}
* and contains an integer array of uids of all of the components
* that have changed.
* @hide
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 619c7d5..ebb95e87 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -124,7 +124,7 @@
private Context mContext;
- private volatile Account[] mAccounts = null;
+ private volatile Account[] mAccounts = INITIAL_ACCOUNTS_ARRAY;
volatile private PowerManager.WakeLock mSyncWakeLock;
volatile private PowerManager.WakeLock mHandleAlarmWakeLock;
@@ -186,9 +186,11 @@
}
};
+ private static final Account[] INITIAL_ACCOUNTS_ARRAY = new Account[0];
+
public void onAccountsUpdated(Account[] accounts) {
// remember if this was the first time this was called after an update
- final boolean justBootedUp = mAccounts == null;
+ final boolean justBootedUp = mAccounts == INITIAL_ACCOUNTS_ARRAY;
mAccounts = accounts;
// if a sync is in progress yet it is no longer in the accounts list,
@@ -486,11 +488,6 @@
Bundle extras, long delay, boolean onlyThoseWithUnkownSyncableState) {
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
- if (mAccounts == null) {
- Log.e(TAG, "scheduleSync: the accounts aren't known yet, this should never happen");
- return;
- }
-
if (!isSyncEnabled()) {
if (isLoggable) {
Log.v(TAG, "not syncing because sync is disabled");
@@ -515,13 +512,6 @@
// if the accounts aren't configured yet then we can't support an account-less
// sync request
accounts = mAccounts;
- if (accounts == null) {
- // not ready yet
- if (isLoggable) {
- Log.v(TAG, "scheduleSync: no accounts yet, dropping");
- }
- return;
- }
if (accounts.length == 0) {
if (isLoggable) {
Log.v(TAG, "scheduleSync: no accounts configured, dropping");
@@ -532,6 +522,12 @@
final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
+ if (manualSync) {
+ extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
+ extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
+ }
+ final boolean ignoreSettings =
+ extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
int source;
if (uploadOnly) {
@@ -590,7 +586,7 @@
final boolean syncAutomatically = masterSyncAutomatically
&& mSyncStorageEngine.getSyncAutomatically(account, authority);
boolean syncAllowed =
- manualSync || (backgroundDataUsageAllowed && syncAutomatically);
+ ignoreSettings || (backgroundDataUsageAllowed && syncAutomatically);
if (!syncAllowed) {
if (isLoggable) {
Log.d(TAG, "scheduleSync: sync of " + account + ", " + authority
@@ -797,21 +793,29 @@
Log.d(TAG, "encountered error(s) during the sync: " + syncResult + ", " + operation);
}
+ operation = new SyncOperation(operation);
+
+ // The SYNC_EXTRAS_IGNORE_BACKOFF only applies to the first attempt to sync a given
+ // request. Retries of the request will always honor the backoff, so clear the
+ // flag in case we retry this request.
+ if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)) {
+ operation.extras.remove(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
+ }
+
// If this sync aborted because the internal sync loop retried too many times then
// don't reschedule. Otherwise we risk getting into a retry loop.
// If the operation succeeded to some extent then retry immediately.
// If this was a two-way sync then retry soft errors with an exponential backoff.
// If this was an upward sync then schedule a two-way sync immediately.
// Otherwise do not reschedule.
- if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)) {
- Log.d(TAG, "not retrying sync operation because it is a manual sync: "
+ if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)) {
+ Log.d(TAG, "not retrying sync operation because SYNC_EXTRAS_DO_NOT_RETRY was specified "
+ operation);
} else if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false)) {
- final SyncOperation newSyncOperation = new SyncOperation(operation);
- newSyncOperation.extras.remove(ContentResolver.SYNC_EXTRAS_UPLOAD);
+ operation.extras.remove(ContentResolver.SYNC_EXTRAS_UPLOAD);
Log.d(TAG, "retrying sync operation as a two-way sync because an upload-only sync "
+ "encountered an error: " + operation);
- scheduleSyncOperation(newSyncOperation);
+ scheduleSyncOperation(operation);
} else if (syncResult.tooManyRetries) {
Log.d(TAG, "not retrying sync operation because it retried too many times: "
+ operation);
@@ -820,13 +824,13 @@
Log.d(TAG, "retrying sync operation because even though it had an error "
+ "it achieved some success");
}
- scheduleSyncOperation(new SyncOperation(operation));
+ scheduleSyncOperation(operation);
} else if (syncResult.hasSoftError()) {
if (isLoggable) {
Log.d(TAG, "retrying sync operation because it encountered a soft error: "
+ operation);
}
- scheduleSyncOperation(new SyncOperation(operation));
+ scheduleSyncOperation(operation);
} else {
Log.d(TAG, "not retrying sync operation because the error is a hard error: "
+ operation);
@@ -942,10 +946,10 @@
final Account[] accounts = mAccounts;
pw.print("accounts: ");
- if (accounts != null) {
+ if (accounts != INITIAL_ACCOUNTS_ARRAY) {
pw.println(accounts.length);
} else {
- pw.println("none");
+ pw.println("not known yet");
}
final long now = SystemClock.elapsedRealtime();
pw.print("now: "); pw.print(now);
@@ -1448,7 +1452,7 @@
}
}
- private boolean isSyncAllowed(Account account, String authority, boolean manualSync,
+ private boolean isSyncAllowed(Account account, String authority, boolean ignoreSettings,
boolean backgroundDataUsageAllowed) {
Account[] accounts = mAccounts;
@@ -1458,7 +1462,7 @@
}
// skip the sync if the account of this operation no longer exists
- if (accounts == null || !ArrayUtils.contains(accounts, account)) {
+ if (!ArrayUtils.contains(accounts, account)) {
return false;
}
@@ -1466,7 +1470,7 @@
final boolean syncAutomatically =
mSyncStorageEngine.getSyncAutomatically(account, authority)
&& mSyncStorageEngine.getMasterSyncAutomatically();
- if (!(manualSync || (backgroundDataUsageAllowed && syncAutomatically))) {
+ if (!(ignoreSettings || (backgroundDataUsageAllowed && syncAutomatically))) {
return false;
}
@@ -1525,7 +1529,7 @@
// If the accounts aren't known yet then we aren't ready to run. We will be kicked
// when the account lookup request does complete.
Account[] accounts = mAccounts;
- if (accounts == null) {
+ if (accounts == INITIAL_ACCOUNTS_ARRAY) {
if (isLoggable) {
Log.v(TAG, "runStateIdle: accounts not known, skipping");
}
@@ -1553,8 +1557,9 @@
// from the queue now
mSyncQueue.remove(op);
- if (!isSyncAllowed(op.account, op.authority,
- op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false),
+ final boolean ignoreSettings = op.extras
+ .getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
+ if (!isSyncAllowed(op.account, op.authority, ignoreSettings,
backgroundDataUsageAllowed)) {
continue;
}
@@ -1609,7 +1614,7 @@
Bundle bestExtras = null;
ArrayList<SyncStorageEngine.AuthorityInfo> infos = mSyncStorageEngine.getAuthorities();
for (SyncStorageEngine.AuthorityInfo info : infos) {
- if (!isSyncAllowed(info.account, info.authority, false /* manualSync */,
+ if (!isSyncAllowed(info.account, info.authority, false /* ignoreSettings */,
backgroundDataUsageAllowed)) {
continue;
}
@@ -1881,7 +1886,6 @@
// in each of these cases the sync loop will be kicked, which will cause this
// method to be called again
if (!mDataConnectionIsConnected) return;
- if (mAccounts == null) return;
if (mStorageIsLow) return;
final long now = SystemClock.elapsedRealtime();
@@ -1895,7 +1899,7 @@
if (activeSyncContext == null) {
synchronized (mSyncQueue) {
Pair<SyncOperation, Long> candidate = bestSyncOperationCandidate();
- alarmTime = candidate != null ? candidate.second : 0;
+ alarmTime = candidate != null ? candidate.second : null;
}
} else {
final long notificationTime =
@@ -2040,18 +2044,4 @@
resultMessage, downstreamActivity, upstreamActivity);
}
}
-
- public static long runTimeWithBackoffs(SyncStorageEngine syncStorageEngine,
- Account account, String authority, boolean isManualSync, long runTime) {
- // if this is a manual sync, the run time is unchanged
- // otherwise, the run time is the max of the backoffs and the run time.
- if (isManualSync) {
- return runTime;
- }
-
- Pair<Long, Long> backoff = syncStorageEngine.getBackoff(account, authority);
- long delayUntilTime = syncStorageEngine.getDelayUntilTime(account, authority);
-
- return Math.max(Math.max(runTime, delayUntilTime), backoff != null ? backoff.first : 0);
- }
}
diff --git a/core/java/android/content/SyncOperation.java b/core/java/android/content/SyncOperation.java
index 2d6e833..4599165 100644
--- a/core/java/android/content/SyncOperation.java
+++ b/core/java/android/content/SyncOperation.java
@@ -26,6 +26,9 @@
this.extras = new Bundle(extras);
removeFalseExtra(ContentResolver.SYNC_EXTRAS_UPLOAD);
removeFalseExtra(ContentResolver.SYNC_EXTRAS_MANUAL);
+ removeFalseExtra(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS);
+ removeFalseExtra(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
+ removeFalseExtra(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY);
removeFalseExtra(ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS);
removeFalseExtra(ContentResolver.SYNC_EXTRAS_EXPEDITED);
removeFalseExtra(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS);
diff --git a/core/java/android/content/SyncQueue.java b/core/java/android/content/SyncQueue.java
index 2eead3a..bb21488 100644
--- a/core/java/android/content/SyncQueue.java
+++ b/core/java/android/content/SyncQueue.java
@@ -113,10 +113,14 @@
SyncOperation best = null;
long bestRunTime = 0;
for (SyncOperation op : mOperationsMap.values()) {
- long opRunTime = SyncManager.runTimeWithBackoffs(mSyncStorageEngine, op.account,
- op.authority,
- op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false),
- op.earliestRunTime);
+ long opRunTime = op.earliestRunTime;
+ if (!op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)) {
+ Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(op.account, op.authority);
+ long delayUntil = mSyncStorageEngine.getDelayUntilTime(op.account, op.authority);
+ opRunTime = Math.max(
+ Math.max(opRunTime, delayUntil),
+ backoff != null ? backoff.first : 0);
+ }
// if the expedited state of both ops are the same then compare their runtime.
// Otherwise the candidate is only better than the current best if the candidate
// is expedited.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 808c839b..6591313 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -270,6 +270,8 @@
* Full paths to the locations of extra resource packages this application
* uses. This field is only used if there are extra resource packages,
* otherwise it is null.
+ *
+ * {@hide}
*/
public String[] resourceDirs;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 745628a..e3b1694 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -437,6 +437,15 @@
public static final int INSTALL_FAILED_CONTAINER_ERROR = -18;
/**
+ * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+ * the new package couldn't be installed in the specified install
+ * location.
+ * @hide
+ */
+ public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19;
+
+ /**
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser was given a path that is not a file, or does not end with the expected
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 7362394..a885820 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -117,8 +117,8 @@
mContext.registerReceiver(receiver, intentFilter);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
- sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE);
- sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(receiver, sdFilter);
}
diff --git a/core/java/android/database/sqlite/SQLiteClosable.java b/core/java/android/database/sqlite/SQLiteClosable.java
index f64261c..7776520 100644
--- a/core/java/android/database/sqlite/SQLiteClosable.java
+++ b/core/java/android/database/sqlite/SQLiteClosable.java
@@ -29,7 +29,7 @@
synchronized(mLock) {
if (mReferenceCount <= 0) {
throw new IllegalStateException(
- "attempt to acquire a reference on a close SQLiteClosable");
+ "attempt to acquire a reference on an already-closed SQLiteClosable obj.");
}
mReferenceCount++;
}
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 22e2a83..540f4445 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -66,64 +66,60 @@
* Algorithms used in ON CONFLICT clause
* http://www.sqlite.org/lang_conflict.html
*/
- public static final class ConflictAlgorithm {
- /**
- * When a constraint violation occurs, an immediate ROLLBACK occurs,
- * thus ending the current transaction, and the command aborts with a
- * return code of SQLITE_CONSTRAINT. If no transaction is active
- * (other than the implied transaction that is created on every command)
- * then this algorithm works the same as ABORT.
- */
- public static final int ROLLBACK = 1;
+ /**
+ * When a constraint violation occurs, an immediate ROLLBACK occurs,
+ * thus ending the current transaction, and the command aborts with a
+ * return code of SQLITE_CONSTRAINT. If no transaction is active
+ * (other than the implied transaction that is created on every command)
+ * then this algorithm works the same as ABORT.
+ */
+ public static final int CONFLICT_ROLLBACK = 1;
- /**
- * When a constraint violation occurs,no ROLLBACK is executed
- * so changes from prior commands within the same transaction
- * are preserved. This is the default behavior.
- */
- public static final int ABORT = 2;
+ /**
+ * When a constraint violation occurs,no ROLLBACK is executed
+ * so changes from prior commands within the same transaction
+ * are preserved. This is the default behavior.
+ */
+ public static final int CONFLICT_ABORT = 2;
- /**
- * When a constraint violation occurs, the command aborts with a return
- * code SQLITE_CONSTRAINT. But any changes to the database that
- * the command made prior to encountering the constraint violation
- * are preserved and are not backed out.
- */
- public static final int FAIL = 3;
+ /**
+ * When a constraint violation occurs, the command aborts with a return
+ * code SQLITE_CONSTRAINT. But any changes to the database that
+ * the command made prior to encountering the constraint violation
+ * are preserved and are not backed out.
+ */
+ public static final int CONFLICT_FAIL = 3;
- /**
- * When a constraint violation occurs, the one row that contains
- * the constraint violation is not inserted or changed.
- * But the command continues executing normally. Other rows before and
- * after the row that contained the constraint violation continue to be
- * inserted or updated normally. No error is returned.
- */
- public static final int IGNORE = 4;
+ /**
+ * When a constraint violation occurs, the one row that contains
+ * the constraint violation is not inserted or changed.
+ * But the command continues executing normally. Other rows before and
+ * after the row that contained the constraint violation continue to be
+ * inserted or updated normally. No error is returned.
+ */
+ public static final int CONFLICT_IGNORE = 4;
- /**
- * When a UNIQUE constraint violation occurs, the pre-existing rows that
- * are causing the constraint violation are removed prior to inserting
- * or updating the current row. Thus the insert or update always occurs.
- * The command continues executing normally. No error is returned.
- * If a NOT NULL constraint violation occurs, the NULL value is replaced
- * by the default value for that column. If the column has no default
- * value, then the ABORT algorithm is used. If a CHECK constraint
- * violation occurs then the IGNORE algorithm is used. When this conflict
- * resolution strategy deletes rows in order to satisfy a constraint,
- * it does not invoke delete triggers on those rows.
- * This behavior might change in a future release.
- */
- public static final int REPLACE = 5;
+ /**
+ * When a UNIQUE constraint violation occurs, the pre-existing rows that
+ * are causing the constraint violation are removed prior to inserting
+ * or updating the current row. Thus the insert or update always occurs.
+ * The command continues executing normally. No error is returned.
+ * If a NOT NULL constraint violation occurs, the NULL value is replaced
+ * by the default value for that column. If the column has no default
+ * value, then the ABORT algorithm is used. If a CHECK constraint
+ * violation occurs then the IGNORE algorithm is used. When this conflict
+ * resolution strategy deletes rows in order to satisfy a constraint,
+ * it does not invoke delete triggers on those rows.
+ * This behavior might change in a future release.
+ */
+ public static final int CONFLICT_REPLACE = 5;
- /**
- * use the following when no conflict action is specified.
- */
- public static final int NONE = 0;
- private static final String[] VALUES = new String[]
- {"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "};
-
- private ConflictAlgorithm() {} // disable instantiation of this class
- }
+ /**
+ * use the following when no conflict action is specified.
+ */
+ public static final int CONFLICT_NONE = 0;
+ private static final String[] CONFLICT_VALUES = new String[]
+ {"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "};
/**
* Maximum Length Of A LIKE Or GLOB Pattern
@@ -290,10 +286,6 @@
@Override
protected void onAllReferencesReleased() {
if (isOpen()) {
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- Log.d(TAG, "captured_sql|" + mPath + "|DETACH DATABASE " +
- getDatabaseName(mPath) + ";");
- }
if (SQLiteDebug.DEBUG_SQL_CACHE) {
mTimeClosed = getTime();
}
@@ -782,7 +774,14 @@
SQLiteDatabase db = null;
try {
// Open the database.
- return new SQLiteDatabase(path, factory, flags);
+ SQLiteDatabase sqliteDatabase = new SQLiteDatabase(path, factory, flags);
+ if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
+ sqliteDatabase.enableSqlTracing(path);
+ }
+ if (SQLiteDebug.DEBUG_SQL_TIME) {
+ sqliteDatabase.enableSqlProfiling(path);
+ }
+ return sqliteDatabase;
} catch (SQLiteDatabaseCorruptException e) {
// Try to recover from this, if we can.
// TODO: should we do this for other open failures?
@@ -1338,7 +1337,7 @@
*/
public long insert(String table, String nullColumnHack, ContentValues values) {
try {
- return insertWithOnConflict(table, nullColumnHack, values, ConflictAlgorithm.NONE);
+ return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
} catch (SQLException e) {
Log.e(TAG, "Error inserting " + values, e);
return -1;
@@ -1360,7 +1359,7 @@
*/
public long insertOrThrow(String table, String nullColumnHack, ContentValues values)
throws SQLException {
- return insertWithOnConflict(table, nullColumnHack, values, ConflictAlgorithm.NONE);
+ return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
}
/**
@@ -1377,7 +1376,7 @@
public long replace(String table, String nullColumnHack, ContentValues initialValues) {
try {
return insertWithOnConflict(table, nullColumnHack, initialValues,
- ConflictAlgorithm.REPLACE);
+ CONFLICT_REPLACE);
} catch (SQLException e) {
Log.e(TAG, "Error inserting " + initialValues, e);
return -1;
@@ -1399,7 +1398,7 @@
public long replaceOrThrow(String table, String nullColumnHack,
ContentValues initialValues) throws SQLException {
return insertWithOnConflict(table, nullColumnHack, initialValues,
- ConflictAlgorithm.REPLACE);
+ CONFLICT_REPLACE);
}
/**
@@ -1412,10 +1411,10 @@
* @param initialValues this map contains the initial column values for the
* row. The keys should be the column names and the values the
* column values
- * @param conflictAlgorithm {@link ConflictAlgorithm} for insert conflict resolver
+ * @param conflictAlgorithm for insert conflict resolver
* @return the row ID of the newly inserted row
* OR the primary key of the existing row if the input param 'conflictAlgorithm' =
- * {@link ConflictAlgorithm#IGNORE}
+ * {@link #CONFLICT_IGNORE}
* OR -1 if any error
*/
public long insertWithOnConflict(String table, String nullColumnHack,
@@ -1427,7 +1426,7 @@
// Measurements show most sql lengths <= 152
StringBuilder sql = new StringBuilder(152);
sql.append("INSERT");
- sql.append(ConflictAlgorithm.VALUES[conflictAlgorithm]);
+ sql.append(CONFLICT_VALUES[conflictAlgorithm]);
sql.append(" INTO ");
sql.append(table);
// Measurements show most values lengths < 40
@@ -1551,7 +1550,7 @@
* @return the number of rows affected
*/
public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
- return updateWithOnConflict(table, values, whereClause, whereArgs, ConflictAlgorithm.NONE);
+ return updateWithOnConflict(table, values, whereClause, whereArgs, CONFLICT_NONE);
}
/**
@@ -1562,7 +1561,7 @@
* valid value that will be translated to NULL.
* @param whereClause the optional WHERE clause to apply when updating.
* Passing null will update all rows.
- * @param conflictAlgorithm {@link ConflictAlgorithm} for update conflict resolver
+ * @param conflictAlgorithm for update conflict resolver
* @return the number of rows affected
*/
public int updateWithOnConflict(String table, ContentValues values,
@@ -1577,7 +1576,7 @@
StringBuilder sql = new StringBuilder(120);
sql.append("UPDATE ");
- sql.append(ConflictAlgorithm.VALUES[conflictAlgorithm]);
+ sql.append(CONFLICT_VALUES[conflictAlgorithm]);
sql.append(table);
sql.append(" SET ");
@@ -1652,9 +1651,6 @@
*/
public void execSQL(String sql) throws SQLException {
long timeStart = Debug.threadCpuTimeNanos();
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- Log.v(TAG, SQLiteDebug.captureSql(this.getPath(), sql, null));
- }
lock();
try {
native_execSQL(sql);
@@ -1680,9 +1676,6 @@
if (bindArgs == null) {
throw new IllegalArgumentException("Empty bindArgs");
}
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- Log.v(TAG, SQLiteDebug.captureSql(this.getPath(), sql, bindArgs));
- }
long timeStart = Debug.threadCpuTimeNanos();
lock();
SQLiteStatement statement = null;
@@ -1741,10 +1734,6 @@
mLeakedException = new IllegalStateException(path +
" SQLiteDatabase created and never closed");
mFactory = factory;
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- Log.d(TAG, "captured_sql|" + mPath + "|ATTACH DATABASE '" + mPath +
- "' as " + getDatabaseName(mPath) + ";");
- }
dbopen(mPath, mFlags);
if (SQLiteDebug.DEBUG_SQL_CACHE) {
mTimeOpened = getTime();
@@ -1754,10 +1743,6 @@
setLocale(Locale.getDefault());
} catch (RuntimeException e) {
Log.e(TAG, "Failed to setLocale() when constructing, closing the database", e);
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- Log.d(TAG, "captured_sql|" + mPath + "|DETACH DATABASE " +
- getDatabaseName(mPath) + ";");
- }
dbclose();
if (SQLiteDebug.DEBUG_SQL_CACHE) {
mTimeClosed = getTime();
@@ -1770,20 +1755,6 @@
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ").format(System.currentTimeMillis());
}
- private String getDatabaseName(String path) {
- if (path == null || path.trim().length() == 0) {
- return "db not specified?";
- }
-
- if (path.equalsIgnoreCase(":memory:")) {
- return "memorydb";
- }
- String[] tokens = path.split("/");
- String[] lastNodeTokens = tokens[tokens.length - 1].split("\\.", 2);
- return (lastNodeTokens.length == 1) ? lastNodeTokens[0]
- : lastNodeTokens[0] + lastNodeTokens[1];
- }
-
/**
* return whether the DB is opened as read only.
* @return true if DB is opened as read only
@@ -2062,6 +2033,23 @@
private native void dbopen(String path, int flags);
/**
+ * Native call to setup tracing of all sql statements
+ *
+ * @param path the full path to the database
+ */
+ private native void enableSqlTracing(String path);
+
+ /**
+ * Native call to setup profiling of all sql statements.
+ * currently, sqlite's profiling = printing of execution-time
+ * (wall-clock time) of each of the sql statements, as they
+ * are executed.
+ *
+ * @param path the full path to the database
+ */
+ private native void enableSqlProfiling(String path);
+
+ /**
* Native call to execute a raw SQL statement. {@link #lock} must be held
* when calling this method.
*
diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java
index b12034a..4ea680e 100644
--- a/core/java/android/database/sqlite/SQLiteDebug.java
+++ b/core/java/android/database/sqlite/SQLiteDebug.java
@@ -31,19 +31,19 @@
Log.isLoggable("SQLiteStatements", Log.VERBOSE);
/**
+ * Controls the printing of wall-clock time taken to execute SQL statements
+ * as they are executed.
+ */
+ public static final boolean DEBUG_SQL_TIME =
+ Log.isLoggable("SQLiteTime", Log.VERBOSE);
+
+ /**
* Controls the printing of compiled-sql-statement cache stats.
*/
public static final boolean DEBUG_SQL_CACHE =
Log.isLoggable("SQLiteCompiledSql", Log.VERBOSE);
/**
- * Controls the capturing and printing of complete sql statement including the bind args and
- * the database name.
- */
- public static final boolean DEBUG_CAPTURE_SQL =
- Log.isLoggable("SQLiteCaptureSql", Log.VERBOSE);
-
- /**
* Controls the stack trace reporting of active cursors being
* finalized.
*/
@@ -121,62 +121,4 @@
static synchronized void notifyActiveCursorFinalized() {
sNumActiveCursorsFinalized++;
}
-
- /**
- * returns a message containing the given database name (path) and the string built by
- * replacing "?" characters in the given sql string with the corresponding
- * positional values from the given param bindArgs.
- *
- * @param path the database name
- * @param sql sql string with possibly "?" for bindargs
- * @param bindArgs args for "?"s in the above string
- * @return the String to be logged
- */
- /* package */ static String captureSql(String path, String sql, Object[] bindArgs) {
- // how many bindargs in sql
- sql = sql.trim();
- String args[] = sql.split("\\?");
- // how many "?"s in the given sql string?
- int varArgsInSql = (sql.endsWith("?")) ? args.length : args.length - 1;
-
- // how many bind args do we have in the given input param bindArgs
- int bindArgsLen = (bindArgs == null) ? 0 : bindArgs.length;
- if (varArgsInSql < bindArgsLen) {
- return "too many bindArgs provided. " +
- "# of bindArgs = " + bindArgsLen + ", # of varargs = " + varArgsInSql +
- "; sql = " + sql;
- }
-
- // if there are no bindArgs, we are done. log the sql as is.
- if (bindArgsLen == 0 && varArgsInSql == 0) {
- return logSql(path, sql);
- }
-
- StringBuilder buf = new StringBuilder();
-
- // take the supplied bindArgs and plug them into sql
- for (int i = 0; i < bindArgsLen; i++) {
- buf.append(args[i]);
- buf.append(bindArgs[i]);
- }
-
- // does given sql have more varArgs than the supplied bindArgs
- // if so, assign nulls to the extra varArgs in sql
- for (int i = bindArgsLen; i < varArgsInSql; i ++) {
- buf.append(args[i]);
- buf.append("null");
- }
-
- // if there are any characters left in the given sql string AFTER the last "?"
- // log them also. for example, if the given sql = "select * from test where a=? and b=1
- // then the following code appends " and b=1" string to buf.
- if (varArgsInSql < args.length) {
- buf.append(args[varArgsInSql]);
- }
- return logSql(path, buf.toString());
- }
-
- private static String logSql(String path, String sql) {
- return "captured_sql|" + path + "|" + sql + ";";
- }
}
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 1159c1d..2d0aa39 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -16,19 +16,10 @@
package android.database.sqlite;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import android.util.Log;
-
/**
* A base class for compiled SQLite programs.
*/
public abstract class SQLiteProgram extends SQLiteClosable {
- private static final String TAG = "SQLiteProgram";
/** The database this program is compiled against. */
protected SQLiteDatabase mDatabase;
@@ -53,16 +44,7 @@
*/
protected int nStatement = 0;
- /**
- * stores all bindargs for debugging purposes
- */
- private Map<Integer, String> mBindArgs = null;
-
/* package */ SQLiteProgram(SQLiteDatabase db, String sql) {
- if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
- Log.d(TAG, "processing sql: " + sql);
- }
-
mDatabase = db;
mSql = sql;
db.acquireReference();
@@ -120,7 +102,7 @@
}
/**
- * @deprecated use this.compiledStatement.compile instead
+ * @deprecated This method is deprecated and must not be used.
*
* @param sql the SQL string to compile
* @param forceCompilation forces the SQL to be recompiled in the event that there is an
@@ -138,9 +120,6 @@
* @param index The 1-based index to the parameter to bind null to
*/
public void bindNull(int index) {
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- addToBindArgs(index, "null");
- }
acquireReference();
try {
native_bind_null(index);
@@ -157,9 +136,6 @@
* @param value The value to bind
*/
public void bindLong(int index, long value) {
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- addToBindArgs(index, value + "");
- }
acquireReference();
try {
native_bind_long(index, value);
@@ -176,9 +152,6 @@
* @param value The value to bind
*/
public void bindDouble(int index, double value) {
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- addToBindArgs(index, value + "");
- }
acquireReference();
try {
native_bind_double(index, value);
@@ -195,9 +168,6 @@
* @param value The value to bind
*/
public void bindString(int index, String value) {
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- addToBindArgs(index, "'" + value + "'");
- }
if (value == null) {
throw new IllegalArgumentException("the bind value at index " + index + " is null");
}
@@ -217,9 +187,6 @@
* @param value The value to bind
*/
public void bindBlob(int index, byte[] value) {
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- addToBindArgs(index, "blob");
- }
if (value == null) {
throw new IllegalArgumentException("the bind value at index " + index + " is null");
}
@@ -235,9 +202,6 @@
* Clears all existing bindings. Unset bindings are treated as NULL.
*/
public void clearBindings() {
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- mBindArgs = null;
- }
acquireReference();
try {
native_clear_bindings();
@@ -259,39 +223,7 @@
}
/**
- * this method is called under the debug flag {@link SQLiteDebug.DEBUG_CAPTURE_SQL} only.
- * it collects the bindargs as they are called by the callers the bind... methods in this
- * class.
- */
- private void addToBindArgs(int index, String obj) {
- if (mBindArgs == null) {
- mBindArgs = new HashMap<Integer, String>();
- }
- mBindArgs.put(index, obj);
- }
-
- /**
- * constructs all the bindargs in sequence and returns a String Array of the values.
- * it uses the HashMap built up by the above method.
- *
- * @return the string array of bindArgs with the args arranged in sequence
- */
- /* package */ String[] getBindArgs() {
- if (mBindArgs == null) {
- return null;
- }
- Set<Integer> indexSet = mBindArgs.keySet();
- ArrayList<Integer> indexList = new ArrayList<Integer>(indexSet);
- Collections.sort(indexList);
- int len = indexList.size();
- String[] bindObjs = new String[len];
- for (int i = 0; i < len; i++) {
- bindObjs[i] = mBindArgs.get(indexList.get(i));
- }
- return bindObjs;
- }
-
- /**
+ * @deprecated This method is deprecated and must not be used.
* Compiles SQL into a SQLite program.
*
* <P>The database lock must be held when calling this method.
@@ -299,6 +231,10 @@
*/
@Deprecated
protected final native void native_compile(String sql);
+
+ /**
+ * @deprecated This method is deprecated and must not be used.
+ */
@Deprecated
protected final native void native_finalize();
diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java
index c34661d..5bcad4b 100644
--- a/core/java/android/database/sqlite/SQLiteQuery.java
+++ b/core/java/android/database/sqlite/SQLiteQuery.java
@@ -18,7 +18,6 @@
import android.database.CursorWindow;
import android.os.Debug;
-import android.os.SystemClock;
import android.util.Log;
/**
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index 0cee3c5..f1f5a2a 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -17,7 +17,6 @@
package android.database.sqlite;
import android.os.Debug;
-import android.util.Log;
/**
* A pre-compiled statement against a {@link SQLiteDatabase} that can be reused.
@@ -27,8 +26,6 @@
*/
public class SQLiteStatement extends SQLiteProgram
{
- private static final String TAG = "SQLiteStatement";
-
/**
* Don't use SQLiteStatement constructor directly, please use
* {@link SQLiteDatabase#compileStatement(String)}
@@ -52,12 +49,6 @@
acquireReference();
try {
- if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
- Log.v(TAG, "execute() for [" + mSql + "]");
- }
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- Log.v(TAG, SQLiteDebug.captureSql(mDatabase.getPath(), mSql, getBindArgs()));
- }
native_execute();
mDatabase.logTimeStat(mSql, timeStart);
} finally {
@@ -82,12 +73,6 @@
acquireReference();
try {
- if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
- Log.v(TAG, "executeInsert() for [" + mSql + "]");
- }
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- Log.v(TAG, SQLiteDebug.captureSql(mDatabase.getPath(), mSql, getBindArgs()));
- }
native_execute();
mDatabase.logTimeStat(mSql, timeStart);
return mDatabase.lastInsertRow();
@@ -111,12 +96,6 @@
acquireReference();
try {
- if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
- Log.v(TAG, "simpleQueryForLong() for [" + mSql + "]");
- }
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- Log.v(TAG, SQLiteDebug.captureSql(mDatabase.getPath(), mSql, getBindArgs()));
- }
long retValue = native_1x1_long();
mDatabase.logTimeStat(mSql, timeStart);
return retValue;
@@ -140,12 +119,6 @@
acquireReference();
try {
- if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
- Log.v(TAG, "simpleQueryForString() for [" + mSql + "]");
- }
- if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
- Log.v(TAG, SQLiteDebug.captureSql(mDatabase.getPath(), mSql, getBindArgs()));
- }
String retValue = native_1x1_string();
mDatabase.logTimeStat(mSql, timeStart);
return retValue;
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
old mode 100755
new mode 100644
index b0c3909..28a86b8
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -620,7 +620,10 @@
if (mBuffer == null || mKeyboardChanged) {
if (mBuffer == null || mKeyboardChanged &&
(mBuffer.getWidth() != getWidth() || mBuffer.getHeight() != getHeight())) {
- mBuffer = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
+ // Make sure our bitmap is at least 1x1
+ final int width = Math.max(1, getWidth());
+ final int height = Math.max(1, getHeight());
+ mBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBuffer);
}
invalidateAllKeys();
@@ -739,6 +742,10 @@
final Key key = keys[nearestKeyIndices[i]];
int dist = 0;
boolean isInside = key.isInside(x,y);
+ if (isInside) {
+ primaryIndex = nearestKeyIndices[i];
+ }
+
if (((mProximityCorrectOn
&& (dist = key.squaredDistanceFrom(x, y)) < mProximityThreshold)
|| isInside)
@@ -767,10 +774,6 @@
}
}
}
-
- if (isInside) {
- primaryIndex = nearestKeyIndices[i];
- }
}
if (primaryIndex == NOT_A_KEY) {
primaryIndex = closestKey;
diff --git a/core/java/android/os/Base64Utils.java b/core/java/android/os/Base64Utils.java
deleted file mode 100644
index 684a469..0000000
--- a/core/java/android/os/Base64Utils.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-/**
- * {@hide}
- */
-public class Base64Utils
-{
- // TODO add encode api here if possible
-
- public static byte [] decodeBase64(String data) {
- return decodeBase64Native(data);
- }
- private static native byte[] decodeBase64Native(String data);
-}
-
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index 324fbaa..fbc4a81 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -75,8 +75,8 @@
mContext.registerReceiver(mPackageChangedReceiver, packageFilter);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
- sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE);
- sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(mPackageChangedReceiver, sdFilter);
}
@@ -96,8 +96,8 @@
if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
Intent.ACTION_PACKAGE_CHANGED.equals(action) ||
- Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action) ||
- Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+ Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action) ||
+ Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
if (DBG) Log.d(TAG, "Got " + action);
// Update list of searchable activities
getSearchables().buildSearchableList();
diff --git a/core/java/android/storage/StorageManager.java b/core/java/android/storage/StorageManager.java
index dd8bd63..924d169 100644
--- a/core/java/android/storage/StorageManager.java
+++ b/core/java/android/storage/StorageManager.java
@@ -254,6 +254,10 @@
*/
public StorageManager(Looper tgtLooper) throws RemoteException {
mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
+ if (mMountService == null) {
+ Log.e(TAG, "Unable to connect to mount service! - is it running yet?");
+ return;
+ }
mTgtLooper = tgtLooper;
mBinderListener = new MountServiceBinderListener();
mMountService.registerListener(mBinderListener);
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 6d0be43..68be08d 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -145,6 +145,12 @@
break;
}
+ if (KeyEvent.KEYCODE_TAB == keyCode) {
+ if (down) {
+ onEditorAction(EditorInfo.IME_ACTION_NEXT);
+ }
+ return true;
+ }
Spannable text = (Spannable) getText();
int oldLength = text.length();
// Normally the delete key's dom events are sent via onTextChanged.
@@ -819,6 +825,7 @@
break;
case 2: // PASSWORD
inPassword = true;
+ imeOptions |= EditorInfo.IME_ACTION_GO;
break;
case 3: // SEARCH
imeOptions |= EditorInfo.IME_ACTION_SEARCH;
@@ -826,20 +833,22 @@
case 4: // EMAIL
// TYPE_TEXT_VARIATION_WEB_EDIT_TEXT prevents EMAIL_ADDRESS
// from working, so exclude it for now.
- inputType = EditorInfo.TYPE_CLASS_TEXT
- | EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+ imeOptions |= EditorInfo.IME_ACTION_GO;
break;
case 5: // NUMBER
- inputType = EditorInfo.TYPE_CLASS_NUMBER;
+ inputType |= EditorInfo.TYPE_CLASS_NUMBER;
+ // Number and telephone do not have both a Tab key and an
+ // action, so set the action to NEXT
+ imeOptions |= EditorInfo.IME_ACTION_NEXT;
break;
case 6: // TELEPHONE
- inputType = EditorInfo.TYPE_CLASS_PHONE;
+ inputType |= EditorInfo.TYPE_CLASS_PHONE;
+ imeOptions |= EditorInfo.IME_ACTION_NEXT;
break;
case 7: // URL
- // TYPE_TEXT_VARIATION_WEB_EDIT_TEXT prevents URI
- // from working, so exclude it for now.
- inputType = EditorInfo.TYPE_CLASS_TEXT
- | EditorInfo.TYPE_TEXT_VARIATION_URI;
+ // TYPE_TEXT_VARIATION_URI prevents Tab key from showing, so
+ // exclude it for now.
+ imeOptions |= EditorInfo.IME_ACTION_GO;
break;
default:
break;
@@ -855,22 +864,6 @@
mWebView.requestFormData(name, mNodePointer);
}
}
- if (type != 3 /* SEARCH */) {
- int action = mWebView.nativeTextFieldAction();
- switch (action) {
- // Keep in sync with CachedRoot::ImeAction
- case 0: // NEXT
- imeOptions |= EditorInfo.IME_ACTION_NEXT;
- break;
- case 1: // GO
- imeOptions |= EditorInfo.IME_ACTION_GO;
- break;
- case -1: // FAILURE
- case 2: // DONE
- imeOptions |= EditorInfo.IME_ACTION_DONE;
- break;
- }
- }
}
mSingle = single;
setMaxLength(maxLength);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6627973..52c0e01 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -26,6 +26,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Interpolator;
import android.graphics.Picture;
import android.graphics.Point;
import android.graphics.Rect;
@@ -2972,8 +2973,16 @@
if (mTitleBar != null) {
canvas.translate(0, (int) mTitleBar.getHeight());
}
- if (mDragTrackerHandler == null || !mDragTrackerHandler.draw(canvas)) {
+ if (mDragTrackerHandler == null) {
drawContent(canvas);
+ } else {
+ if (!mDragTrackerHandler.draw(canvas)) {
+ // sometimes the tracker doesn't draw, even though its active
+ drawContent(canvas);
+ }
+ if (mDragTrackerHandler.isFinished()) {
+ mDragTrackerHandler = null;
+ }
}
canvas.restoreToCount(saveCount);
@@ -4066,6 +4075,14 @@
private final float mMaxDY, mMaxDX;
private float mCurrStretchY, mCurrStretchX;
private int mSX, mSY;
+ private Interpolator mInterp;
+ private float[] mXY = new float[2];
+
+ // inner (non-state) classes can't have enums :(
+ private static final int DRAGGING_STATE = 0;
+ private static final int ANIMATING_STATE = 1;
+ private static final int FINISHED_STATE = 2;
+ private int mState;
public DragTrackerHandler(float x, float y, DragTracker proxy) {
mProxy = proxy;
@@ -4090,6 +4107,7 @@
mMinDX = -viewLeft;
mMaxDX = docRight - viewRight;
+ mState = DRAGGING_STATE;
mProxy.onStartDrag(x, y);
// ensure we buildBitmap at least once
@@ -4112,6 +4130,12 @@
float sy = computeStretch(mStartY - y, mMinDY, mMaxDY);
float sx = computeStretch(mStartX - x, mMinDX, mMaxDX);
+ if ((mSnapScrollMode & SNAP_X) != 0) {
+ sy = 0;
+ } else if ((mSnapScrollMode & SNAP_Y) != 0) {
+ sx = 0;
+ }
+
if (mCurrStretchX != sx || mCurrStretchY != sy) {
mCurrStretchX = sx;
mCurrStretchY = sy;
@@ -4126,10 +4150,26 @@
}
public void stopDrag() {
+ final int DURATION = 200;
+ int now = (int)SystemClock.uptimeMillis();
+ mInterp = new Interpolator(2);
+ mXY[0] = mCurrStretchX;
+ mXY[1] = mCurrStretchY;
+ // float[] blend = new float[] { 0.5f, 0, 0.75f, 1 };
+ float[] blend = new float[] { 0, 0.5f, 0.75f, 1 };
+ mInterp.setKeyFrame(0, now, mXY, blend);
+ float[] zerozero = new float[] { 0, 0 };
+ mInterp.setKeyFrame(1, now + DURATION, zerozero, null);
+ mState = ANIMATING_STATE;
+
if (DebugFlags.DRAG_TRACKER || DEBUG_DRAG_TRACKER) {
- Log.d(DebugFlags.DRAG_TRACKER_LOGTAG, "----- stopDrag");
+ Log.d(DebugFlags.DRAG_TRACKER_LOGTAG, "----- stopDrag, starting animation");
}
- mProxy.onStopDrag();
+ }
+
+ // Call this after each draw. If it ruturns null, the tracker is done
+ public boolean isFinished() {
+ return mState == FINISHED_STATE;
}
private int hiddenHeightOfTitleBar() {
@@ -4150,13 +4190,23 @@
if (mCurrStretchX != 0 || mCurrStretchY != 0) {
int sx = getScrollX();
int sy = getScrollY() - hiddenHeightOfTitleBar();
-
if (mSX != sx || mSY != sy) {
buildBitmap(sx, sy);
mSX = sx;
mSY = sy;
}
+ if (mState == ANIMATING_STATE) {
+ Interpolator.Result result = mInterp.timeToValues(mXY);
+ if (result == Interpolator.Result.FREEZE_END) {
+ mState = FINISHED_STATE;
+ return false;
+ } else {
+ mProxy.onStretchChange(mXY[0], mXY[1]);
+ invalidate();
+ // fall through to the draw
+ }
+ }
int count = canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(sx, sy);
mProxy.onDraw(canvas);
@@ -4600,7 +4650,6 @@
case MotionEvent.ACTION_UP: {
if (mDragTrackerHandler != null) {
mDragTrackerHandler.stopDrag();
- mDragTrackerHandler = null;
}
mLastTouchUpTime = eventTime;
switch (mTouchMode) {
@@ -4712,7 +4761,6 @@
private void cancelTouch() {
if (mDragTrackerHandler != null) {
mDragTrackerHandler.stopDrag();
- mDragTrackerHandler = null;
}
// we also use mVelocityTracker == null to tell us that we are
// not "moving around", so we can take the slower/prettier
@@ -6736,8 +6784,6 @@
private native void nativeSetFindIsUp();
private native void nativeSetFollowedLink(boolean followed);
private native void nativeSetHeightCanMeasure(boolean measure);
- // Returns a value corresponding to CachedFrame::ImeAction
- /* package */ native int nativeTextFieldAction();
private native int nativeTextGeneration();
// Never call this version except by updateCachedTextfield(String) -
// we always want to pass in our generation number.
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index fd6af05..2f96aef 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1953,6 +1953,7 @@
}
}
}
+ mLastTouchMode = isInTouchMode ? TOUCH_MODE_ON : TOUCH_MODE_OFF;
}
@Override
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboard.java b/core/java/com/android/internal/widget/PasswordEntryKeyboard.java
new file mode 100644
index 0000000..51f7f69
--- /dev/null
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboard.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.internal.widget;
+
+import java.util.Locale;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.Paint.Align;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.inputmethodservice.Keyboard;
+import android.inputmethodservice.KeyboardView;
+import android.util.Log;
+import com.android.internal.R;
+
+/**
+ * A basic, embed-able keyboard designed for password entry. Allows entry of all Latin-1 characters.
+ *
+ * It has two modes: alpha and numeric. In alpha mode, it allows all Latin-1 characters and enables
+ * an additional keyboard with symbols. In numeric mode, it shows a 12-key DTMF dialer-like
+ * keypad with alpha characters hints.
+ */
+public class PasswordEntryKeyboard extends Keyboard {
+ private static final String TAG = "PasswordEntryKeyboard";
+ private static final int SHIFT_OFF = 0;
+ private static final int SHIFT_ON = 1;
+ private static final int SHIFT_LOCKED = 2;
+ public static final int KEYCODE_SPACE = ' ';
+
+ private Drawable mShiftIcon;
+ private Drawable mShiftLockIcon;
+ private Drawable mShiftLockPreviewIcon;
+ private Drawable mOldShiftIcon;
+ private Drawable mOldShiftPreviewIcon;
+ private Drawable mSpaceIcon;
+ private Key mShiftKey;
+ private Key mEnterKey;
+ private Key mF1Key;
+ private Key mSpaceKey;
+ private Locale mLocale;
+ private Resources mRes;
+ private int mExtensionResId;
+ private int mShiftState = SHIFT_OFF;
+
+ static int sSpacebarVerticalCorrection;
+
+ public PasswordEntryKeyboard(Context context, int xmlLayoutResId) {
+ this(context, xmlLayoutResId, 0);
+ }
+
+ public PasswordEntryKeyboard(Context context, int xmlLayoutResId, int mode) {
+ super(context, xmlLayoutResId, mode);
+ final Resources res = context.getResources();
+ mRes = res;
+ mShiftIcon = res.getDrawable(R.drawable.sym_keyboard_shift);
+ mShiftLockIcon = res.getDrawable(R.drawable.sym_keyboard_shift_locked);
+ mShiftLockPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_shift_locked);
+ mShiftLockPreviewIcon.setBounds(0, 0,
+ mShiftLockPreviewIcon.getIntrinsicWidth(),
+ mShiftLockPreviewIcon.getIntrinsicHeight());
+ mSpaceIcon = res.getDrawable(R.drawable.sym_keyboard_space);
+ sSpacebarVerticalCorrection = res.getDimensionPixelOffset(
+ R.dimen.password_keyboard_spacebar_vertical_correction);
+ }
+
+ public PasswordEntryKeyboard(Context context, int layoutTemplateResId,
+ CharSequence characters, int columns, int horizontalPadding) {
+ super(context, layoutTemplateResId, characters, columns, horizontalPadding);
+ }
+
+ @Override
+ protected Key createKeyFromXml(Resources res, Row parent, int x, int y,
+ XmlResourceParser parser) {
+ LatinKey key = new LatinKey(res, parent, x, y, parser);
+ final int code = key.codes[0];
+ if (code >=0 && code != '\n' && (code < 32 || code > 127)) {
+ Log.w(TAG, "Key code for " + key.label + " is not latin-1");
+ key.label = " ";
+ key.setEnabled(false);
+ }
+ switch (key.codes[0]) {
+ case 10:
+ mEnterKey = key;
+ break;
+ case PasswordEntryKeyboardView.KEYCODE_F1:
+ mF1Key = key;
+ break;
+ case 32:
+ mSpaceKey = key;
+ break;
+ }
+ return key;
+ }
+
+ /**
+ * Allows enter key resources to be overridden
+ * @param res resources to grab given items from
+ * @param previewId preview drawable shown on enter key
+ * @param iconId normal drawable shown on enter key
+ * @param labelId string shown on enter key
+ */
+ void setEnterKeyResources(Resources res, int previewId, int iconId, int labelId) {
+ if (mEnterKey != null) {
+ // Reset some of the rarely used attributes.
+ mEnterKey.popupCharacters = null;
+ mEnterKey.popupResId = 0;
+ mEnterKey.text = null;
+
+ mEnterKey.iconPreview = res.getDrawable(previewId);
+ mEnterKey.icon = res.getDrawable(iconId);
+ mEnterKey.label = res.getText(labelId);
+
+ // Set the initial size of the preview icon
+ if (mEnterKey.iconPreview != null) {
+ mEnterKey.iconPreview.setBounds(0, 0,
+ mEnterKey.iconPreview.getIntrinsicWidth(),
+ mEnterKey.iconPreview.getIntrinsicHeight());
+ }
+ }
+ }
+
+ /**
+ * Allows shiftlock to be turned on. See {@link #setShiftLocked(boolean)}
+ *
+ */
+ void enableShiftLock() {
+ int index = getShiftKeyIndex();
+ if (index >= 0) {
+ mShiftKey = getKeys().get(index);
+ if (mShiftKey instanceof LatinKey) {
+ ((LatinKey)mShiftKey).enableShiftLock();
+ }
+ mOldShiftIcon = mShiftKey.icon;
+ mOldShiftPreviewIcon = mShiftKey.iconPreview;
+ }
+ }
+
+ /**
+ * Turn on shift lock. This turns on the LED for this key, if it has one.
+ * It should be followed by a call to {@link KeyboardView#invalidateKey(int)}
+ * or {@link KeyboardView#invalidateAllKeys()}
+ *
+ * @param shiftLocked
+ */
+ void setShiftLocked(boolean shiftLocked) {
+ if (mShiftKey != null) {
+ if (shiftLocked) {
+ mShiftKey.on = true;
+ mShiftKey.icon = mShiftLockIcon;
+ mShiftState = SHIFT_LOCKED;
+ } else {
+ mShiftKey.on = false;
+ mShiftKey.icon = mShiftLockIcon;
+ mShiftState = SHIFT_ON;
+ }
+ }
+ }
+
+ /**
+ * Turn on shift mode. Sets shift mode and turns on icon for shift key.
+ * It should be followed by a call to {@link KeyboardView#invalidateKey(int)}
+ * or {@link KeyboardView#invalidateAllKeys()}
+ *
+ * @param shiftLocked
+ */
+ @Override
+ public boolean setShifted(boolean shiftState) {
+ boolean shiftChanged = false;
+ if (mShiftKey != null) {
+ if (shiftState == false) {
+ shiftChanged = mShiftState != SHIFT_OFF;
+ mShiftState = SHIFT_OFF;
+ mShiftKey.on = false;
+ mShiftKey.icon = mOldShiftIcon;
+ } else if (mShiftState == SHIFT_OFF) {
+ shiftChanged = mShiftState == SHIFT_OFF;
+ mShiftState = SHIFT_ON;
+ mShiftKey.on = false;
+ mShiftKey.icon = mShiftIcon;
+ }
+ } else {
+ return super.setShifted(shiftState);
+ }
+ return shiftChanged;
+ }
+
+ /**
+ * Whether or not keyboard is shifted.
+ * @return true if keyboard state is shifted.
+ */
+ @Override
+ public boolean isShifted() {
+ if (mShiftKey != null) {
+ return mShiftState != SHIFT_OFF;
+ } else {
+ return super.isShifted();
+ }
+ }
+
+ /**
+ * Sets keyboard extension. Keyboard extension is shown when input is detected above keyboard
+ * while keyboard has focus.
+ *
+ * @param resId
+ */
+ public void setExtension(int resId) {
+ mExtensionResId = resId;
+ }
+
+ /**
+ * Get current extesion resource id.
+ *
+ * @return resource id, 0 if not set.
+ */
+ public int getExtension() {
+ return mExtensionResId;
+ }
+
+ private void updateSpaceBarForLocale() {
+ if (mLocale != null) {
+ // Create the graphic for spacebar
+ Bitmap buffer = Bitmap.createBitmap(mSpaceKey.width, mSpaceIcon.getIntrinsicHeight(),
+ Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(buffer);
+ canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ // TODO: Make the text size a customizable attribute
+ paint.setTextSize(22);
+ paint.setTextAlign(Align.CENTER);
+ // Draw a drop shadow for the text
+ paint.setShadowLayer(1f, 0, 0, 0xFF000000);
+ paint.setColor(0x80C0C0C0);
+ canvas.drawText(mLocale.getDisplayLanguage(mLocale),
+ buffer.getWidth() / 2, - paint.ascent() + 2, paint);
+ int x = (buffer.getWidth() - mSpaceIcon.getIntrinsicWidth()) / 2;
+ int y = buffer.getHeight() - mSpaceIcon.getIntrinsicHeight();
+ mSpaceIcon.setBounds(x, y,
+ x + mSpaceIcon.getIntrinsicWidth(), y + mSpaceIcon.getIntrinsicHeight());
+ mSpaceIcon.draw(canvas);
+ mSpaceKey.icon = new BitmapDrawable(mRes, buffer);
+ mSpaceKey.repeatable = false;
+ } else {
+ mSpaceKey.icon = mRes.getDrawable(R.drawable.sym_keyboard_space);
+ mSpaceKey.repeatable = true;
+ }
+ }
+
+ public void setLanguage(Locale locale) {
+ if (mLocale != null && mLocale.equals(locale)) return;
+ mLocale = locale;
+ updateSpaceBarForLocale();
+ }
+
+ static class LatinKey extends Keyboard.Key {
+ private boolean mShiftLockEnabled;
+ private boolean mEnabled = true;
+
+ public LatinKey(Resources res, Keyboard.Row parent, int x, int y,
+ XmlResourceParser parser) {
+ super(res, parent, x, y, parser);
+ if (popupCharacters != null && popupCharacters.length() == 0) {
+ // If there is a keyboard with no keys specified in popupCharacters
+ popupResId = 0;
+ }
+ }
+
+ void setEnabled(boolean enabled) {
+ mEnabled = enabled;
+ }
+
+ void enableShiftLock() {
+ mShiftLockEnabled = true;
+ }
+
+ @Override
+ public void onReleased(boolean inside) {
+ if (!mShiftLockEnabled) {
+ super.onReleased(inside);
+ } else {
+ pressed = !pressed;
+ }
+ }
+
+ /**
+ * Overriding this method so that we can reduce the target area for certain keys.
+ */
+ @Override
+ public boolean isInside(int x, int y) {
+ if (!mEnabled) {
+ return false;
+ }
+ final int code = codes[0];
+ if (code == KEYCODE_SHIFT || code == KEYCODE_DELETE) {
+ y -= height / 10;
+ if (code == KEYCODE_SHIFT) x += width / 6;
+ if (code == KEYCODE_DELETE) x -= width / 6;
+ } else if (code == KEYCODE_SPACE) {
+ y += PasswordEntryKeyboard.sSpacebarVerticalCorrection;
+ }
+ return super.isInside(x, y);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
new file mode 100644
index 0000000..b809afc
--- /dev/null
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.inputmethodservice.Keyboard;
+import android.inputmethodservice.KeyboardView;
+import android.inputmethodservice.KeyboardView.OnKeyboardActionListener;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.text.Editable;
+import android.text.Selection;
+import android.util.Log;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewRoot;
+import android.view.inputmethod.InputConnection;
+import android.widget.EditText;
+import com.android.internal.R;
+
+public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener {
+
+ public static final int KEYBOARD_MODE_ALPHA = 0;
+ public static final int KEYBOARD_MODE_NUMERIC = 1;
+ private static final int KEYBOARD_STATE_NORMAL = 0;
+ private static final int KEYBOARD_STATE_SHIFTED = 1;
+ private static final int KEYBOARD_STATE_CAPSLOCK = 2;
+ private static final String TAG = "PasswordEntryKeyboardHelper";
+ private int mKeyboardMode = KEYBOARD_MODE_ALPHA;
+ private int mKeyboardState = KEYBOARD_STATE_NORMAL;
+ private PasswordEntryKeyboard mQwertyKeyboard;
+ private PasswordEntryKeyboard mQwertyKeyboardShifted;
+ private PasswordEntryKeyboard mSymbolsKeyboard;
+ private PasswordEntryKeyboard mSymbolsKeyboardShifted;
+ private PasswordEntryKeyboard mNumericKeyboard;
+ private Context mContext;
+ private View mTargetView;
+ private KeyboardView mKeyboardView;
+
+ public PasswordEntryKeyboardHelper(Context context, KeyboardView keyboardView, View targetView) {
+ mContext = context;
+ mTargetView = targetView;
+ mKeyboardView = keyboardView;
+ createKeyboards();
+ mKeyboardView.setOnKeyboardActionListener(this);
+ }
+
+ public boolean isAlpha() {
+ return mKeyboardMode == KEYBOARD_MODE_ALPHA;
+ }
+
+ private void createKeyboards() {
+ mNumericKeyboard = new PasswordEntryKeyboard(mContext, R.xml.password_kbd_numeric);
+ mQwertyKeyboard = new PasswordEntryKeyboard(mContext,
+ R.xml.password_kbd_qwerty, R.id.mode_normal);
+ mQwertyKeyboard.enableShiftLock();
+
+ mQwertyKeyboardShifted = new PasswordEntryKeyboard(mContext,
+ R.xml.password_kbd_qwerty_shifted,
+ R.id.mode_normal);
+ mQwertyKeyboardShifted.enableShiftLock();
+ mQwertyKeyboardShifted.setShifted(true); // always shifted.
+
+ mSymbolsKeyboard = new PasswordEntryKeyboard(mContext, R.xml.password_kbd_symbols);
+ mSymbolsKeyboard.enableShiftLock();
+
+ mSymbolsKeyboardShifted = new PasswordEntryKeyboard(mContext,
+ R.xml.password_kbd_symbols_shift);
+ mSymbolsKeyboardShifted.enableShiftLock();
+ mSymbolsKeyboardShifted.setShifted(true); // always shifted
+ }
+
+ public void setKeyboardMode(int mode) {
+ switch (mode) {
+ case KEYBOARD_MODE_ALPHA:
+ mKeyboardView.setKeyboard(mQwertyKeyboard);
+ mKeyboardState = KEYBOARD_STATE_NORMAL;
+ break;
+ case KEYBOARD_MODE_NUMERIC:
+ mKeyboardView.setKeyboard(mNumericKeyboard);
+ mKeyboardState = KEYBOARD_STATE_NORMAL;
+ break;
+ }
+ mKeyboardMode = mode;
+ }
+
+ private void sendKeyEventsToTarget(int keyEventCode) {
+ Handler handler = mTargetView.getHandler();
+ KeyEvent[] events = KeyCharacterMap.load(KeyCharacterMap.ALPHA).getEvents(
+ new char[] { (char) keyEventCode });
+ if (events != null) {
+ for (KeyEvent event : events) {
+ handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY, event));
+ }
+ }
+ }
+
+ public void sendDownUpKeyEvents(int keyEventCode) {
+ long eventTime = SystemClock.uptimeMillis();
+ Handler handler = mTargetView.getHandler();
+ handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+ new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, 0, 0,
+ KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
+ handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+ new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0, 0, 0,
+ KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
+ }
+
+ public void onKey(int primaryCode, int[] keyCodes) {
+ Log.v(TAG, "Key code = " + Integer.toHexString(primaryCode));
+ if (primaryCode == Keyboard.KEYCODE_DELETE) {
+ handleBackspace();
+ } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
+ handleShift();
+ } else if (primaryCode == Keyboard.KEYCODE_CANCEL) {
+ handleClose();
+ return;
+ } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE && mKeyboardView != null) {
+ handleModeChange();
+ } else {
+ handleCharacter(primaryCode, keyCodes);
+ // Switch back to old keyboard if we're not in capslock mode
+ if (mKeyboardState == KEYBOARD_STATE_SHIFTED) {
+ // skip to the unlocked state
+ mKeyboardState = KEYBOARD_STATE_CAPSLOCK;
+ handleShift();
+ }
+ }
+ }
+
+ private void handleModeChange() {
+ final Keyboard current = mKeyboardView.getKeyboard();
+ Keyboard next = null;
+ if (current == mQwertyKeyboard || current == mQwertyKeyboardShifted) {
+ next = mSymbolsKeyboard;
+ } else if (current == mSymbolsKeyboard || current == mSymbolsKeyboardShifted) {
+ next = mQwertyKeyboard;
+ }
+ if (next != null) {
+ mKeyboardView.setKeyboard(next);
+ mKeyboardState = KEYBOARD_STATE_NORMAL;
+ }
+ }
+
+ private void handleBackspace() {
+ sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
+ }
+
+ private void handleShift() {
+ if (mKeyboardView == null) {
+ return;
+ }
+ Keyboard current = mKeyboardView.getKeyboard();
+ PasswordEntryKeyboard next = null;
+ final boolean isAlphaMode = current == mQwertyKeyboard
+ || current == mQwertyKeyboardShifted;
+ if (mKeyboardState == KEYBOARD_STATE_NORMAL) {
+ mKeyboardState = isAlphaMode ? KEYBOARD_STATE_SHIFTED : KEYBOARD_STATE_CAPSLOCK;
+ next = isAlphaMode ? mQwertyKeyboardShifted : mSymbolsKeyboardShifted;
+ } else if (mKeyboardState == KEYBOARD_STATE_SHIFTED) {
+ mKeyboardState = KEYBOARD_STATE_CAPSLOCK;
+ next = isAlphaMode ? mQwertyKeyboardShifted : mSymbolsKeyboardShifted;
+ } else if (mKeyboardState == KEYBOARD_STATE_CAPSLOCK) {
+ mKeyboardState = KEYBOARD_STATE_NORMAL;
+ next = isAlphaMode ? mQwertyKeyboard : mSymbolsKeyboard;
+ }
+ if (next != null) {
+ if (next != current) {
+ mKeyboardView.setKeyboard(next);
+ }
+ next.setShiftLocked(mKeyboardState == KEYBOARD_STATE_CAPSLOCK);
+ mKeyboardView.setShifted(mKeyboardState != KEYBOARD_STATE_NORMAL);
+ }
+ }
+
+ private void handleCharacter(int primaryCode, int[] keyCodes) {
+ // Maybe turn off shift if not in capslock mode.
+ if (mKeyboardView.isShifted() && primaryCode != ' ' && primaryCode != '\n') {
+ primaryCode = Character.toUpperCase(primaryCode);
+ }
+ sendKeyEventsToTarget(primaryCode);
+ }
+
+ private void handleClose() {
+
+ }
+
+ public void onPress(int primaryCode) {
+
+ }
+
+ public void onRelease(int primaryCode) {
+
+ }
+
+ public void onText(CharSequence text) {
+
+ }
+
+ public void swipeDown() {
+
+ }
+
+ public void swipeLeft() {
+
+ }
+
+ public void swipeRight() {
+
+ }
+
+ public void swipeUp() {
+
+ }
+};
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardView.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardView.java
new file mode 100644
index 0000000..9b93fc2
--- /dev/null
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardView.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.inputmethodservice.Keyboard;
+import android.inputmethodservice.KeyboardView;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.widget.PopupWindow;
+import com.android.internal.R;
+
+public class PasswordEntryKeyboardView extends KeyboardView {
+
+ public static final int KEYCODE_OPTIONS = -100;
+ static final int KEYCODE_SHIFT_LONGPRESS = -101;
+ static final int KEYCODE_VOICE = -102;
+ static final int KEYCODE_F1 = -103;
+ static final int KEYCODE_NEXT_LANGUAGE = -104;
+
+ private boolean mExtensionVisible;
+ private PasswordEntryKeyboardView mExtension;
+ private PopupWindow mExtensionPopup;
+ private boolean mFirstEvent;
+
+ public PasswordEntryKeyboardView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public PasswordEntryKeyboardView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent me) {
+ if (((PasswordEntryKeyboard) getKeyboard()).getExtension() == 0) {
+ return super.onTouchEvent(me);
+ }
+ if (me.getY() < 0) {
+ if (mExtensionVisible) {
+ int action = me.getAction();
+ if (mFirstEvent) action = MotionEvent.ACTION_DOWN;
+ mFirstEvent = false;
+ MotionEvent translated = MotionEvent.obtain(me.getEventTime(), me.getEventTime(),
+ action,
+ me.getX(), me.getY() + mExtension.getHeight(), me.getMetaState());
+ boolean result = mExtension.onTouchEvent(translated);
+ translated.recycle();
+ if (me.getAction() == MotionEvent.ACTION_UP
+ || me.getAction() == MotionEvent.ACTION_CANCEL) {
+ closeExtension();
+ }
+ return result;
+ } else {
+ if (openExtension()) {
+ MotionEvent cancel = MotionEvent.obtain(me.getDownTime(), me.getEventTime(),
+ MotionEvent.ACTION_CANCEL, me.getX() - 100, me.getY() - 100, 0);
+ super.onTouchEvent(cancel);
+ cancel.recycle();
+ if (mExtension.getHeight() > 0) {
+ MotionEvent translated = MotionEvent.obtain(me.getEventTime(),
+ me.getEventTime(),
+ MotionEvent.ACTION_DOWN,
+ me.getX(), me.getY() + mExtension.getHeight(),
+ me.getMetaState());
+ mExtension.onTouchEvent(translated);
+ translated.recycle();
+ } else {
+ mFirstEvent = true;
+ }
+ }
+ return true;
+ }
+ } else if (mExtensionVisible) {
+ closeExtension();
+ // Send a down event into the main keyboard first
+ MotionEvent down = MotionEvent.obtain(me.getEventTime(), me.getEventTime(),
+ MotionEvent.ACTION_DOWN, me.getX(), me.getY(), me.getMetaState());
+ super.onTouchEvent(down);
+ down.recycle();
+ // Send the actual event
+ return super.onTouchEvent(me);
+ } else {
+ return super.onTouchEvent(me);
+ }
+ }
+
+ private boolean openExtension() {
+ if (((PasswordEntryKeyboard) getKeyboard()).getExtension() == 0) return false;
+ makePopupWindow();
+ mExtensionVisible = true;
+ return true;
+ }
+
+ private void makePopupWindow() {
+ if (mExtensionPopup == null) {
+ int[] windowLocation = new int[2];
+ mExtensionPopup = new PopupWindow(getContext());
+ mExtensionPopup.setBackgroundDrawable(null);
+ LayoutInflater li = (LayoutInflater) getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ mExtension = (PasswordEntryKeyboardView) li.inflate(
+ R.layout.password_keyboard_input, null);
+ mExtension.setOnKeyboardActionListener(getOnKeyboardActionListener());
+ mExtension.setPopupParent(this);
+ mExtension.setPopupOffset(0, -windowLocation[1]);
+ Keyboard keyboard;
+ mExtension.setKeyboard(keyboard = new PasswordEntryKeyboard(getContext(),
+ ((PasswordEntryKeyboard) getKeyboard()).getExtension()));
+ mExtensionPopup.setContentView(mExtension);
+ mExtensionPopup.setWidth(getWidth());
+ mExtensionPopup.setHeight(keyboard.getHeight());
+ getLocationInWindow(windowLocation);
+ // TODO: Fix the "- 30".
+ mExtension.setPopupOffset(0, -windowLocation[1] - 30);
+ mExtensionPopup.showAtLocation(this, 0, 0, -keyboard.getHeight()
+ + windowLocation[1]);
+ } else {
+ mExtension.setVisibility(VISIBLE);
+ }
+ }
+
+ @Override
+ public void closing() {
+ super.closing();
+ if (mExtensionPopup != null && mExtensionPopup.isShowing()) {
+ mExtensionPopup.dismiss();
+ mExtensionPopup = null;
+ }
+ }
+
+ private void closeExtension() {
+ mExtension.setVisibility(INVISIBLE);
+ mExtension.closing();
+ mExtensionVisible = false;
+ }
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 7fd58e8..1ffd265 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -70,7 +70,6 @@
android_util_Process.cpp \
android_util_StringBlock.cpp \
android_util_XmlBlock.cpp \
- android_util_Base64.cpp \
android/graphics/Bitmap.cpp \
android/graphics/BitmapFactory.cpp \
android/graphics/Camera.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 1d22de3..7c8df03 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -153,7 +153,6 @@
extern int register_android_server_BluetoothA2dpService(JNIEnv* env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env);
-extern int register_android_util_Base64(JNIEnv* env);
extern int register_android_location_GpsLocationProvider(JNIEnv* env);
extern int register_android_backup_BackupDataInput(JNIEnv *env);
extern int register_android_backup_BackupDataOutput(JNIEnv *env);
@@ -1266,7 +1265,6 @@
REG_JNI(register_android_server_BluetoothA2dpService),
REG_JNI(register_android_message_digest_sha1),
REG_JNI(register_android_ddm_DdmHandleNativeHeap),
- REG_JNI(register_android_util_Base64),
REG_JNI(register_android_location_GpsLocationProvider),
REG_JNI(register_android_backup_BackupDataInput),
REG_JNI(register_android_backup_BackupDataOutput),
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index 020aff4a..c197010 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -143,12 +143,68 @@
if (handle != NULL) sqlite3_close(handle);
}
+void sqlTrace(void *databaseName, const char *sql) {
+ LOGI("sql_statement|%s|%s\n", (char *)databaseName, sql);
+}
+
+/* public native void enableSqlTracing(); */
+static void enableSqlTracing(JNIEnv* env, jobject object, jstring databaseName)
+{
+ sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
+ char const *path = env->GetStringUTFChars(databaseName, NULL);
+ if (path == NULL) {
+ LOGE("Failure in enableSqlTracing(). VM ran out of memory?\n");
+ return; // VM would have thrown OutOfMemoryError
+ }
+ int len = strlen(path);
+ char *traceFuncArg = (char *)malloc(len + 1);
+ strncpy(traceFuncArg, path, len);
+ traceFuncArg[len-1] = NULL;
+ env->ReleaseStringUTFChars(databaseName, path);
+ sqlite3_trace(handle, &sqlTrace, (void *)traceFuncArg);
+ LOGI("will be printing all sql statements executed on database = %s\n", traceFuncArg);
+}
+
+void sqlProfile(void *databaseName, const char *sql, sqlite3_uint64 tm) {
+ double d = tm/1000000.0;
+ LOGI("elapsedTime4Sql|%s|%.3f ms|%s\n", (char *)databaseName, d, sql);
+}
+
+/* public native void enableSqlProfiling(); */
+static void enableSqlProfiling(JNIEnv* env, jobject object, jstring databaseName)
+{
+ sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
+ char const *path = env->GetStringUTFChars(databaseName, NULL);
+ if (path == NULL) {
+ LOGE("Failure in enableSqlProfiling(). VM ran out of memory?\n");
+ return; // VM would have thrown OutOfMemoryError
+ }
+ int len = strlen(path);
+ char *traceFuncArg = (char *)malloc(len + 1);
+ strncpy(traceFuncArg, path, len);
+ traceFuncArg[len-1] = NULL;
+ env->ReleaseStringUTFChars(databaseName, path);
+ sqlite3_profile(handle, &sqlProfile, (void *)traceFuncArg);
+ LOGI("will be printing execution time of all sql statements executed on database = %s\n",
+ traceFuncArg);
+}
+
/* public native void close(); */
static void dbclose(JNIEnv* env, jobject object)
{
sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
if (handle != NULL) {
+ // release the memory associated with the traceFuncArg in enableSqlTracing function
+ void *traceFuncArg = sqlite3_trace(handle, &sqlTrace, NULL);
+ if (traceFuncArg != NULL) {
+ free(traceFuncArg);
+ }
+ // release the memory associated with the traceFuncArg in enableSqlProfiling function
+ traceFuncArg = sqlite3_profile(handle, &sqlProfile, NULL);
+ if (traceFuncArg != NULL) {
+ free(traceFuncArg);
+ }
LOGV("Closing database: handle=%p\n", handle);
int result = sqlite3_close(handle);
if (result == SQLITE_OK) {
@@ -357,6 +413,8 @@
/* name, signature, funcPtr */
{"dbopen", "(Ljava/lang/String;I)V", (void *)dbopen},
{"dbclose", "()V", (void *)dbclose},
+ {"enableSqlTracing", "(Ljava/lang/String;)V", (void *)enableSqlTracing},
+ {"enableSqlProfiling", "(Ljava/lang/String;)V", (void *)enableSqlProfiling},
{"native_execSQL", "(Ljava/lang/String;)V", (void *)native_execSQL},
{"lastInsertRow", "()J", (void *)lastInsertRow},
{"lastChangeCount", "()I", (void *)lastChangeCount},
diff --git a/core/jni/android_util_Base64.cpp b/core/jni/android_util_Base64.cpp
deleted file mode 100644
index bc69747..0000000
--- a/core/jni/android_util_Base64.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/* //device/libs/android_runtime/android_util_Base64.cpp
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-/*********************************************************
-*
-* This code was copied from
-* system/extra/ssh/dropbear-0.49/libtomcrypt/src/misc/base64/base64_decode.c
-*
-*********************************************************/
-
-#define LOG_TAG "Base64"
-
-#include <utils/Log.h>
-
-#include <android_runtime/AndroidRuntime.h>
-
-#include "JNIHelp.h"
-
-#include <sys/errno.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <signal.h>
-
-namespace android {
-
-static const unsigned char map[256] = {
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
-255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
-255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
- 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255 };
-
-/**
- base64 decode a block of memory
- @param in The base64 data to decode
- @param inlen The length of the base64 data
- @param out [out] The destination of the binary decoded data
- @param outlen [in/out] The max size and resulting size of the decoded data
- @return 0 if successful
-*/
-int base64_decode(const unsigned char *in, unsigned long inlen,
- unsigned char *out, unsigned long *outlen)
-{
- unsigned long t, x, y, z;
- unsigned char c;
- int g;
-
- g = 3;
- for (x = y = z = t = 0; x < inlen; x++) {
- c = map[in[x]&0xFF];
- if (c == 255) continue;
- /* the final = symbols are read and used to trim the remaining bytes */
- if (c == 254) {
- c = 0;
- /* prevent g < 0 which would potentially allow an overflow later */
- if (--g < 0) {
- return -3;
- }
- } else if (g != 3) {
- /* we only allow = to be at the end */
- return -4;
- }
-
- t = (t<<6)|c;
-
- if (++y == 4) {
- if (z + g > *outlen) {
- return -2;
- }
- out[z++] = (unsigned char)((t>>16)&255);
- if (g > 1) out[z++] = (unsigned char)((t>>8)&255);
- if (g > 2) out[z++] = (unsigned char)(t&255);
- y = t = 0;
- }
- }
- if (y != 0) {
- return -5;
- }
- *outlen = z;
- return 0;
-}
-
-static jbyteArray decodeBase64(JNIEnv *env, jobject jobj, jstring jdata)
-{
- const char * rawData = env->GetStringUTFChars(jdata, NULL);
- int stringLength = env->GetStringUTFLength(jdata);
-
- int resultLength = stringLength / 4 * 3;
- if (rawData[stringLength-1] == '=') {
- resultLength -= 1;
- if (rawData[stringLength-2] == '=') {
- resultLength -= 1;
- }
- }
-
- jbyteArray byteArray = env->NewByteArray(resultLength);
- jbyte* byteArrayData = env->GetByteArrayElements(byteArray, NULL);
-
- unsigned long outlen = resultLength;
- int result = base64_decode((const unsigned char*)rawData, stringLength, (unsigned char *)byteArrayData, &outlen);
- if (result != 0)
- memset((unsigned char *)byteArrayData, -result, resultLength);
-
- env->ReleaseStringUTFChars(jdata, rawData);
- env->ReleaseByteArrayElements(byteArray, byteArrayData, 0);
-
- return byteArray;
-}
-
-static const JNINativeMethod methods[] = {
- {"decodeBase64Native", "(Ljava/lang/String;)[B", (void*)decodeBase64 }
-};
-
-static const char* const kBase64PathName = "android/os/Base64Utils";
-
-int register_android_util_Base64(JNIEnv* env)
-{
- jclass clazz;
-
- clazz = env->FindClass(kBase64PathName);
- LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Base64Utils");
-
- return AndroidRuntime::registerNativeMethods(
- env, kBase64PathName,
- methods, NELEM(methods));
-}
-
-}
diff --git a/core/res/res/drawable-en-hdpi/sym_keyboard_delete.png b/core/res/res/drawable-en-hdpi/sym_keyboard_delete.png
new file mode 100755
index 0000000..569369e
--- /dev/null
+++ b/core/res/res/drawable-en-hdpi/sym_keyboard_delete.png
Binary files differ
diff --git a/core/res/res/drawable-en-hdpi/sym_keyboard_feedback_delete.png b/core/res/res/drawable-en-hdpi/sym_keyboard_feedback_delete.png
new file mode 100755
index 0000000..ca76375
--- /dev/null
+++ b/core/res/res/drawable-en-hdpi/sym_keyboard_feedback_delete.png
Binary files differ
diff --git a/core/res/res/drawable-en-mdpi/sym_keyboard_delete.png b/core/res/res/drawable-en-mdpi/sym_keyboard_delete.png
new file mode 100644
index 0000000..f1f7c58c
--- /dev/null
+++ b/core/res/res/drawable-en-mdpi/sym_keyboard_delete.png
Binary files differ
diff --git a/core/res/res/drawable-en-mdpi/sym_keyboard_feedback_delete.png b/core/res/res/drawable-en-mdpi/sym_keyboard_feedback_delete.png
new file mode 100644
index 0000000..3c90839
--- /dev/null
+++ b/core/res/res/drawable-en-mdpi/sym_keyboard_feedback_delete.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal.9.png
new file mode 100644
index 0000000..b6c234c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal_off.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal_off.9.png
new file mode 100644
index 0000000..9f3c087
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal_off.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal_on.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal_on.9.png
new file mode 100644
index 0000000..4041342
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal_on.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed.9.png
new file mode 100644
index 0000000..73a8cd1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed_off.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed_off.9.png
new file mode 100644
index 0000000..8473e8e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed_off.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed_on.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed_on.9.png
new file mode 100644
index 0000000..f4f59c0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed_on.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_trans_normal_off.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_trans_normal_off.9.png
new file mode 100644
index 0000000..1508653
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_trans_normal_off.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_trans_normal_on.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_trans_normal_on.9.png
new file mode 100644
index 0000000..66c231a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_trans_normal_on.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_trans_pressed_off.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_trans_pressed_off.9.png
new file mode 100644
index 0000000..cdad182
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_trans_pressed_off.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_trans_pressed_on.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_trans_pressed_on.9.png
new file mode 100644
index 0000000..e95f4cf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_trans_pressed_on.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/password_field_default.9.png b/core/res/res/drawable-hdpi/password_field_default.9.png
new file mode 100644
index 0000000..2c424f0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/password_field_default.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_delete.png b/core/res/res/drawable-hdpi/sym_keyboard_delete.png
new file mode 100755
index 0000000..59d78be
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_delete.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_delete_dim.png b/core/res/res/drawable-hdpi/sym_keyboard_delete_dim.png
new file mode 100644
index 0000000..34b6d1f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_delete_dim.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_feedback_delete.png b/core/res/res/drawable-hdpi/sym_keyboard_feedback_delete.png
new file mode 100755
index 0000000..ca76375
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_feedback_delete.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_feedback_ok.png b/core/res/res/drawable-hdpi/sym_keyboard_feedback_ok.png
new file mode 100644
index 0000000..2d144ec
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_feedback_ok.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_feedback_return.png b/core/res/res/drawable-hdpi/sym_keyboard_feedback_return.png
new file mode 100755
index 0000000..ae57299
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_feedback_return.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_feedback_shift.png b/core/res/res/drawable-hdpi/sym_keyboard_feedback_shift.png
new file mode 100755
index 0000000..4db31c8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_feedback_shift.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_feedback_shift_locked.png b/core/res/res/drawable-hdpi/sym_keyboard_feedback_shift_locked.png
new file mode 100755
index 0000000..3fd5659
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_feedback_shift_locked.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_feedback_space.png b/core/res/res/drawable-hdpi/sym_keyboard_feedback_space.png
new file mode 100755
index 0000000..98266ee
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_feedback_space.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_num0_no_plus.png b/core/res/res/drawable-hdpi/sym_keyboard_num0_no_plus.png
new file mode 100644
index 0000000..2aad23c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_num0_no_plus.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_num1.png b/core/res/res/drawable-hdpi/sym_keyboard_num1.png
new file mode 100755
index 0000000..0fc03ef
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_num1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_num2.png b/core/res/res/drawable-hdpi/sym_keyboard_num2.png
new file mode 100755
index 0000000..283560b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_num2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_num3.png b/core/res/res/drawable-hdpi/sym_keyboard_num3.png
new file mode 100755
index 0000000..9a3b329
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_num3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_num4.png b/core/res/res/drawable-hdpi/sym_keyboard_num4.png
new file mode 100755
index 0000000..f13ff1a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_num4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_num5.png b/core/res/res/drawable-hdpi/sym_keyboard_num5.png
new file mode 100755
index 0000000..c251329
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_num5.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_num6.png b/core/res/res/drawable-hdpi/sym_keyboard_num6.png
new file mode 100755
index 0000000..4acba4c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_num6.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_num7.png b/core/res/res/drawable-hdpi/sym_keyboard_num7.png
new file mode 100755
index 0000000..14931c1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_num7.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_num8.png b/core/res/res/drawable-hdpi/sym_keyboard_num8.png
new file mode 100755
index 0000000..d4973fd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_num8.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_num9.png b/core/res/res/drawable-hdpi/sym_keyboard_num9.png
new file mode 100755
index 0000000..49cec66
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_num9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_ok.png b/core/res/res/drawable-hdpi/sym_keyboard_ok.png
new file mode 100644
index 0000000..9105da2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_ok.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_ok_dim.png b/core/res/res/drawable-hdpi/sym_keyboard_ok_dim.png
new file mode 100644
index 0000000..bd419de
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_ok_dim.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_return.png b/core/res/res/drawable-hdpi/sym_keyboard_return.png
new file mode 100755
index 0000000..58505c5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_return.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_shift.png b/core/res/res/drawable-hdpi/sym_keyboard_shift.png
new file mode 100755
index 0000000..8149081
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_shift.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_shift_locked.png b/core/res/res/drawable-hdpi/sym_keyboard_shift_locked.png
new file mode 100755
index 0000000..31ca277
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_shift_locked.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_keyboard_space.png b/core/res/res/drawable-hdpi/sym_keyboard_space.png
new file mode 100755
index 0000000..3e98b30
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_keyboard_space.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal.9.png
new file mode 100644
index 0000000..20f3d50
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal_off.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal_off.9.png
new file mode 100644
index 0000000..d09ce53
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal_off.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal_on.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal_on.9.png
new file mode 100644
index 0000000..a9e008c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal_on.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed.9.png
new file mode 100644
index 0000000..1ed3065
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed_off.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed_off.9.png
new file mode 100644
index 0000000..5710ebf
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed_off.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed_on.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed_on.9.png
new file mode 100644
index 0000000..dd7d89e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed_on.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_trans_normal_off.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_trans_normal_off.9.png
new file mode 100644
index 0000000..77426ef
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_trans_normal_off.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_trans_normal_on.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_trans_normal_on.9.png
new file mode 100644
index 0000000..e4c9bd5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_trans_normal_on.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_trans_pressed_off.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_trans_pressed_off.9.png
new file mode 100644
index 0000000..bb98b01
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_trans_pressed_off.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_keyboard_key_trans_pressed_on.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_trans_pressed_on.9.png
new file mode 100644
index 0000000..3c7dcc80
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_trans_pressed_on.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/password_field_default.9.png b/core/res/res/drawable-mdpi/password_field_default.9.png
new file mode 100644
index 0000000..3193275
--- /dev/null
+++ b/core/res/res/drawable-mdpi/password_field_default.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_delete.png b/core/res/res/drawable-mdpi/sym_keyboard_delete.png
new file mode 100644
index 0000000..43a033ea
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_delete.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_delete_dim.png b/core/res/res/drawable-mdpi/sym_keyboard_delete_dim.png
new file mode 100644
index 0000000..25460d8
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_delete_dim.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_feedback_delete.png b/core/res/res/drawable-mdpi/sym_keyboard_feedback_delete.png
new file mode 100644
index 0000000..1edb10b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_feedback_delete.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_feedback_ok.png b/core/res/res/drawable-mdpi/sym_keyboard_feedback_ok.png
new file mode 100644
index 0000000..3148836
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_feedback_ok.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_feedback_return.png b/core/res/res/drawable-mdpi/sym_keyboard_feedback_return.png
new file mode 100644
index 0000000..03d9c9b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_feedback_return.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_feedback_shift.png b/core/res/res/drawable-mdpi/sym_keyboard_feedback_shift.png
new file mode 100644
index 0000000..97f4661
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_feedback_shift.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_feedback_shift_locked.png b/core/res/res/drawable-mdpi/sym_keyboard_feedback_shift_locked.png
new file mode 100755
index 0000000..7194b30
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_feedback_shift_locked.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_feedback_space.png b/core/res/res/drawable-mdpi/sym_keyboard_feedback_space.png
new file mode 100644
index 0000000..739db68
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_feedback_space.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_num0_no_plus.png b/core/res/res/drawable-mdpi/sym_keyboard_num0_no_plus.png
new file mode 100644
index 0000000..91332b1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_num0_no_plus.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_num1.png b/core/res/res/drawable-mdpi/sym_keyboard_num1.png
new file mode 100644
index 0000000..aaac11b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_num1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_num2.png b/core/res/res/drawable-mdpi/sym_keyboard_num2.png
new file mode 100644
index 0000000..4372eb8
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_num2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_num3.png b/core/res/res/drawable-mdpi/sym_keyboard_num3.png
new file mode 100644
index 0000000..6f54c85
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_num3.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_num4.png b/core/res/res/drawable-mdpi/sym_keyboard_num4.png
new file mode 100644
index 0000000..3e50bb9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_num4.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_num5.png b/core/res/res/drawable-mdpi/sym_keyboard_num5.png
new file mode 100644
index 0000000..c39ef44
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_num5.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_num6.png b/core/res/res/drawable-mdpi/sym_keyboard_num6.png
new file mode 100644
index 0000000..ea88ceb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_num6.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_num7.png b/core/res/res/drawable-mdpi/sym_keyboard_num7.png
new file mode 100644
index 0000000..ce800ba
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_num7.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_num8.png b/core/res/res/drawable-mdpi/sym_keyboard_num8.png
new file mode 100644
index 0000000..1a8ff94
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_num8.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_num9.png b/core/res/res/drawable-mdpi/sym_keyboard_num9.png
new file mode 100644
index 0000000..8b344c0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_num9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_ok.png b/core/res/res/drawable-mdpi/sym_keyboard_ok.png
new file mode 100644
index 0000000..b8b5292
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_ok.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_ok_dim.png b/core/res/res/drawable-mdpi/sym_keyboard_ok_dim.png
new file mode 100644
index 0000000..33ecff5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_ok_dim.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_return.png b/core/res/res/drawable-mdpi/sym_keyboard_return.png
new file mode 100644
index 0000000..17f2574
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_return.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_shift.png b/core/res/res/drawable-mdpi/sym_keyboard_shift.png
new file mode 100644
index 0000000..0566e5a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_shift.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_shift_locked.png b/core/res/res/drawable-mdpi/sym_keyboard_shift_locked.png
new file mode 100755
index 0000000..ccaf05d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_shift_locked.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_keyboard_space.png b/core/res/res/drawable-mdpi/sym_keyboard_space.png
new file mode 100644
index 0000000..4e6273b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_keyboard_space.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_fulltrans.xml b/core/res/res/drawable/btn_keyboard_key_fulltrans.xml
new file mode 100644
index 0000000..cfad6e3
--- /dev/null
+++ b/core/res/res/drawable/btn_keyboard_key_fulltrans.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <!-- Toggle keys. Use checkable/checked state. -->
+
+ <item android:state_checkable="true" android:state_checked="true"
+ android:state_pressed="true"
+ android:drawable="@drawable/btn_keyboard_key_fulltrans_pressed_on" />
+ <item android:state_checkable="true" android:state_pressed="true"
+ android:drawable="@drawable/btn_keyboard_key_fulltrans_pressed_off" />
+ <item android:state_checkable="true" android:state_checked="true"
+ android:drawable="@drawable/btn_keyboard_key_fulltrans_normal_on" />
+ <item android:state_checkable="true"
+ android:drawable="@drawable/btn_keyboard_key_fulltrans_normal_off" />
+
+ <!-- Normal keys -->
+ <item android:state_pressed="true"
+ android:drawable="@drawable/btn_keyboard_key_fulltrans_pressed" />
+ <item android:drawable="@drawable/btn_keyboard_key_fulltrans_normal" />
+
+</selector>
diff --git a/core/res/res/layout/keyguard_screen_password_landscape.xml b/core/res/res/layout/keyguard_screen_password_landscape.xml
index 5bc034b..b089df6 100644
--- a/core/res/res/layout/keyguard_screen_password_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_password_landscape.xml
@@ -16,105 +16,68 @@
** limitations under the License.
*/
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@android:color/background_dark">
-
- <!-- displays dots as user enters pin -->
- <LinearLayout android:id="@+id/pinDisplayGroup"
- android:orientation="horizontal"
- android:layout_centerInParent="true"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:addStatesFromChildren="true"
- android:gravity="center_vertical"
- android:baselineAligned="false"
- android:paddingRight="0dip"
- android:layout_marginRight="30dip"
- android:layout_marginLeft="30dip"
- android:layout_marginTop="6dip"
- android:background="@android:drawable/edit_text">
-
- <EditText android:id="@+id/pinDisplay"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="fill_parent"
- android:maxLines="1"
- android:background="@null"
- android:textSize="32sp"
- android:inputType="textPassword"
- />
-
- <ImageButton android:id="@+id/backspace"
- android:src="@android:drawable/ic_input_delete"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:layout_marginTop="2dip"
- android:layout_marginRight="2dip"
- android:layout_marginBottom="2dip"
- android:gravity="center"
- />
-
- </LinearLayout>
-
- <!-- header text ('Enter Pin Code') -->
- <TextView android:id="@+id/headerText"
- android:layout_above="@id/pinDisplayGroup"
- android:layout_centerHorizontal="true"
- android:layout_marginBottom="30dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="24sp"
- />
+ android:background="#70000000"
+ android:gravity="center_horizontal">
<LinearLayout
- android:orientation="horizontal"
- android:layout_alignParentBottom="true"
- android:layout_width="fill_parent"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="8dip"
- android:layout_marginLeft="8dip"
- android:layout_marginRight="8dip">
-
- <Button android:id="@+id/ok"
- android:text="@android:string/ok"
- android:layout_alignParentBottom="true"
+ android:orientation="horizontal">
+ <!-- "Enter PIN(Password) to unlock" -->
+ <TextView android:id="@+id/enter_password_label"
android:layout_width="0dip"
android:layout_height="wrap_content"
- android:layout_weight="1.0"
- android:layout_marginBottom="8dip"
- android:layout_marginRight="8dip"
- android:textSize="18sp"
- />
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ android:layout_marginRight="6dip"
+ android:layout_marginLeft="6dip"
+ android:layout_marginTop="10dip"
+ android:layout_marginBottom="10dip"
+ android:gravity="center"
+ android:ellipsize="marquee"
+ android:text="@android:string/keyguard_password_enter_password_code"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ />
- <Button android:id="@+id/emergencyCall"
- android:text="@android:string/lockscreen_emergency_call"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
+ <!-- Password entry field -->
+ <EditText android:id="@+id/passwordEntry"
android:layout_width="0dip"
android:layout_height="wrap_content"
- android:layout_weight="1.0"
- android:layout_marginBottom="8dip"
- android:layout_marginLeft="8dip"
- android:textSize="18sp"
- android:drawableLeft="@drawable/ic_emergency"
- android:drawablePadding="8dip"
+ android:layout_weight="1"
+ android:singleLine="true"
+ android:textStyle="bold"
+ android:inputType="textPassword"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:textSize="32sp"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:background="@drawable/password_field_default"
+ android:textColor="#ffffffff"
/>
</LinearLayout>
- <!-- Not currently visible on this screen -->
- <TextView
- android:id="@+id/carrier"
- android:layout_width="wrap_content"
+ <!-- Alphanumeric keyboard -->
+ <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
+ android:layout_alignParentBottom="true"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_marginTop="6dip"
- android:layout_alignParentRight="true"
- android:layout_marginRight="8dip"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:visibility="gone"
+ android:background="#00000000"
+ android:keyBackground="@drawable/btn_keyboard_key_fulltrans"
/>
-</RelativeLayout>
+ <!-- emergency call button -->
+ <Button
+ android:id="@+id/emergencyCall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:drawableLeft="@drawable/ic_emergency"
+ android:drawablePadding="8dip"
+ android:text="@string/lockscreen_emergency_call"
+ style="@style/Widget.Button.Transparent"
+ />
+
+</LinearLayout>
diff --git a/core/res/res/layout/keyguard_screen_password_portrait.xml b/core/res/res/layout/keyguard_screen_password_portrait.xml
index a7814af..9ee8781 100644
--- a/core/res/res/layout/keyguard_screen_password_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_password_portrait.xml
@@ -17,142 +17,77 @@
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:orientation="vertical"
android:background="#70000000"
android:gravity="center_horizontal">
- <LinearLayout android:id="@+id/topDisplayGroup"
- android:layout_width="fill_parent"
+ <!-- "Enter PIN(Password) to unlock" -->
+ <TextView android:id="@+id/enter_password_label"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
-
- <com.android.internal.widget.DigitalClock android:id="@+id/time"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="6dip"
- android:layout_marginLeft="6dip"
- android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true">
-
- <TextView android:id="@+id/timeDisplay"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="bottom"
- android:singleLine="true"
- android:ellipsize="none"
- android:textSize="56sp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:shadowColor="#C0000000"
- android:shadowDx="0"
- android:shadowDy="0"
- android:shadowRadius="3.0"
- android:layout_marginBottom="6dip"
- />
-
- <TextView android:id="@+id/am_pm"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:gravity="bottom"
- android:singleLine="true"
- android:ellipsize="none"
- android:textSize="18sp"
- android:layout_marginLeft="4dip"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:shadowColor="#C0000000"
- android:shadowDx="0"
- android:shadowDy="0"
- android:shadowRadius="3.0"
- />
-
- </com.android.internal.widget.DigitalClock>
-
- <TextView android:id="@+id/carrier"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_marginTop="6dip"
- android:layout_alignParentRight="true"
- android:layout_marginRight="8dip"
- android:textAppearance="?android:attr/textAppearanceMedium"
- />
-
- </RelativeLayout>
-
- <!-- password entry -->
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_marginRight="6dip"
- android:layout_marginLeft="6dip"
- android:gravity="center_vertical"
- android:hint="@android:string/keyguard_password_enter_password_code"
- android:background="@android:drawable/edit_text">
-
- <!-- displays dots as user enters pin -->
- <TextView android:id="@+id/pinDisplay"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:maxLines="1"
- android:textAppearance="?android:attr/textAppearanceLargeInverse"
- android:textStyle="bold"
- android:inputType="textPassword"
- />
-
- <ImageButton android:id="@+id/backspace"
- android:src="@android:drawable/ic_input_delete"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="-3dip"
- android:layout_marginBottom="-3dip"
- />
- </LinearLayout>
-
- </LinearLayout>
-
- <include
- android:id="@+id/keyPad"
- layout="@android:layout/twelve_key_entry"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/topDisplayGroup"
+ android:orientation="horizontal"
+ android:layout_marginRight="6dip"
+ android:layout_marginLeft="6dip"
android:layout_marginTop="10dip"
+ android:layout_marginBottom="10dip"
+ android:gravity="center"
+ android:text="@android:string/keyguard_password_enter_password_code"
+ android:textAppearance="?android:attr/textAppearanceLarge"
/>
- <!-- spacer below keypad -->
+ <!-- spacer above text entry field -->
<View
android:id="@+id/spacerBottom"
android:layout_width="fill_parent"
android:layout_height="1dip"
android:layout_marginTop="6dip"
- android:layout_above="@id/emergencyCall"
android:background="@android:drawable/divider_horizontal_dark"
/>
- <!-- The emergency button should take the rest of the space and be centered vertically -->
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
+ <!-- Password entry field -->
+ <EditText android:id="@+id/passwordEntry"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textStyle="bold"
+ android:inputType="textPassword"
android:gravity="center"
- android:orientation="vertical">
+ android:layout_gravity="center"
+ android:textSize="32sp"
+ android:layout_marginTop="15dip"
+ android:layout_marginLeft="30dip"
+ android:layout_marginRight="30dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:background="@drawable/password_field_default"
+ android:textColor="#ffffffff"
+ />
- <!-- emergency call button -->
- <Button
- android:id="@+id/emergencyCall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:drawableLeft="@android:drawable/ic_emergency"
- android:drawablePadding="8dip"
- android:text="@android:string/lockscreen_emergency_call"
- />
- </LinearLayout>
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1" />
+ <!-- Alphanumeric keyboard -->
+ <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
+ android:layout_alignParentBottom="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="#00000000"
+ android:keyBackground="@drawable/btn_keyboard_key_fulltrans"
+ />
+
+ <!-- emergency call button -->
+ <Button
+ android:id="@+id/emergencyCall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:drawableLeft="@drawable/ic_emergency"
+ android:drawablePadding="8dip"
+ android:layout_marginTop="20dip"
+ android:layout_marginBottom="20dip"
+ android:text="@string/lockscreen_emergency_call"
+ style="@style/Widget.Button.Transparent"
+ />
</LinearLayout>
diff --git a/core/res/res/layout/password_keyboard_input.xml b/core/res/res/layout/password_keyboard_input.xml
new file mode 100755
index 0000000..e40b69e
--- /dev/null
+++ b/core/res/res/layout/password_keyboard_input.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<com.android.passwordunlockdemo.LatinKeyboardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/keyboardView"
+ android:layout_alignParentBottom="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="#00000000"
+ android:keyBackground="@drawable/btn_keyboard_key_fulltrans"
+ />
diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml
new file mode 100644
index 0000000..647a562
--- /dev/null
+++ b/core/res/res/values-land/dimens.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<resources>
+ <dimen name="password_keyboard_key_height">47dip</dimen>
+ <dimen name="password_keyboard_spacebar_vertical_correction">2dip</dimen>
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6a3538d..5cea28db 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -4,16 +4,16 @@
**
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** 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
+** 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
+** 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.
*/
-->
@@ -34,4 +34,8 @@
<dimen name="fastscroll_thumb_width">64dp</dimen>
<!-- Height of the fastscroll thumb -->
<dimen name="fastscroll_thumb_height">52dp</dimen>
+ <!-- Default height of a key in the password keyboard -->
+ <dimen name="password_keyboard_key_height">56dip</dimen>
+ <!-- Default correction for the space key in the password keyboard -->
+ <dimen name="password_keyboard_spacebar_vertical_correction">4dip</dimen>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4df570c..89cbd08 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1536,6 +1536,14 @@
<!-- Displayed on lock screen's right tab - turn sound off -->
<string name="lockscreen_sound_off_label">Sound off</string>
+ <!-- Password keyboard strings. Used by LockScreen and Settings --><skip />
+ <!-- Label for "switch to symbols" key. Must be short to fit on key! -->
+ <string name="password_keyboard_label_symbol_key">\?123</string>
+ <!-- Label for "switch to alphabetic" key. Must be short to fit on key! -->
+ <string name="password_keyboard_label_alpha_key">ABC</string>
+ <!-- Label for ALT modifier key. Must be short to fit on key! -->
+ <string name="password_keyboard_label_alt_key">ALT</string>
+
<!-- A format string for 12-hour time of day, just the hour, not the minute, with lower-case "am" or "pm" (example: "3pm"). -->
<string name="hour_ampm">"<xliff:g id="hour" example="3">%-l</xliff:g><xliff:g id="ampm" example="pm">%P</xliff:g>"</string>
diff --git a/core/res/res/xml-land/password_kbd_qwerty.xml b/core/res/res/xml-land/password_kbd_qwerty.xml
new file mode 100755
index 0000000..a3d4e88
--- /dev/null
+++ b/core/res/res/xml-land/password_kbd_qwerty.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/password_keyboard_key_height"
+ >
+
+ <Row>
+ <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
+ <Key android:codes="119" android:keyLabel="w"/>
+ <Key android:codes="101" android:keyLabel="e"/>
+ <Key android:codes="114" android:keyLabel="r"/>
+ <Key android:codes="116" android:keyLabel="t"/>
+ <Key android:codes="121" android:keyLabel="y"/>
+ <Key android:codes="117" android:keyLabel="u"/>
+ <Key android:codes="105" android:keyLabel="i"/>
+ <Key android:codes="111" android:keyLabel="o"/>
+ <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="97" android:keyLabel="a" android:horizontalGap="5%p"
+ android:keyEdgeFlags="left"/>
+ <Key android:codes="115" android:keyLabel="s"/>
+ <Key android:codes="100" android:keyLabel="d"/>
+ <Key android:codes="102" android:keyLabel="f"/>
+ <Key android:codes="103" android:keyLabel="g"/>
+ <Key android:codes="104" android:keyLabel="h"/>
+ <Key android:codes="106" android:keyLabel="j"/>
+ <Key android:codes="107" android:keyLabel="k"/>
+ <Key android:codes="108" android:keyLabel="l" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift"
+ android:keyWidth="15%p" android:isModifier="true"
+ android:iconPreview="@drawable/sym_keyboard_feedback_shift"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:codes="122" android:keyLabel="z"/>
+ <Key android:codes="120" android:keyLabel="x"/>
+ <Key android:codes="99" android:keyLabel="c"/>
+ <Key android:codes="118" android:keyLabel="v"/>
+ <Key android:codes="98" android:keyLabel="b"/>
+ <Key android:codes="110" android:keyLabel="n"/>
+ <Key android:codes="109" android:keyLabel="m"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="15%p" android:keyEdgeFlags="right"
+ android:iconPreview="@drawable/sym_keyboard_feedback_delete"
+ android:isRepeatable="true"/>
+ </Row>
+
+ <Row android:keyboardMode="@+id/mode_normal" android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/password_keyboard_label_symbol_key"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="," />
+ <Key android:keyLabel="-" />
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
+ <Key android:keyLabel="=" />
+ <Key android:codes="46" android:keyLabel="."
+ android:keyWidth="10%p"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:iconPreview="@drawable/sym_keyboard_feedback_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+
+</Keyboard>
+
diff --git a/core/res/res/xml-land/password_kbd_qwerty_shifted.xml b/core/res/res/xml-land/password_kbd_qwerty_shifted.xml
new file mode 100755
index 0000000..2285d91
--- /dev/null
+++ b/core/res/res/xml-land/password_kbd_qwerty_shifted.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/password_keyboard_key_height"
+ >
+
+ <Row>
+ <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
+ <Key android:codes="119" android:keyLabel="w"/>
+ <Key android:codes="101" android:keyLabel="e"/>
+ <Key android:codes="114" android:keyLabel="r"/>
+ <Key android:codes="116" android:keyLabel="t"/>
+ <Key android:codes="121" android:keyLabel="y"/>
+ <Key android:codes="117" android:keyLabel="u"/>
+ <Key android:codes="105" android:keyLabel="i"/>
+ <Key android:codes="111" android:keyLabel="o"/>
+ <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="97" android:keyLabel="a" android:horizontalGap="5%p"
+ android:keyEdgeFlags="left"/>
+ <Key android:codes="115" android:keyLabel="s"/>
+ <Key android:codes="100" android:keyLabel="d"/>
+ <Key android:codes="102" android:keyLabel="f"/>
+ <Key android:codes="103" android:keyLabel="g"/>
+ <Key android:codes="104" android:keyLabel="h"/>
+ <Key android:codes="106" android:keyLabel="j"/>
+ <Key android:codes="107" android:keyLabel="k"/>
+ <Key android:codes="108" android:keyLabel="l" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift"
+ android:keyWidth="15%p" android:isModifier="true"
+ android:iconPreview="@drawable/sym_keyboard_feedback_shift"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:codes="122" android:keyLabel="z"/>
+ <Key android:codes="120" android:keyLabel="x"/>
+ <Key android:codes="99" android:keyLabel="c"/>
+ <Key android:codes="118" android:keyLabel="v"/>
+ <Key android:codes="98" android:keyLabel="b"/>
+ <Key android:codes="110" android:keyLabel="n"/>
+ <Key android:codes="109" android:keyLabel="m"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="15%p" android:keyEdgeFlags="right"
+ android:iconPreview="@drawable/sym_keyboard_feedback_delete"
+ android:isRepeatable="true"/>
+ </Row>
+
+ <Row android:keyboardMode="@+id/mode_normal" android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/password_keyboard_label_symbol_key"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="," />
+ <Key android:keyLabel="_" />
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
+ <Key android:keyLabel="+" />
+ <Key android:codes="46" android:keyLabel="."/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:iconPreview="@drawable/sym_keyboard_feedback_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+
+</Keyboard>
+
diff --git a/core/res/res/xml-mdpi/password_kbd_qwerty.xml b/core/res/res/xml-mdpi/password_kbd_qwerty.xml
new file mode 100755
index 0000000..a3d4e88
--- /dev/null
+++ b/core/res/res/xml-mdpi/password_kbd_qwerty.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/password_keyboard_key_height"
+ >
+
+ <Row>
+ <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
+ <Key android:codes="119" android:keyLabel="w"/>
+ <Key android:codes="101" android:keyLabel="e"/>
+ <Key android:codes="114" android:keyLabel="r"/>
+ <Key android:codes="116" android:keyLabel="t"/>
+ <Key android:codes="121" android:keyLabel="y"/>
+ <Key android:codes="117" android:keyLabel="u"/>
+ <Key android:codes="105" android:keyLabel="i"/>
+ <Key android:codes="111" android:keyLabel="o"/>
+ <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="97" android:keyLabel="a" android:horizontalGap="5%p"
+ android:keyEdgeFlags="left"/>
+ <Key android:codes="115" android:keyLabel="s"/>
+ <Key android:codes="100" android:keyLabel="d"/>
+ <Key android:codes="102" android:keyLabel="f"/>
+ <Key android:codes="103" android:keyLabel="g"/>
+ <Key android:codes="104" android:keyLabel="h"/>
+ <Key android:codes="106" android:keyLabel="j"/>
+ <Key android:codes="107" android:keyLabel="k"/>
+ <Key android:codes="108" android:keyLabel="l" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift"
+ android:keyWidth="15%p" android:isModifier="true"
+ android:iconPreview="@drawable/sym_keyboard_feedback_shift"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:codes="122" android:keyLabel="z"/>
+ <Key android:codes="120" android:keyLabel="x"/>
+ <Key android:codes="99" android:keyLabel="c"/>
+ <Key android:codes="118" android:keyLabel="v"/>
+ <Key android:codes="98" android:keyLabel="b"/>
+ <Key android:codes="110" android:keyLabel="n"/>
+ <Key android:codes="109" android:keyLabel="m"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="15%p" android:keyEdgeFlags="right"
+ android:iconPreview="@drawable/sym_keyboard_feedback_delete"
+ android:isRepeatable="true"/>
+ </Row>
+
+ <Row android:keyboardMode="@+id/mode_normal" android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/password_keyboard_label_symbol_key"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="," />
+ <Key android:keyLabel="-" />
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
+ <Key android:keyLabel="=" />
+ <Key android:codes="46" android:keyLabel="."
+ android:keyWidth="10%p"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:iconPreview="@drawable/sym_keyboard_feedback_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+
+</Keyboard>
+
diff --git a/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml b/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml
new file mode 100755
index 0000000..2285d91
--- /dev/null
+++ b/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/password_keyboard_key_height"
+ >
+
+ <Row>
+ <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
+ <Key android:codes="119" android:keyLabel="w"/>
+ <Key android:codes="101" android:keyLabel="e"/>
+ <Key android:codes="114" android:keyLabel="r"/>
+ <Key android:codes="116" android:keyLabel="t"/>
+ <Key android:codes="121" android:keyLabel="y"/>
+ <Key android:codes="117" android:keyLabel="u"/>
+ <Key android:codes="105" android:keyLabel="i"/>
+ <Key android:codes="111" android:keyLabel="o"/>
+ <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="97" android:keyLabel="a" android:horizontalGap="5%p"
+ android:keyEdgeFlags="left"/>
+ <Key android:codes="115" android:keyLabel="s"/>
+ <Key android:codes="100" android:keyLabel="d"/>
+ <Key android:codes="102" android:keyLabel="f"/>
+ <Key android:codes="103" android:keyLabel="g"/>
+ <Key android:codes="104" android:keyLabel="h"/>
+ <Key android:codes="106" android:keyLabel="j"/>
+ <Key android:codes="107" android:keyLabel="k"/>
+ <Key android:codes="108" android:keyLabel="l" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift"
+ android:keyWidth="15%p" android:isModifier="true"
+ android:iconPreview="@drawable/sym_keyboard_feedback_shift"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:codes="122" android:keyLabel="z"/>
+ <Key android:codes="120" android:keyLabel="x"/>
+ <Key android:codes="99" android:keyLabel="c"/>
+ <Key android:codes="118" android:keyLabel="v"/>
+ <Key android:codes="98" android:keyLabel="b"/>
+ <Key android:codes="110" android:keyLabel="n"/>
+ <Key android:codes="109" android:keyLabel="m"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="15%p" android:keyEdgeFlags="right"
+ android:iconPreview="@drawable/sym_keyboard_feedback_delete"
+ android:isRepeatable="true"/>
+ </Row>
+
+ <Row android:keyboardMode="@+id/mode_normal" android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/password_keyboard_label_symbol_key"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="," />
+ <Key android:keyLabel="_" />
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
+ <Key android:keyLabel="+" />
+ <Key android:codes="46" android:keyLabel="."/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:iconPreview="@drawable/sym_keyboard_feedback_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+
+</Keyboard>
+
diff --git a/core/res/res/xml/password_kbd_extension.xml b/core/res/res/xml/password_kbd_extension.xml
new file mode 100755
index 0000000..354594e
--- /dev/null
+++ b/core/res/res/xml/password_kbd_extension.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/password_keyboard_key_height"
+ >
+
+ <Row android:rowEdgeFlags="top">
+ <Key android:keyLabel="!" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="\@"/>
+ <Key android:keyLabel="\#"/>
+ <Key android:keyLabel="&"/>
+ <Key android:keyLabel="-"/>
+ <Key android:keyLabel="\'"/>
+ <Key android:keyLabel=":"/>
+ <Key android:keyLabel="""/>
+ <Key android:keyLabel="/"/>
+ <Key android:keyLabel="\?" android:keyEdgeFlags="right"
+ />
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom">
+ <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"
+ />
+ <Key android:codes="50" android:keyLabel="2"
+ />
+ <Key android:codes="51" android:keyLabel="3"
+ />
+ <Key android:codes="52" android:keyLabel="4"
+ />
+ <Key android:codes="53" android:keyLabel="5"
+ />
+ <Key android:codes="54" android:keyLabel="6"/>
+ <Key android:codes="55" android:keyLabel="7"
+ />
+ <Key android:codes="56" android:keyLabel="8"/>
+ <Key android:codes="57" android:keyLabel="9"/>
+ <Key android:codes="48" android:keyLabel="0"
+ android:keyEdgeFlags="right"/>
+ </Row>
+</Keyboard>
diff --git a/core/res/res/xml/password_kbd_numeric.xml b/core/res/res/xml/password_kbd_numeric.xml
new file mode 100755
index 0000000..e3f1612
--- /dev/null
+++ b/core/res/res/xml/password_kbd_numeric.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="33.33%p"
+ android:horizontalGap="2px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/password_keyboard_key_height"
+ >
+
+ <Row>
+ <Key android:codes="49" android:keyIcon="@drawable/sym_keyboard_num1" android:keyEdgeFlags="left"/>
+ <Key android:codes="50" android:keyIcon="@drawable/sym_keyboard_num2"/>
+ <Key android:codes="51" android:keyIcon="@drawable/sym_keyboard_num3"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="52" android:keyIcon="@drawable/sym_keyboard_num4" android:keyEdgeFlags="left"/>
+ <Key android:codes="53" android:keyIcon="@drawable/sym_keyboard_num5"/>
+ <Key android:codes="54" android:keyIcon="@drawable/sym_keyboard_num6"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="55" android:keyIcon="@drawable/sym_keyboard_num7" android:keyEdgeFlags="left"/>
+ <Key android:codes="56" android:keyIcon="@drawable/sym_keyboard_num8"/>
+ <Key android:codes="57" android:keyIcon="@drawable/sym_keyboard_num9"/>
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom">
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_ok"/>
+ <Key android:codes="48" android:keyIcon="@drawable/sym_keyboard_num0_no_plus"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:iconPreview="@drawable/sym_keyboard_feedback_delete"
+ android:isRepeatable="true" android:keyEdgeFlags="right"/>
+ </Row>
+
+</Keyboard>
diff --git a/core/res/res/xml/password_kbd_popup_template.xml b/core/res/res/xml/password_kbd_popup_template.xml
new file mode 100644
index 0000000..5ddfd3e
--- /dev/null
+++ b/core/res/res/xml/password_kbd_popup_template.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/password_keyboard_key_height"
+ >
+</Keyboard>
diff --git a/core/res/res/xml/password_kbd_qwerty.xml b/core/res/res/xml/password_kbd_qwerty.xml
new file mode 100755
index 0000000..d4a454b
--- /dev/null
+++ b/core/res/res/xml/password_kbd_qwerty.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/password_keyboard_key_height"
+ >
+
+ <Row android:rowEdgeFlags="top">
+ <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/>
+ <Key android:codes="50" android:keyLabel="2"/>
+ <Key android:codes="51" android:keyLabel="3"/>
+ <Key android:codes="52" android:keyLabel="4"/>
+ <Key android:codes="53" android:keyLabel="5"/>
+ <Key android:codes="54" android:keyLabel="6"/>
+ <Key android:codes="55" android:keyLabel="7"/>
+ <Key android:codes="56" android:keyLabel="8"/>
+ <Key android:codes="57" android:keyLabel="9"/>
+ <Key android:codes="48" android:keyLabel="0" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
+ <Key android:codes="119" android:keyLabel="w"/>
+ <Key android:codes="101" android:keyLabel="e"/>
+ <Key android:codes="114" android:keyLabel="r"/>
+ <Key android:codes="116" android:keyLabel="t"/>
+ <Key android:codes="121" android:keyLabel="y"/>
+ <Key android:codes="117" android:keyLabel="u"/>
+ <Key android:codes="105" android:keyLabel="i"/>
+ <Key android:codes="111" android:keyLabel="o"/>
+ <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="97" android:keyLabel="a" android:horizontalGap="5%p"
+ android:keyEdgeFlags="left"/>
+ <Key android:codes="115" android:keyLabel="s"/>
+ <Key android:codes="100" android:keyLabel="d"/>
+ <Key android:codes="102" android:keyLabel="f"/>
+ <Key android:codes="103" android:keyLabel="g"/>
+ <Key android:codes="104" android:keyLabel="h"/>
+ <Key android:codes="106" android:keyLabel="j"/>
+ <Key android:codes="107" android:keyLabel="k"/>
+ <Key android:codes="108" android:keyLabel="l" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift"
+ android:keyWidth="15%p" android:isModifier="true"
+ android:iconPreview="@drawable/sym_keyboard_feedback_shift"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:codes="122" android:keyLabel="z"/>
+ <Key android:codes="120" android:keyLabel="x"/>
+ <Key android:codes="99" android:keyLabel="c"/>
+ <Key android:codes="118" android:keyLabel="v"/>
+ <Key android:codes="98" android:keyLabel="b"/>
+ <Key android:codes="110" android:keyLabel="n"/>
+ <Key android:codes="109" android:keyLabel="m"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="15%p" android:keyEdgeFlags="right"
+ android:iconPreview="@drawable/sym_keyboard_feedback_delete"
+ android:isRepeatable="true"/>
+ </Row>
+
+ <Row android:keyboardMode="@+id/mode_normal" android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/password_keyboard_label_symbol_key"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="," />
+ <Key android:keyLabel="-" />
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
+ <Key android:keyLabel="=" />
+ <Key android:codes="46" android:keyLabel="."
+ android:keyWidth="10%p"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_ok"
+ android:iconPreview="@drawable/sym_keyboard_feedback_ok"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+
+</Keyboard>
+
diff --git a/core/res/res/xml/password_kbd_qwerty_shifted.xml b/core/res/res/xml/password_kbd_qwerty_shifted.xml
new file mode 100755
index 0000000..f341d9e
--- /dev/null
+++ b/core/res/res/xml/password_kbd_qwerty_shifted.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/password_keyboard_key_height"
+ >
+
+ <Row android:rowEdgeFlags="top">
+ <Key android:codes="64" android:keyLabel="\@" android:keyEdgeFlags="left"/>
+ <Key android:codes="35" android:keyLabel="\#"/>
+ <Key android:codes="36" android:keyLabel="$"/>
+ <Key android:codes="37" android:keyLabel="%"/>
+ <Key android:codes="38" android:keyLabel="&"/>
+ <Key android:codes="42" android:keyLabel="*"/>
+ <Key android:codes="45" android:keyLabel="-"/>
+ <Key android:keyLabel="+"/>
+ <Key android:codes="40" android:keyLabel="("/>
+ <Key android:codes="41" android:keyLabel=")" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
+ <Key android:codes="119" android:keyLabel="w"/>
+ <Key android:codes="101" android:keyLabel="e"/>
+ <Key android:codes="114" android:keyLabel="r"/>
+ <Key android:codes="116" android:keyLabel="t"/>
+ <Key android:codes="121" android:keyLabel="y"/>
+ <Key android:codes="117" android:keyLabel="u"/>
+ <Key android:codes="105" android:keyLabel="i"/>
+ <Key android:codes="111" android:keyLabel="o"/>
+ <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="97" android:keyLabel="a" android:horizontalGap="5%p"
+ android:keyEdgeFlags="left"/>
+ <Key android:codes="115" android:keyLabel="s"/>
+ <Key android:codes="100" android:keyLabel="d"/>
+ <Key android:codes="102" android:keyLabel="f"/>
+ <Key android:codes="103" android:keyLabel="g"/>
+ <Key android:codes="104" android:keyLabel="h"/>
+ <Key android:codes="106" android:keyLabel="j"/>
+ <Key android:codes="107" android:keyLabel="k"/>
+ <Key android:codes="108" android:keyLabel="l" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift"
+ android:keyWidth="15%p" android:isModifier="true"
+ android:iconPreview="@drawable/sym_keyboard_feedback_shift"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:codes="122" android:keyLabel="z"/>
+ <Key android:codes="120" android:keyLabel="x"/>
+ <Key android:codes="99" android:keyLabel="c"/>
+ <Key android:codes="118" android:keyLabel="v"/>
+ <Key android:codes="98" android:keyLabel="b"/>
+ <Key android:codes="110" android:keyLabel="n"/>
+ <Key android:codes="109" android:keyLabel="m"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="15%p" android:keyEdgeFlags="right"
+ android:iconPreview="@drawable/sym_keyboard_feedback_delete"
+ android:isRepeatable="true"/>
+ </Row>
+
+ <Row android:keyboardMode="@+id/mode_normal" android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/password_keyboard_label_symbol_key"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="," />
+ <Key android:keyLabel="_" />
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:keyWidth="20%p" android:isRepeatable="true"/>
+ <Key android:keyLabel="+" />
+ <Key android:codes="46" android:keyLabel="."/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_ok"
+ android:iconPreview="@drawable/sym_keyboard_feedback_ok"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+
+</Keyboard>
+
diff --git a/core/res/res/xml/password_kbd_symbols.xml b/core/res/res/xml/password_kbd_symbols.xml
new file mode 100755
index 0000000..c97e6ae
--- /dev/null
+++ b/core/res/res/xml/password_kbd_symbols.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/password_keyboard_key_height"
+ >
+
+ <Row>
+ <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/>
+ <Key android:codes="50" android:keyLabel="2"/>
+ <Key android:codes="51" android:keyLabel="3"/>
+ <Key android:codes="52" android:keyLabel="4"/>
+ <Key android:codes="53" android:keyLabel="5"/>
+ <Key android:codes="54" android:keyLabel="6"/>
+ <Key android:codes="55" android:keyLabel="7"/>
+ <Key android:codes="56" android:keyLabel="8"/>
+ <Key android:codes="57" android:keyLabel="9"/>
+ <Key android:codes="48" android:keyLabel="0" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="64" android:keyLabel="\@" android:keyEdgeFlags="left"/>
+ <Key android:codes="35" android:keyLabel="\#"/>
+ <Key android:codes="36" android:keyLabel="$"/>
+ <Key android:codes="37" android:keyLabel="%"/>
+ <Key android:codes="38" android:keyLabel="&"/>
+ <Key android:codes="42" android:keyLabel="*"/>
+ <Key android:codes="45" android:keyLabel="-"/>
+ <Key android:keyLabel="+"/>
+ <Key android:codes="40" android:keyLabel="("
+ android:popupKeyboard="@xml/password_kbd_popup_template"
+ android:popupCharacters="[{<"
+ />
+ <Key android:codes="41" android:keyLabel=")" android:keyEdgeFlags="right"
+ android:popupKeyboard="@xml/password_kbd_popup_template"
+ android:popupCharacters="]}>"
+ />
+ </Row>
+
+ <Row>
+ <Key android:codes="-1" android:keyLabel="@string/password_keyboard_label_alt_key"
+ android:keyWidth="15%p" android:isModifier="true"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:codes="33" android:keyLabel="!"/>
+ <Key android:codes="34" android:keyLabel="""/>
+ <Key android:codes="39" android:keyLabel="\'"/>
+ <Key android:codes="58" android:keyLabel=":"/>
+ <Key android:codes="59" android:keyLabel=";"/>
+ <Key android:codes="47" android:keyLabel="/" />
+ <Key android:codes="63" android:keyLabel="\?"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="15%p" android:keyEdgeFlags="right"
+ android:iconPreview="@drawable/sym_keyboard_feedback_delete"
+ android:isRepeatable="true"/>
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/password_keyboard_label_alpha_key"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="," android:keyWidth="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:keyWidth="40%p"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:isRepeatable="true"/>
+ <Key android:keyLabel="." android:keyWidth="10%p" />
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_ok"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"
+ android:iconPreview="@drawable/sym_keyboard_feedback_ok"
+ />
+ </Row>
+</Keyboard>
diff --git a/core/res/res/xml/password_kbd_symbols_shift.xml b/core/res/res/xml/password_kbd_symbols_shift.xml
new file mode 100755
index 0000000..97ec3c5f
--- /dev/null
+++ b/core/res/res/xml/password_kbd_symbols_shift.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/password_keyboard_key_height"
+ >
+
+ <Row>
+ <Key android:keyLabel="~" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="`"/>
+ <Key android:keyLabel="|"/>
+ <Key android:keyLabel="•"/>
+ <Key android:keyLabel="√"/>
+ <Key android:keyLabel="π"/>
+ <Key android:keyLabel="÷"/>
+ <Key android:keyLabel="×"/>
+ <Key android:keyLabel="{"/>
+ <Key android:keyLabel="}" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:keyLabel="¥" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="£"/>
+ <Key android:keyLabel="¢"/>
+ <Key android:keyLabel="€"/>
+ <Key android:keyLabel="°"/>
+ <Key android:keyLabel="^"/>
+ <Key android:keyLabel="_"/>
+ <Key android:keyLabel="="/>
+ <Key android:keyLabel="["/>
+ <Key android:keyLabel="]" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="-1" android:keyLabel="@string/password_keyboard_label_alt_key"
+ android:keyWidth="15%p" android:isModifier="true"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="™"/>
+ <Key android:keyLabel="®"/>
+ <Key android:keyLabel="©"/>
+ <Key android:keyLabel="¶"/>
+ <Key android:keyLabel="\\"/>
+ <Key android:keyLabel="<"/>
+ <Key android:keyLabel=">"/>
+ <Key android:codes="-5"
+ android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="15%p" android:keyEdgeFlags="right"
+ android:iconPreview="@drawable/sym_keyboard_feedback_delete"
+ android:isRepeatable="true"
+ />
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom">
+ <Key android:codes="-2" android:keyLabel="@string/password_keyboard_label_alpha_key"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:keyLabel="„" android:keyWidth="10%p" />
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:keyWidth="40%p"
+ android:iconPreview="@drawable/sym_keyboard_feedback_space"
+ android:isRepeatable="true"/>
+ <Key android:keyLabel="…" android:keyWidth="10%p" />
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_ok"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"
+ android:iconPreview="@drawable/sym_keyboard_feedback_ok"
+ />
+ </Row>
+</Keyboard>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 8d7e187..6bc6f2e 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -74,6 +74,10 @@
<uses-permission android:name="android.permission.ACCESSIBILITY_EVENT_TRANSITION_TYPES" />
<uses-permission android:name="android.permission.ACCESSIBILITY_EVENT_NOTIFICATION_TYPES" />
+ <!-- package manager test permissions -->
+ <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+ <uses-permission android:name="android.permission.DELETE_PACKAGES" />
+
<application android:theme="@style/Theme">
<uses-library android:name="android.test.runner" />
<activity android:name="StubTestBrowserActivity" android:label="Stubbed Test Browser">
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteDebugTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteDebugTest.java
deleted file mode 100644
index ea807bd..0000000
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteDebugTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.database.sqlite;
-
-import junit.framework.TestCase;
-
-/**
- * Tests for the SQLiteDebug
- */
-public class SQLiteDebugTest extends TestCase {
- private static final String TEST_DB = "test.db";
-
- public void testCaptureSql() {
- String rslt = SQLiteDebug.captureSql(TEST_DB, "select * from t1 where a=? and b=1",
- new Object[] {"blah"});
- String expectedVal = "select * from t1 where a='blah' and b=1";
- assertTrue(rslt.equals("captured_sql|" + TEST_DB + "|" + expectedVal));
-
- rslt = SQLiteDebug.captureSql(TEST_DB, "select * from t1 where a=?",
- new Object[] {"blah"});
- expectedVal = "select * from t1 where a='blah'";
- assertTrue(rslt.equals("captured_sql|" + TEST_DB + "|" + expectedVal));
-
- rslt = SQLiteDebug.captureSql(TEST_DB, "select * from t1 where a=1",
- new Object[] {"blah"});
- assertTrue(rslt.startsWith("too many bindArgs provided."));
-
- rslt = SQLiteDebug.captureSql(TEST_DB, "update t1 set a=? where b=?",
- new Object[] {"blah", "foo"});
- expectedVal = "update t1 set a='blah' where b='foo'";
- assertTrue(rslt.equals("captured_sql|" + TEST_DB + "|" + expectedVal));
- }
-}
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 113c452..022b849 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -54,6 +54,7 @@
METADATA_KEY_VIDEO_WIDTH = 20,
METADATA_KEY_WRITER = 21,
METADATA_KEY_MIMETYPE = 22,
+ METADATA_KEY_DISC_NUMBER = 23,
// Add more here...
};
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 3b21468..8f423f7 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -59,6 +59,7 @@
kKeyAlbumArtMIME = 'alAM', // cstring
kKeyAuthor = 'auth', // cstring
kKeyCDTrackNumber = 'cdtr', // cstring
+ kKeyDiscNumber = 'dnum', // cstring
kKeyDate = 'date', // cstring
kKeyWriter = 'writ', // cstring
};
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index 88521f6..98464a0 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -110,5 +110,9 @@
include $(BUILD_SHARED_LIBRARY)
+# include the java examples
+include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk,\
+ java \
+ ))
endif #simulator
diff --git a/libs/rs/rsVertexArray.cpp b/libs/rs/rsVertexArray.cpp
index d0c0414..6c2002d 100644
--- a/libs/rs/rsVertexArray.cpp
+++ b/libs/rs/rsVertexArray.cpp
@@ -191,6 +191,9 @@
if (sc->isUserVertexProgram()) {
slot = sc->vtxAttribSlot(ct);
} else {
+ if (mAttribs[ct].kind == RS_KIND_USER) {
+ continue;
+ }
slot = sc->vtxAttribSlot(mAttribs[ct].kind);
}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 1fac07c..628cb6b7 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -81,10 +81,6 @@
void setTestProviderStatus(String provider, int status, in Bundle extras, long updateTime);
void clearTestProviderStatus(String provider);
- /* for installing external Location Providers */
- void installLocationProvider(String name, ILocationProvider provider);
- void installGeocodeProvider(IGeocodeProvider provider);
-
// for NI support
boolean sendNiResponse(int notifId, int userResponse);
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 6d7a23d..9027fc2 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -104,48 +104,6 @@
*/
public static final String KEY_LOCATION_CHANGED = "location";
- public interface GeocodeProvider {
- String getFromLocation(double latitude, double longitude, int maxResults,
- GeocoderParams params, List<Address> addrs);
-
- String getFromLocationName(String locationName,
- double lowerLeftLatitude, double lowerLeftLongitude,
- double upperRightLatitude, double upperRightLongitude, int maxResults,
- GeocoderParams params, List<Address> addrs);
- }
-
- private static final class GeocodeProviderProxy extends IGeocodeProvider.Stub {
- private GeocodeProvider mProvider;
-
- GeocodeProviderProxy(GeocodeProvider provider) {
- mProvider = provider;
- }
-
- /**
- * This method is overridden to implement the
- * {@link Geocoder#getFromLocation(double, double, int)} method.
- * Classes implementing this method should not hold a reference to the params parameter.
- */
- public String getFromLocation(double latitude, double longitude, int maxResults,
- GeocoderParams params, List<Address> addrs) {
- return mProvider.getFromLocation(latitude, longitude, maxResults, params, addrs);
- }
-
- /**
- * This method is overridden to implement the
- * {@link Geocoder#getFromLocationName(String, int, double, double, double, double)} method.
- * Classes implementing this method should not hold a reference to the params parameter.
- */
- public String getFromLocationName(String locationName,
- double lowerLeftLatitude, double lowerLeftLongitude,
- double upperRightLatitude, double upperRightLongitude, int maxResults,
- GeocoderParams params, List<Address> addrs) {
- return mProvider.getFromLocationName(locationName, lowerLeftLatitude,
- lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
- maxResults, params, addrs);
- }
- }
-
// Map from LocationListeners to their associated ListenerTransport objects
private HashMap<LocationListener,ListenerTransport> mListeners =
new HashMap<LocationListener,ListenerTransport>();
@@ -1395,75 +1353,6 @@
return false;
}
}
-
- /**
- * Installs a location provider.
- *
- * @param name of the location provider
- * @param provider Binder interface for the location provider
- *
- * @return true if the command succeeds.
- *
- * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
- *
- * {@hide}
- */
- public boolean installLocationProvider(String name, ILocationProvider provider) {
- try {
- mService.installLocationProvider(name, provider);
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in installLocationProvider: ", e);
- return false;
- }
- }
-
- /**
- * Installs a location provider.
- *
- * @param provider implementation of the location provider
- *
- * @return true if the command succeeds.
- *
- * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
- */
- public boolean installLocationProvider(LocationProviderImpl provider) {
- return installLocationProvider(provider.getName(), provider.getInterface());
- }
-
- /**
- * Installs a geocoder server.
- *
- * @param provider Binder interface for the geocoder provider
- *
- * @return true if the command succeeds.
- *
- * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
- */
- public boolean installGeocodeProvider(GeocodeProvider provider) {
- try {
- mService.installGeocodeProvider(new GeocodeProviderProxy(provider));
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in setGeocodeProvider: ", e);
- return false;
- }
- }
-
- /**
- * Used by location providers to report new locations.
- *
- * @param location new Location to report
- *
- * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
- */
- public void reportLocation(Location location) {
- try {
- mService.reportLocation(location);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in reportLocation: ", e);
- }
- }
/**
* Used by NetInitiatedActivity to report user response
diff --git a/location/java/android/location/LocationProviderImpl.java b/location/java/android/location/LocationProviderImpl.java
deleted file mode 100644
index 7148a02..0000000
--- a/location/java/android/location/LocationProviderImpl.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * 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.net.NetworkInfo;
-import android.os.Bundle;
-
-/**
- * An abstract superclass for location providers that are implemented
- * outside of the core android platform.
- * A LocationProviderImpl can be installed using the
- * {@link LocationManager#installLocationProvider(LocationProviderImpl)} method.
- * Installing a location provider requires the
- * android.permission.INSTALL_LOCATION_PROVIDER permission.
- */
-public abstract class LocationProviderImpl extends LocationProvider {
-
- private ILocationProvider.Stub mProvider = new ILocationProvider.Stub() {
-
- public boolean requiresNetwork() {
- return LocationProviderImpl.this.requiresNetwork();
- }
-
- public boolean requiresSatellite() {
- return LocationProviderImpl.this.requiresSatellite();
- }
-
- public boolean requiresCell() {
- return LocationProviderImpl.this.requiresCell();
- }
-
- public boolean hasMonetaryCost() {
- return LocationProviderImpl.this.hasMonetaryCost();
- }
-
- public boolean supportsAltitude() {
- return LocationProviderImpl.this.supportsAltitude();
- }
-
- public boolean supportsSpeed() {
- return LocationProviderImpl.this.supportsSpeed();
- }
-
- public boolean supportsBearing() {
- return LocationProviderImpl.this.supportsBearing();
- }
-
- public int getPowerRequirement() {
- return LocationProviderImpl.this.getPowerRequirement();
- }
-
- public int getAccuracy() {
- return LocationProviderImpl.this.getAccuracy();
- }
-
- public void enable() {
- LocationProviderImpl.this.enable();
- }
-
- public void disable() {
- LocationProviderImpl.this.disable();
- }
-
- public int getStatus(Bundle extras) {
- return LocationProviderImpl.this.getStatus(extras);
- }
-
- public long getStatusUpdateTime() {
- return LocationProviderImpl.this.getStatusUpdateTime();
- }
-
- public void enableLocationTracking(boolean enable) {
- LocationProviderImpl.this.enableLocationTracking(enable);
- }
-
- public void setMinTime(long minTime) {
- LocationProviderImpl.this.setMinTime(minTime);
- }
-
- public void updateNetworkState(int state, NetworkInfo info) {
- LocationProviderImpl.this.updateNetworkState(state, info);
- }
-
- public void updateLocation(Location location) {
- LocationProviderImpl.this.updateLocation(location);
- }
-
- public boolean sendExtraCommand(String command, Bundle extras) {
- return LocationProviderImpl.this.sendExtraCommand(command, extras);
- }
-
- public void addListener(int uid) {
- LocationProviderImpl.this.addListener(uid);
- }
-
- public void removeListener(int uid) {
- LocationProviderImpl.this.removeListener(uid);
- }
- };
-
- public LocationProviderImpl(String name) {
- super(name);
- }
-
- /**
- * {@hide}
- */
- /* package */ ILocationProvider getInterface() {
- return mProvider;
- }
-
- /**
- * Enables the location provider
- */
- public abstract void enable();
-
- /**
- * Disables the location provider
- */
- public abstract void disable();
-
- /**
- * Returns a information on the status of this provider.
- * {@link #OUT_OF_SERVICE} is returned if the provider is
- * out of service, and this is not expected to change in the near
- * future; {@link #TEMPORARILY_UNAVAILABLE} is returned if
- * the provider is temporarily unavailable but is expected to be
- * available shortly; and {@link #AVAILABLE} is returned
- * if the provider is currently available.
- *
- * <p> If extras is non-null, additional status information may be
- * added to it in the form of provider-specific key/value pairs.
- */
- public abstract int getStatus(Bundle extras);
-
- /**
- * Returns the time at which the status was last updated. It is the
- * responsibility of the provider to appropriately set this value using
- * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}.
- * there is a status update that it wishes to broadcast to all its
- * listeners. The provider should be careful not to broadcast
- * the same status again.
- *
- * @return time of last status update in millis since last reboot
- */
- public abstract long getStatusUpdateTime();
-
- /**
- * Notifies the location provider that clients are listening for locations.
- * Called with enable set to true when the first client is added and
- * called with enable set to false when the last client is removed.
- * This allows the provider to prepare for receiving locations,
- * and to shut down when no clients are remaining.
- *
- * @param enable true if location tracking should be enabled.
- */
- public abstract void enableLocationTracking(boolean enable);
-
- /**
- * Notifies the location provider of the smallest minimum time between updates amongst
- * all clients that are listening for locations. This allows the provider to reduce
- * the frequency of updates to match the requested frequency.
- *
- * @param minTime the smallest minTime value over all listeners for this provider.
- */
- public abstract void setMinTime(long minTime);
-
- /**
- * Updates the network state for the given provider. This function must
- * be overwritten if {@link #requiresNetwork} returns true. The state is
- * {@link #TEMPORARILY_UNAVAILABLE} (disconnected), OR {@link #AVAILABLE}
- * (connected or connecting).
- *
- * @param state data state
- */
- public abstract void updateNetworkState(int state, NetworkInfo info);
-
- /**
- * Informs the provider when a new location has been computed by a different
- * location provider. This is intended to be used as aiding data for the
- * receiving provider.
- *
- * @param location new location from other location provider
- */
- public abstract void updateLocation(Location location);
-
- /**
- * Implements addditional location provider specific additional commands.
- *
- * @param command name of the command to send to the provider.
- * @param extras optional arguments for the command (or null).
- * The provider may optionally fill the extras Bundle with results from the command.
- *
- * @return true if the command succeeds.
- */
- public abstract boolean sendExtraCommand(String command, Bundle extras);
-
- /**
- * Notifies the location provider when a new client is listening for locations.
- *
- * @param uid user ID of the new client.
- */
- public abstract void addListener(int uid);
-
- /**
- * Notifies the location provider when a client is no longer listening for locations.
- *
- * @param uid user ID of the client no longer listening.
- */
- public abstract void removeListener(int uid);
-}
-
diff --git a/location/java/android/location/provider/GeocodeProvider.java b/location/java/android/location/provider/GeocodeProvider.java
new file mode 100644
index 0000000..86376a7
--- /dev/null
+++ b/location/java/android/location/provider/GeocodeProvider.java
@@ -0,0 +1,83 @@
+/*
+ * 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.provider;
+
+import android.os.IBinder;
+
+import android.location.Address;
+import android.location.GeocoderParams;
+import android.location.IGeocodeProvider;
+
+import java.util.List;
+
+/**
+ * An abstract superclass for geocode providers that are implemented
+ * outside of the core android platform.
+ * Geocode providers can be implemented as services and return the result of
+ * {@link GeocodeProvider#getBinder()} in its getBinder() method.
+ *
+ * @hide
+ */
+public abstract class GeocodeProvider {
+
+ private IGeocodeProvider.Stub mProvider = new IGeocodeProvider.Stub() {
+ public String getFromLocation(double latitude, double longitude, int maxResults,
+ GeocoderParams params, List<Address> addrs) {
+ return GeocodeProvider.this.onGetFromLocation(latitude, longitude, maxResults,
+ params, addrs);
+ }
+
+ public String getFromLocationName(String locationName,
+ double lowerLeftLatitude, double lowerLeftLongitude,
+ double upperRightLatitude, double upperRightLongitude, int maxResults,
+ GeocoderParams params, List<Address> addrs) {
+ return GeocodeProvider.this.onGetFromLocationName(locationName, lowerLeftLatitude,
+ lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
+ maxResults, params, addrs);
+ }
+ };
+
+ /**
+ * This method is overridden to implement the
+ * {@link Geocoder#getFromLocation(double, double, int)} method.
+ * Classes implementing this method should not hold a reference to the params parameter.
+ */
+ public abstract String onGetFromLocation(double latitude, double longitude, int maxResults,
+ GeocoderParams params, List<Address> addrs);
+
+ /**
+ * This method is overridden to implement the
+ * {@link Geocoder#getFromLocationName(String, int, double, double, double, double)} method.
+ * Classes implementing this method should not hold a reference to the params parameter.
+ */
+ public abstract String onGetFromLocationName(String locationName,
+ double lowerLeftLatitude, double lowerLeftLongitude,
+ double upperRightLatitude, double upperRightLongitude, int maxResults,
+ GeocoderParams params, List<Address> addrs);
+
+ /**
+ * Returns the Binder interface for the geocode provider.
+ * This is intended to be used for the onBind() method of
+ * a service that implements a geocoder service.
+ *
+ * @return the IBinder instance for the provider
+ */
+ public IBinder getBinder() {
+ return mProvider;
+ }
+}
+
diff --git a/location/java/android/location/provider/LocationProvider.java b/location/java/android/location/provider/LocationProvider.java
new file mode 100644
index 0000000..0d028c0
--- /dev/null
+++ b/location/java/android/location/provider/LocationProvider.java
@@ -0,0 +1,333 @@
+/*
+ * 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.provider;
+
+import android.content.Context;
+import android.net.NetworkInfo;
+import android.location.ILocationManager;
+import android.location.ILocationProvider;
+import android.location.Location;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * An abstract superclass for location providers that are implemented
+ * outside of the core android platform.
+ * Location providers can be implemented as services and return the result of
+ * {@link LocationProvider#getBinder()} in its getBinder() method.
+ *
+ * @hide
+ */
+public abstract class LocationProvider {
+
+ private static final String TAG = "LocationProvider";
+
+ private ILocationManager mLocationManager;
+
+ private ILocationProvider.Stub mProvider = new ILocationProvider.Stub() {
+
+ public boolean requiresNetwork() {
+ return LocationProvider.this.onRequiresNetwork();
+ }
+
+ public boolean requiresSatellite() {
+ return LocationProvider.this.onRequiresSatellite();
+ }
+
+ public boolean requiresCell() {
+ return LocationProvider.this.onRequiresCell();
+ }
+
+ public boolean hasMonetaryCost() {
+ return LocationProvider.this.onHasMonetaryCost();
+ }
+
+ public boolean supportsAltitude() {
+ return LocationProvider.this.onSupportsAltitude();
+ }
+
+ public boolean supportsSpeed() {
+ return LocationProvider.this.onSupportsSpeed();
+ }
+
+ public boolean supportsBearing() {
+ return LocationProvider.this.onSupportsBearing();
+ }
+
+ public int getPowerRequirement() {
+ return LocationProvider.this.onGetPowerRequirement();
+ }
+
+ public int getAccuracy() {
+ return LocationProvider.this.onGetAccuracy();
+ }
+
+ public void enable() {
+ LocationProvider.this.onEnable();
+ }
+
+ public void disable() {
+ LocationProvider.this.onDisable();
+ }
+
+ public int getStatus(Bundle extras) {
+ return LocationProvider.this.onGetStatus(extras);
+ }
+
+ public long getStatusUpdateTime() {
+ return LocationProvider.this.onGetStatusUpdateTime();
+ }
+
+ public void enableLocationTracking(boolean enable) {
+ LocationProvider.this.onEnableLocationTracking(enable);
+ }
+
+ public void setMinTime(long minTime) {
+ LocationProvider.this.onSetMinTime(minTime);
+ }
+
+ public void updateNetworkState(int state, NetworkInfo info) {
+ LocationProvider.this.onUpdateNetworkState(state, info);
+ }
+
+ public void updateLocation(Location location) {
+ LocationProvider.this.onUpdateLocation(location);
+ }
+
+ public boolean sendExtraCommand(String command, Bundle extras) {
+ return LocationProvider.this.onSendExtraCommand(command, extras);
+ }
+
+ public void addListener(int uid) {
+ LocationProvider.this.onAddListener(uid);
+ }
+
+ public void removeListener(int uid) {
+ LocationProvider.this.onRemoveListener(uid);
+ }
+ };
+
+ public LocationProvider() {
+ IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
+ mLocationManager = ILocationManager.Stub.asInterface(b);
+ }
+
+ /**
+ * {@hide}
+ */
+ /* package */ ILocationProvider getInterface() {
+ return mProvider;
+ }
+
+ /**
+ * Returns the Binder interface for the location provider.
+ * This is intended to be used for the onBind() method of
+ * a service that implements a location provider service.
+ *
+ * @return the IBinder instance for the provider
+ */
+ public IBinder getBinder() {
+ return mProvider;
+ }
+
+ /**
+ * Used by the location provider to report new locations.
+ *
+ * @param location new Location to report
+ *
+ * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
+ */
+ public void reportLocation(Location location) {
+ try {
+ mLocationManager.reportLocation(location);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in reportLocation: ", e);
+ }
+ }
+
+ /**
+ * Returns true if the provider requires access to a
+ * data network (e.g., the Internet), false otherwise.
+ */
+ public abstract boolean onRequiresNetwork();
+
+ /**
+ * Returns true if the provider requires access to a
+ * satellite-based positioning system (e.g., GPS), false
+ * otherwise.
+ */
+ public abstract boolean onRequiresSatellite();
+
+ /**
+ * Returns true if the provider requires access to an appropriate
+ * cellular network (e.g., to make use of cell tower IDs), false
+ * otherwise.
+ */
+ public abstract boolean onRequiresCell();
+
+ /**
+ * Returns true if the use of this provider may result in a
+ * monetary charge to the user, false if use is free. It is up to
+ * each provider to give accurate information.
+ */
+ public abstract boolean onHasMonetaryCost();
+
+ /**
+ * Returns true if the provider is able to provide altitude
+ * information, false otherwise. A provider that reports altitude
+ * under most circumstances but may occassionally not report it
+ * should return true.
+ */
+ public abstract boolean onSupportsAltitude();
+
+ /**
+ * Returns true if the provider is able to provide speed
+ * information, false otherwise. A provider that reports speed
+ * under most circumstances but may occassionally not report it
+ * should return true.
+ */
+ public abstract boolean onSupportsSpeed();
+
+ /**
+ * Returns true if the provider is able to provide bearing
+ * information, false otherwise. A provider that reports bearing
+ * under most circumstances but may occassionally not report it
+ * should return true.
+ */
+ public abstract boolean onSupportsBearing();
+
+ /**
+ * Returns the power requirement for this provider.
+ *
+ * @return the power requirement for this provider, as one of the
+ * constants Criteria.POWER_REQUIREMENT_*.
+ */
+ public abstract int onGetPowerRequirement();
+
+ /**
+ * Returns a constant describing horizontal accuracy of this provider.
+ * If the provider returns finer grain or exact location,
+ * {@link Criteria#ACCURACY_FINE} is returned, otherwise if the
+ * location is only approximate then {@link Criteria#ACCURACY_COARSE}
+ * is returned.
+ */
+ public abstract int onGetAccuracy();
+
+ /**
+ * Enables the location provider
+ */
+ public abstract void onEnable();
+
+ /**
+ * Disables the location provider
+ */
+ public abstract void onDisable();
+
+ /**
+ * Returns a information on the status of this provider.
+ * {@link #OUT_OF_SERVICE} is returned if the provider is
+ * out of service, and this is not expected to change in the near
+ * future; {@link #TEMPORARILY_UNAVAILABLE} is returned if
+ * the provider is temporarily unavailable but is expected to be
+ * available shortly; and {@link #AVAILABLE} is returned
+ * if the provider is currently available.
+ *
+ * <p> If extras is non-null, additional status information may be
+ * added to it in the form of provider-specific key/value pairs.
+ */
+ public abstract int onGetStatus(Bundle extras);
+
+ /**
+ * Returns the time at which the status was last updated. It is the
+ * responsibility of the provider to appropriately set this value using
+ * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}.
+ * there is a status update that it wishes to broadcast to all its
+ * listeners. The provider should be careful not to broadcast
+ * the same status again.
+ *
+ * @return time of last status update in millis since last reboot
+ */
+ public abstract long onGetStatusUpdateTime();
+
+ /**
+ * Notifies the location provider that clients are listening for locations.
+ * Called with enable set to true when the first client is added and
+ * called with enable set to false when the last client is removed.
+ * This allows the provider to prepare for receiving locations,
+ * and to shut down when no clients are remaining.
+ *
+ * @param enable true if location tracking should be enabled.
+ */
+ public abstract void onEnableLocationTracking(boolean enable);
+
+ /**
+ * Notifies the location provider of the smallest minimum time between updates amongst
+ * all clients that are listening for locations. This allows the provider to reduce
+ * the frequency of updates to match the requested frequency.
+ *
+ * @param minTime the smallest minTime value over all listeners for this provider.
+ */
+ public abstract void onSetMinTime(long minTime);
+
+ /**
+ * Updates the network state for the given provider. This function must
+ * be overwritten if {@link #requiresNetwork} returns true. The state is
+ * {@link #TEMPORARILY_UNAVAILABLE} (disconnected), OR {@link #AVAILABLE}
+ * (connected or connecting).
+ *
+ * @param state data state
+ */
+ public abstract void onUpdateNetworkState(int state, NetworkInfo info);
+
+ /**
+ * Informs the provider when a new location has been computed by a different
+ * location provider. This is intended to be used as aiding data for the
+ * receiving provider.
+ *
+ * @param location new location from other location provider
+ */
+ public abstract void onUpdateLocation(Location location);
+
+ /**
+ * Implements addditional location provider specific additional commands.
+ *
+ * @param command name of the command to send to the provider.
+ * @param extras optional arguments for the command (or null).
+ * The provider may optionally fill the extras Bundle with results from the command.
+ *
+ * @return true if the command succeeds.
+ */
+ public abstract boolean onSendExtraCommand(String command, Bundle extras);
+
+ /**
+ * Notifies the location provider when a new client is listening for locations.
+ *
+ * @param uid user ID of the new client.
+ */
+ public abstract void onAddListener(int uid);
+
+ /**
+ * Notifies the location provider when a client is no longer listening for locations.
+ *
+ * @param uid user ID of the client no longer listening.
+ */
+ public abstract void onRemoveListener(int uid);
+}
+
diff --git a/location/java/com/android/internal/location/GeocoderProxy.java b/location/java/com/android/internal/location/GeocoderProxy.java
new file mode 100644
index 0000000..b06297b
--- /dev/null
+++ b/location/java/com/android/internal/location/GeocoderProxy.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.location;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.location.Address;
+import android.location.GeocoderParams;
+import android.location.IGeocodeProvider;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * A class for proxying IGeocodeProvider implementations.
+ *
+ * {@hide}
+ */
+public class GeocoderProxy {
+
+ private static final String TAG = "GeocoderProxy";
+
+ private final Context mContext;
+ private final Intent mIntent;
+ private final Connection mServiceConnection = new Connection();
+ private IGeocodeProvider mProvider;
+
+ public GeocoderProxy(Context context, String serviceName) {
+ mContext = context;
+ mIntent = new Intent(serviceName);
+ mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ private class Connection implements ServiceConnection {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "onServiceConnected " + className);
+ synchronized (this) {
+ mProvider = IGeocodeProvider.Stub.asInterface(service);
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ Log.d(TAG, "onServiceDisconnected " + className);
+ synchronized (this) {
+ mProvider = null;
+ }
+ }
+ }
+
+ public String getFromLocation(double latitude, double longitude, int maxResults,
+ GeocoderParams params, List<Address> addrs) {
+ IGeocodeProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ return provider.getFromLocation(latitude, longitude, maxResults,
+ params, addrs);
+ } catch (RemoteException e) {
+ Log.e(TAG, "getFromLocation failed", e);
+ }
+ }
+ return "Service not Available";
+ }
+
+ public String getFromLocationName(String locationName,
+ double lowerLeftLatitude, double lowerLeftLongitude,
+ double upperRightLatitude, double upperRightLongitude, int maxResults,
+ GeocoderParams params, List<Address> addrs) {
+ IGeocodeProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ return provider.getFromLocationName(locationName, lowerLeftLatitude,
+ lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
+ maxResults, params, addrs);
+ } catch (RemoteException e) {
+ Log.e(TAG, "getFromLocationName failed", e);
+ }
+ }
+ return "Service not Available";
+ }
+}
diff --git a/location/java/com/android/internal/location/LocationProviderProxy.java b/location/java/com/android/internal/location/LocationProviderProxy.java
index 2e0be89..361104f 100644
--- a/location/java/com/android/internal/location/LocationProviderProxy.java
+++ b/location/java/com/android/internal/location/LocationProviderProxy.java
@@ -16,155 +16,229 @@
package com.android.internal.location;
-import android.location.Address;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
import android.location.ILocationProvider;
import android.location.Location;
-import android.location.LocationManager;
import android.net.NetworkInfo;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.util.Log;
-import java.util.List;
-
/**
- * A class for proxying remote ILocationProvider implementations.
+ * A class for proxying ILocationProvider implementations.
*
* {@hide}
*/
-public class LocationProviderProxy implements IBinder.DeathRecipient {
+public class LocationProviderProxy {
private static final String TAG = "LocationProviderProxy";
+ private final Context mContext;
private final String mName;
- private final ILocationProvider mProvider;
+ private ILocationProvider mProvider;
+ private Intent mIntent;
+ private Handler mHandler;
+ private final Connection mServiceConnection = new Connection();
+
+ // cached values set by the location manager
private boolean mLocationTracking = false;
private boolean mEnabled = false;
- private long mMinTime = 0;
- private boolean mDead;
+ private long mMinTime = -1;
+ private int mNetworkState;
+ private NetworkInfo mNetworkInfo;
- public LocationProviderProxy(String name, ILocationProvider provider) {
+ // 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;
- try {
- provider.asBinder().linkToDeath(this, 0);
- } catch (RemoteException e) {
- Log.e(TAG, "linkToDeath failed", e);
- mDead = true;
+ }
+
+ // 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);
+ }
+
+ private class Connection implements ServiceConnection {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "LocationProviderProxy.onServiceConnected " + className);
+ synchronized (this) {
+ mProvider = ILocationProvider.Stub.asInterface(service);
+ if (mProvider != null) {
+ mHandler.post(mServiceConnectedTask);
+ }
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ Log.d(TAG, "LocationProviderProxy.onServiceDisconnected " + className);
+ synchronized (this) {
+ mProvider = null;
+ }
}
}
- public void unlinkProvider() {
- if (mProvider != null) {
- mProvider.asBinder().unlinkToDeath(this, 0);
+ private Runnable mServiceConnectedTask = new Runnable() {
+ public void run() {
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ if (provider == null) {
+ return;
+ }
+ }
+
+ if (mCachedAttributes == null) {
+ try {
+ mCachedAttributes = new DummyLocationProvider(mName);
+ mCachedAttributes.setRequiresNetwork(provider.requiresNetwork());
+ mCachedAttributes.setRequiresSatellite(provider.requiresSatellite());
+ mCachedAttributes.setRequiresCell(provider.requiresCell());
+ mCachedAttributes.setHasMonetaryCost(provider.hasMonetaryCost());
+ mCachedAttributes.setSupportsAltitude(provider.supportsAltitude());
+ mCachedAttributes.setSupportsSpeed(provider.supportsSpeed());
+ mCachedAttributes.setSupportsBearing(provider.supportsBearing());
+ mCachedAttributes.setPowerRequirement(provider.getPowerRequirement());
+ mCachedAttributes.setAccuracy(provider.getAccuracy());
+ } catch (RemoteException e) {
+ mCachedAttributes = null;
+ }
+ }
+
+ // resend previous values from the location manager if the service has restarted
+ try {
+ if (mEnabled) {
+ provider.enable();
+ }
+ if (mLocationTracking) {
+ provider.enableLocationTracking(true);
+ }
+ if (mMinTime >= 0) {
+ provider.setMinTime(mMinTime);
+ }
+ if (mNetworkInfo != null) {
+ provider.updateNetworkState(mNetworkState, mNetworkInfo);
+ }
+ } catch (RemoteException e) {
+ }
}
- }
+ };
public String getName() {
return mName;
}
- public boolean isDead() {
- return mDead;
- }
-
public boolean requiresNetwork() {
- try {
- return mProvider.requiresNetwork();
- } catch (RemoteException e) {
- Log.e(TAG, "requiresNetwork failed", e);
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.requiresNetwork();
+ } else {
return false;
}
}
public boolean requiresSatellite() {
- try {
- return mProvider.requiresSatellite();
- } catch (RemoteException e) {
- Log.e(TAG, "requiresSatellite failed", e);
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.requiresSatellite();
+ } else {
return false;
}
}
public boolean requiresCell() {
- try {
- return mProvider.requiresCell();
- } catch (RemoteException e) {
- Log.e(TAG, "requiresCell failed", e);
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.requiresCell();
+ } else {
return false;
}
}
public boolean hasMonetaryCost() {
- try {
- return mProvider.hasMonetaryCost();
- } catch (RemoteException e) {
- Log.e(TAG, "hasMonetaryCost failed", e);
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.hasMonetaryCost();
+ } else {
return false;
}
}
public boolean supportsAltitude() {
- try {
- return mProvider.supportsAltitude();
- } catch (RemoteException e) {
- Log.e(TAG, "supportsAltitude failed", e);
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.supportsAltitude();
+ } else {
return false;
}
}
public boolean supportsSpeed() {
- try {
- return mProvider.supportsSpeed();
- } catch (RemoteException e) {
- Log.e(TAG, "supportsSpeed failed", e);
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.supportsSpeed();
+ } else {
return false;
}
}
public boolean supportsBearing() {
- try {
- return mProvider.supportsBearing();
- } catch (RemoteException e) {
- Log.e(TAG, "supportsBearing failed", e);
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.supportsBearing();
+ } else {
return false;
}
}
public int getPowerRequirement() {
- try {
- return mProvider.getPowerRequirement();
- } catch (RemoteException e) {
- Log.e(TAG, "getPowerRequirement failed", e);
- return 0;
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.getPowerRequirement();
+ } else {
+ return -1;
}
}
public int getAccuracy() {
- try {
- return mProvider.getAccuracy();
- } catch (RemoteException e) {
- Log.e(TAG, "getAccuracy failed", e);
- return 0;
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.getAccuracy();
+ } else {
+ return -1;
}
}
public void enable() {
- try {
- mProvider.enable();
- mEnabled = true;
- } catch (RemoteException e) {
- Log.e(TAG, "enable failed", e);
+ mEnabled = true;
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.enable();
+ } catch (RemoteException e) {
+ }
}
}
public void disable() {
- try {
- mProvider.disable();
- mEnabled = false;
- } catch (RemoteException e) {
- Log.e(TAG, "disable failed", e);
+ mEnabled = false;
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.disable();
+ } catch (RemoteException e) {
+ }
}
}
@@ -173,22 +247,32 @@
}
public int getStatus(Bundle extras) {
- try {
- return mProvider.getStatus(extras);
- } catch (RemoteException e) {
- Log.e(TAG, "getStatus failed", e);
- return 0;
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
}
+ if (provider != null) {
+ try {
+ return provider.getStatus(extras);
+ } catch (RemoteException e) {
+ }
+ }
+ return 0;
}
public long getStatusUpdateTime() {
- try {
- return mProvider.getStatusUpdateTime();
- } catch (RemoteException e) {
- Log.e(TAG, "getStatusUpdateTime failed", e);
- return 0;
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
}
- }
+ if (provider != null) {
+ try {
+ return provider.getStatusUpdateTime();
+ } catch (RemoteException e) {
+ }
+ }
+ return 0;
+ }
public boolean isLocationTracking() {
return mLocationTracking;
@@ -196,10 +280,18 @@
public void enableLocationTracking(boolean enable) {
mLocationTracking = enable;
- try {
- mProvider.enableLocationTracking(enable);
- } catch (RemoteException e) {
- Log.e(TAG, "enableLocationTracking failed", e);
+ if (!enable) {
+ mMinTime = -1;
+ }
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.enableLocationTracking(enable);
+ } catch (RemoteException e) {
+ }
}
}
@@ -208,58 +300,84 @@
}
public void setMinTime(long minTime) {
- mMinTime = minTime;
- try {
- mProvider.setMinTime(minTime);
- } catch (RemoteException e) {
- Log.e(TAG, "setMinTime failed", e);
+ mMinTime = minTime;
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.setMinTime(minTime);
+ } catch (RemoteException e) {
+ }
}
}
public void updateNetworkState(int state, NetworkInfo info) {
- try {
- mProvider.updateNetworkState(state, info);
- } catch (RemoteException e) {
- Log.e(TAG, "updateNetworkState failed", e);
+ mNetworkState = state;
+ mNetworkInfo = info;
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.updateNetworkState(state, info);
+ } catch (RemoteException e) {
+ }
}
}
public void updateLocation(Location location) {
- try {
- mProvider.updateLocation(location);
- } catch (RemoteException e) {
- Log.e(TAG, "updateLocation failed", e);
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.updateLocation(location);
+ } catch (RemoteException e) {
+ }
}
}
public boolean sendExtraCommand(String command, Bundle extras) {
- try {
- return mProvider.sendExtraCommand(command, extras);
- } catch (RemoteException e) {
- Log.e(TAG, "sendExtraCommand failed", e);
- return false;
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
}
+ if (provider != null) {
+ try {
+ provider.sendExtraCommand(command, extras);
+ } catch (RemoteException e) {
+ }
+ }
+ return false;
}
public void addListener(int uid) {
- try {
- mProvider.addListener(uid);
- } catch (RemoteException e) {
- Log.e(TAG, "addListener failed", e);
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.addListener(uid);
+ } catch (RemoteException e) {
+ }
}
}
public void removeListener(int uid) {
- try {
- mProvider.removeListener(uid);
- } catch (RemoteException e) {
- Log.e(TAG, "removeListener failed", e);
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
}
- }
-
- public void binderDied() {
- Log.w(TAG, "Location Provider " + mName + " died");
- mDead = true;
- mProvider.asBinder().unlinkToDeath(this, 0);
+ if (provider != null) {
+ try {
+ provider.removeListener(uid);
+ } catch (RemoteException e) {
+ }
+ }
}
}
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index d51ab30..12872bc 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -54,12 +54,20 @@
LOCAL_SHARED_LIBRARIES += libdl
endif
-LOCAL_C_INCLUDES := external/tremor/Tremor \
+LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE) \
$(call include-path-for, graphics corecg) \
$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
$(TOP)/frameworks/base/media/libstagefright/include
+ifeq ($(TARGET_ARCH),arm)
+ LOCAL_C_INCLUDES += \
+ $(TOP)/external/tremolo/Tremolo
+else
+ LOCAL_C_INCLUDES += \
+ $(TOP)/external/tremor/Tremor
+endif
+
LOCAL_MODULE:= libmediaplayerservice
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index f42d55b..1bfcf65 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -49,30 +49,11 @@
}
status_t StagefrightPlayer::prepare() {
- LOGV("prepare");
-
- int32_t width, height;
- if (mPlayer->getVideoDimensions(&width, &height) != OK) {
- width = height = 0;
- }
-
- sendEvent(MEDIA_SET_VIDEO_SIZE, width, height);
-
- return OK;
+ return mPlayer->prepare();
}
status_t StagefrightPlayer::prepareAsync() {
- LOGV("prepareAsync");
-
- status_t err = prepare();
-
- if (err != OK) {
- return err;
- }
-
- sendEvent(MEDIA_PREPARED);
-
- return OK;
+ return mPlayer->prepareAsync();
}
status_t StagefrightPlayer::start() {
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index b25ce67..58eb12e 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -48,8 +48,15 @@
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
- $(TOP)/external/opencore/android \
+ $(TOP)/external/opencore/android
+
+ifeq ($(TARGET_ARCH),arm)
+ LOCAL_C_INCLUDES += \
+ $(TOP)/external/tremolo/Tremolo
+else
+ LOCAL_C_INCLUDES += \
$(TOP)/external/tremor/Tremor
+endif
LOCAL_SHARED_LIBRARIES := \
libbinder \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index e7351dc..4926920 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -229,6 +229,8 @@
mInputBuffer->release();
mInputBuffer = NULL;
}
+
+ mSeeking = false;
}
}
@@ -240,8 +242,6 @@
Mutex::Autolock autoLock(mLock);
- mSeeking = false;
-
if (err != OK) {
mReachedEOS = true;
memset((char *)data + size_done, 0, size_remaining);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 2b403f8..d25f7f6 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -37,21 +37,23 @@
namespace android {
struct AwesomeEvent : public TimedEventQueue::Event {
- AwesomeEvent(AwesomePlayer *player, int32_t code)
+ AwesomeEvent(
+ AwesomePlayer *player,
+ void (AwesomePlayer::*method)())
: mPlayer(player),
- mCode(code) {
+ mMethod(method) {
}
protected:
virtual ~AwesomeEvent() {}
virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
- mPlayer->onEvent(mCode);
+ (mPlayer->*mMethod)();
}
private:
AwesomePlayer *mPlayer;
- int32_t mCode;
+ void (AwesomePlayer::*mMethod)();
AwesomeEvent(const AwesomeEvent &);
AwesomeEvent &operator=(const AwesomeEvent &);
@@ -115,13 +117,16 @@
DataSource::RegisterDefaultSniffers();
- mVideoEvent = new AwesomeEvent(this, 0);
+ mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
mVideoEventPending = false;
- mStreamDoneEvent = new AwesomeEvent(this, 1);
+ mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
mStreamDoneEventPending = false;
- mBufferingEvent = new AwesomeEvent(this, 2);
+ mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
mBufferingEventPending = false;
- mCheckAudioStatusEvent = new AwesomeEvent(this, 3);
+
+ mCheckAudioStatusEvent = new AwesomeEvent(
+ this, &AwesomePlayer::onCheckAudioStatus);
+
mAudioStatusEventPending = false;
mQueue.start();
@@ -287,12 +292,12 @@
mPrefetcher.clear();
}
-void AwesomePlayer::notifyListener_l(int msg, int ext1) {
+void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
if (mListener != NULL) {
sp<MediaPlayerBase> listener = mListener.promote();
if (listener != NULL) {
- listener->sendEvent(msg, ext1);
+ listener->sendEvent(msg, ext1, ext2);
}
}
}
@@ -623,18 +628,7 @@
return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
}
-void AwesomePlayer::onEvent(int32_t code) {
- if (code == 1) {
- onStreamDone();
- return;
- } else if (code == 2) {
- onBufferingUpdate();
- return;
- } else if (code == 3) {
- onCheckAudioStatus();
- return;
- }
-
+void AwesomePlayer::onVideoEvent() {
Mutex::Autolock autoLock(mLock);
mVideoEventPending = false;
@@ -819,5 +813,65 @@
postCheckAudioStatusEvent_l();
}
+status_t AwesomePlayer::prepare() {
+ Mutex::Autolock autoLock(mLock);
+
+ status_t err = prepareAsync_l();
+
+ if (err != OK) {
+ return err;
+ }
+
+ while (mAsyncPrepareEvent != NULL) {
+ mPreparedCondition.wait(mLock);
+ }
+
+ return OK;
+}
+
+status_t AwesomePlayer::prepareAsync() {
+ Mutex::Autolock autoLock(mLock);
+ return prepareAsync_l();
+}
+
+status_t AwesomePlayer::prepareAsync_l() {
+ if (mAsyncPrepareEvent != NULL) {
+ return UNKNOWN_ERROR; // async prepare already pending.
+ }
+
+ mAsyncPrepareEvent = new AwesomeEvent(
+ this, &AwesomePlayer::onPrepareAsyncEvent);
+
+ mQueue.postEvent(mAsyncPrepareEvent);
+
+ return OK;
+}
+
+void AwesomePlayer::onPrepareAsyncEvent() {
+ sp<Prefetcher> prefetcher;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ prefetcher = mPrefetcher;
+ }
+
+ if (prefetcher != NULL) {
+ prefetcher->prepare();
+ }
+
+ 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);
+ }
+
+ notifyListener_l(MEDIA_PREPARED);
+
+ mAsyncPrepareEvent = NULL;
+ mPreparedCondition.signal();
+}
+
} // namespace android
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index accd94d..79b7674 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -737,6 +737,7 @@
{ kKeyYear, "TYE", "TYER" },
{ kKeyAuthor, "TXT", "TEXT" },
{ kKeyCDTrackNumber, "TRK", "TRCK" },
+ { kKeyDiscNumber, "TPA", "TPOS" },
};
static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp
index 862998a..835e167 100644
--- a/media/libstagefright/Prefetcher.cpp
+++ b/media/libstagefright/Prefetcher.cpp
@@ -171,7 +171,7 @@
}
}
-int64_t Prefetcher::getCachedDurationUs() {
+int64_t Prefetcher::getCachedDurationUs(bool *noMoreData) {
Mutex::Autolock autoLock(mLock);
int64_t minCacheDurationUs = -1;
@@ -197,9 +197,25 @@
}
}
+ if (noMoreData) {
+ *noMoreData = minCacheDurationUs < 0;
+ }
+
return minCacheDurationUs < 0 ? 0 : minCacheDurationUs;
}
+status_t Prefetcher::prepare() {
+ // Buffer about 2 secs worth of data on prepare.
+
+ int64_t duration;
+ bool noMoreData;
+ do {
+ duration = getCachedDurationUs(&noMoreData);
+ } while (!noMoreData && duration < 2000000);
+
+ return OK;
+}
+
////////////////////////////////////////////////////////////////////////////////
PrefetchedSource::PrefetchedSource(
@@ -232,15 +248,6 @@
mStarted = true;
- for (;;) {
- // Buffer 2 secs on startup.
- if (mReachedEOS || mCacheDurationUs > 2000000) {
- break;
- }
-
- mCondition.wait(mLock);
- }
-
return OK;
}
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 3451383..22f701c 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -191,6 +191,7 @@
};
static const KeyMap kKeyMap[] = {
{ "tracknumber", METADATA_KEY_CD_TRACK_NUMBER },
+ { "discnumber", METADATA_KEY_DISC_NUMBER },
{ "album", METADATA_KEY_ALBUM },
{ "artist", METADATA_KEY_ARTIST },
{ "composer", METADATA_KEY_COMPOSER },
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index dfba74f..f617fe8 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -305,6 +305,7 @@
static const Map kMap[] = {
{ kKeyMIMEType, METADATA_KEY_MIMETYPE },
{ kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER },
+ { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER },
{ kKeyAlbum, METADATA_KEY_ALBUM },
{ kKeyArtist, METADATA_KEY_ARTIST },
{ kKeyAuthor, METADATA_KEY_AUTHOR },
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 6d64717..16a2a10 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -24,6 +24,7 @@
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/Utils.h>
#include <utils/String8.h>
+#include <byteswap.h>
namespace android {
@@ -273,7 +274,9 @@
String8 *s) {
size_t utf8len = 0;
for (size_t i = 0; i < size; ++i) {
- if (data[i] < 0x80) {
+ if (data[i] == '\0') {
+ break;
+ } else if (data[i] < 0x80) {
++utf8len;
} else {
utf8len += 2;
@@ -290,7 +293,9 @@
char *tmp = new char[utf8len];
char *ptr = tmp;
for (size_t i = 0; i < size; ++i) {
- if (data[i] < 0x80) {
+ if (data[i] == '\0') {
+ break;
+ } else if (data[i] < 0x80) {
*ptr++ = data[i];
} else if (data[i] < 0xc0) {
*ptr++ = 0xc2;
@@ -324,7 +329,7 @@
return;
}
- id->setTo((const char *)mFrameData, mFrameSize);
+ convertISO8859ToString8(mFrameData, mFrameSize, id);
return;
}
@@ -336,7 +341,26 @@
} else {
// UCS-2
// API wants number of characters, not number of bytes...
- id->setTo((const char16_t *)(mFrameData + 1), n / 2);
+ int len = n / 2;
+ const char16_t *framedata = (const char16_t *) (mFrameData + 1);
+ char16_t *framedatacopy = NULL;
+ if (*framedata == 0xfffe) {
+ // endianness marker doesn't match host endianness, convert
+ framedatacopy = new char16_t[len];
+ for (int i = 0; i < len; i++) {
+ framedatacopy[i] = bswap_16(framedata[i]);
+ }
+ framedata = framedatacopy;
+ }
+ // If the string starts with an endianness marker, skip it
+ if (*framedata == 0xfeff) {
+ framedata++;
+ len--;
+ }
+ id->setTo(framedata, len);
+ if (framedatacopy != NULL) {
+ delete[] framedatacopy;
+ }
}
}
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 75e71e6..651b910 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -57,6 +57,10 @@
void reset();
+ status_t prepare();
+ status_t prepareAsync();
+ status_t prepareAsync_l();
+
status_t play();
status_t pause();
@@ -121,6 +125,9 @@
sp<TimedEventQueue::Event> mCheckAudioStatusEvent;
bool mAudioStatusEventPending;
+ sp<TimedEventQueue::Event> mAsyncPrepareEvent;
+ Condition mPreparedCondition;
+
void postVideoEvent_l(int64_t delayUs = -1);
void postBufferingEvent_l();
void postStreamDoneEvent_l();
@@ -143,13 +150,14 @@
status_t setAudioSource(sp<MediaSource> source);
status_t setVideoSource(sp<MediaSource> source);
- void onEvent(int32_t code);
void onStreamDone();
- void notifyListener_l(int msg, int ext1 = 0);
+ void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0);
+ void onVideoEvent();
void onBufferingUpdate();
void onCheckAudioStatus();
+ void onPrepareAsyncEvent();
AwesomePlayer(const AwesomePlayer &);
AwesomePlayer &operator=(const AwesomePlayer &);
diff --git a/media/libstagefright/include/Prefetcher.h b/media/libstagefright/include/Prefetcher.h
index 7a97785..d227864 100644
--- a/media/libstagefright/include/Prefetcher.h
+++ b/media/libstagefright/include/Prefetcher.h
@@ -34,7 +34,9 @@
// that will benefit from prefetching/caching the original one.
sp<MediaSource> addSource(const sp<MediaSource> &source);
- int64_t getCachedDurationUs();
+ int64_t getCachedDurationUs(bool *noMoreData = NULL);
+
+ status_t prepare();
protected:
virtual ~Prefetcher();
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index b7eea2e..bca736a2e 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -133,6 +133,7 @@
private HashMap<String, ITtsCallback> mCallbacksMap;
private Boolean mIsSpeaking;
+ private Boolean mSynthBusy;
private ArrayList<SpeechItem> mSpeechQueue;
private HashMap<String, SoundResource> mEarcons;
private HashMap<String, SoundResource> mUtterances;
@@ -168,6 +169,7 @@
mSelf = this;
mIsSpeaking = false;
+ mSynthBusy = false;
mEarcons = new HashMap<String, SoundResource>();
mUtterances = new HashMap<String, SoundResource>();
@@ -733,10 +735,11 @@
try {
synthAvailable = synthesizerLock.tryLock();
if (!synthAvailable) {
+ mSynthBusy = true;
Thread.sleep(100);
Thread synth = (new Thread(new SynthThread()));
- //synth.setPriority(Thread.MIN_PRIORITY);
synth.start();
+ mSynthBusy = false;
return;
}
int streamType = DEFAULT_STREAM_TYPE;
@@ -821,10 +824,11 @@
try {
synthAvailable = synthesizerLock.tryLock();
if (!synthAvailable) {
+ mSynthBusy = true;
Thread.sleep(100);
Thread synth = (new Thread(new SynthThread()));
- //synth.setPriority(Thread.MIN_PRIORITY);
synth.start();
+ mSynthBusy = false;
return;
}
String language = "";
@@ -959,6 +963,12 @@
private void processSpeechQueue() {
boolean speechQueueAvailable = false;
+ synchronized (this) {
+ if (mSynthBusy){
+ // There is already a synth thread waiting to run.
+ return;
+ }
+ }
try {
speechQueueAvailable =
speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java
index b56b13b..407983d 100644
--- a/services/java/com/android/server/AccessibilityManagerService.java
+++ b/services/java/com/android/server/AccessibilityManagerService.java
@@ -176,8 +176,8 @@
context.registerReceiver(broadcastReceiver, packageFilter);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
- sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE);
- sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(broadcastReceiver, sdFilter);
// boot completed
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index c28cf44..44cc0bb 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -782,7 +782,7 @@
mContext.registerReceiver(this, filter);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
- sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(this, sdFilter);
}
@@ -791,7 +791,7 @@
synchronized (mLock) {
String action = intent.getAction();
String pkgList[] = null;
- if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+ if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
} else {
Uri data = intent.getData();
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 684f117..f336d1f 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -147,8 +147,8 @@
mContext.registerReceiver(mBroadcastReceiver, filter);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
- sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE);
- sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(mBroadcastReceiver, sdFilter);
}
@@ -1077,10 +1077,10 @@
} else {
boolean added = false;
String pkgList[] = null;
- if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action)) {
+ if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
added = true;
- } if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+ } if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
added = false;
} else {
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 2f845e1..27055ed 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -76,6 +76,7 @@
import java.util.List;
import java.util.Map;
import java.util.Random;
+import java.util.Set;
class BackupManagerService extends IBackupManager.Stub {
private static final String TAG = "BackupManagerService";
@@ -226,7 +227,9 @@
private File mEverStored;
HashSet<String> mEverStoredApps = new HashSet<String>();
+ static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1; // increment when the schema changes
File mTokenFile;
+ Set<String> mAncestralPackages = null;
long mAncestralToken = 0;
long mCurrentToken = 0;
@@ -500,8 +503,20 @@
mTokenFile = new File(mBaseStateDir, "ancestral");
try {
RandomAccessFile tf = new RandomAccessFile(mTokenFile, "r");
- mAncestralToken = tf.readLong();
- mCurrentToken = tf.readLong();
+ int version = tf.readInt();
+ if (version == CURRENT_ANCESTRAL_RECORD_VERSION) {
+ mAncestralToken = tf.readLong();
+ mCurrentToken = tf.readLong();
+
+ int numPackages = tf.readInt();
+ if (numPackages >= 0) {
+ mAncestralPackages = new HashSet<String>();
+ for (int i = 0; i < numPackages; i++) {
+ String pkgName = tf.readUTF();
+ mAncestralPackages.add(pkgName);
+ }
+ }
+ }
} catch (IOException e) {
Log.w(TAG, "Unable to read token file", e);
}
@@ -565,8 +580,8 @@
mContext.registerReceiver(mBroadcastReceiver, filter);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
- sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE);
- sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(mBroadcastReceiver, sdFilter);
}
@@ -724,10 +739,10 @@
}
added = Intent.ACTION_PACKAGE_ADDED.equals(action);
replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
- } else if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action)) {
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
added = true;
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- } else if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
added = false;
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
}
@@ -972,12 +987,31 @@
}
}
- // Record the current and ancestral backup tokens persistently
+ // Persistently record the current and ancestral backup tokens as well
+ // as the set of packages with data [supposedly] available in the
+ // ancestral dataset.
void writeRestoreTokens() {
try {
RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd");
+
+ // First, the version number of this record, for futureproofing
+ af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION);
+
+ // Write the ancestral and current tokens
af.writeLong(mAncestralToken);
af.writeLong(mCurrentToken);
+
+ // Now write the set of ancestral packages
+ if (mAncestralPackages == null) {
+ af.writeInt(-1);
+ } else {
+ af.writeInt(mAncestralPackages.size());
+ if (DEBUG) Log.v(TAG, "Ancestral packages: " + mAncestralPackages.size());
+ for (String pkgName : mAncestralPackages) {
+ af.writeUTF(pkgName);
+ if (DEBUG) Log.v(TAG, " " + pkgName);
+ }
+ }
af.close();
} catch (IOException e) {
Log.w(TAG, "Unable to write token file:", e);
@@ -1502,6 +1536,7 @@
* the user is waiting, after all.
*/
+ PackageManagerBackupAgent pmAgent = null;
int error = -1; // assume error
// build the set of apps to restore
@@ -1562,7 +1597,7 @@
}
// Pull the Package Manager metadata from the restore set first
- PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+ pmAgent = new PackageManagerBackupAgent(
mPackageManager, agentPackages);
processOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(pmAgent.onBind()));
@@ -1705,8 +1740,10 @@
}
// If this was a restoreAll operation, record that this was our
- // ancestral dataset
- if (mTargetPackage == null) {
+ // ancestral dataset, as well as the set of apps that are possibly
+ // restoreable from the dataset
+ if (mTargetPackage == null && pmAgent != null) {
+ mAncestralPackages = pmAgent.getRestoredPackages();
mAncestralToken = mToken;
writeRestoreTokens();
}
@@ -2436,6 +2473,12 @@
}
}
+ pw.println("Ancestral packages: "
+ + (mAncestralPackages == null ? "none" : mAncestralPackages.size()));
+ for (String pkg : mAncestralPackages) {
+ pw.println(" " + pkg);
+ }
+
pw.println("Ever backed up: " + mEverStoredApps.size());
for (String pkg : mEverStoredApps) {
pw.println(" " + pkg);
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index dc942a2..5e96a2f 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -344,8 +344,8 @@
if (pkg != null) {
pkgList = new String[] { pkg };
}
- } else if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action) ||
- Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action) ||
+ Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
}
if (pkgList == null || pkgList.length == 0) {
@@ -448,8 +448,8 @@
mContext.registerReceiver(mBroadcastReceiver, packageFilt);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
- sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE);
- sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(mBroadcastReceiver, sdFilter);
IntentFilter screenOnOffFilt = new IntentFilter();
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 3a42b37..fff6c54 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -29,16 +29,18 @@
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.ContentQueryMap;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.database.Cursor;
import android.location.Address;
import android.location.GeocoderParams;
-import android.location.IGeocodeProvider;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
import android.location.ILocationListener;
@@ -64,10 +66,11 @@
import android.util.Log;
import android.util.PrintWriterPrinter;
+import com.android.internal.location.GeocoderProxy;
import com.android.internal.location.GpsLocationProvider;
+import com.android.internal.location.GpsNetInitiatedHandler;
import com.android.internal.location.LocationProviderProxy;
import com.android.internal.location.MockProvider;
-import com.android.internal.location.GpsNetInitiatedHandler;
/**
* The service class that manages LocationProviders and issues location
@@ -105,7 +108,7 @@
private static boolean sProvidersLoaded = false;
private final Context mContext;
- private IGeocodeProvider mGeocodeProvider;
+ private GeocoderProxy mGeocodeProvider;
private IGpsStatusProvider mGpsStatusProvider;
private INetInitiatedListener mNetInitiatedListener;
private LocationWorkerHandler mLocationHandler;
@@ -415,7 +418,6 @@
private void removeProvider(LocationProviderProxy provider) {
mProviders.remove(provider);
- provider.unlinkProvider();
mProvidersByName.remove(provider.getName());
}
@@ -446,11 +448,28 @@
GpsLocationProvider provider = new GpsLocationProvider(mContext, this);
mGpsStatusProvider = provider.getGpsStatusProvider();
mNetInitiatedListener = provider.getNetInitiatedListener();
- LocationProviderProxy proxy = new LocationProviderProxy(LocationManager.GPS_PROVIDER, provider);
+ LocationProviderProxy proxy =
+ new LocationProviderProxy(mContext, LocationManager.GPS_PROVIDER, provider);
addProvider(proxy);
mGpsLocationProvider = proxy;
}
+ // initialize external network location and geocoder services
+ Resources resources = mContext.getResources();
+ String serviceName = resources.getString(
+ com.android.internal.R.string.config_networkLocationProvider);
+ if (serviceName != null) {
+ mNetworkLocationProvider =
+ new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER,
+ serviceName, mLocationHandler);
+ addProvider(mNetworkLocationProvider);
+ }
+
+ serviceName = resources.getString(com.android.internal.R.string.config_geocodeProvider);
+ if (serviceName != null) {
+ mGeocodeProvider = new GeocoderProxy(mContext, serviceName);
+ }
+
updateProvidersLocked();
}
@@ -484,7 +503,7 @@
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
mContext.registerReceiver(mBroadcastReceiver, intentFilter);
- IntentFilter sdFilter = new IntentFilter(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+ IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(mBroadcastReceiver, sdFilter);
// listen for settings changes
@@ -507,45 +526,6 @@
Looper.loop();
}
- public void installLocationProvider(String name, ILocationProvider provider) {
- if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
- }
-
- synchronized (mLock) {
- // check to see if we are reinstalling a dead provider
- LocationProviderProxy oldProvider = mProvidersByName.get(name);
- if (oldProvider != null) {
- if (oldProvider.isDead()) {
- Log.d(TAG, "replacing dead provider");
- removeProvider(oldProvider);
- } else {
- throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
- }
- }
-
- LocationProviderProxy proxy = new LocationProviderProxy(name, provider);
- addProvider(proxy);
- updateProvidersLocked();
- if (LocationManager.NETWORK_PROVIDER.equals(name)) {
- mNetworkLocationProvider = proxy;
- }
-
- // notify provider of current network state
- proxy.updateNetworkState(mNetworkState, null);
- }
- }
-
- public void installGeocodeProvider(IGeocodeProvider provider) {
- if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
- }
-
- mGeocodeProvider = provider;
- }
-
private boolean isAllowedBySettingsLocked(String provider) {
if (mEnabledProviders.contains(provider)) {
return true;
@@ -1313,7 +1293,7 @@
}
/**
- * @return null if the provider does not exits
+ * @return null if the provider does not exist
* @throws SecurityException if the provider is not allowed to be
* accessed by the caller
*/
@@ -1332,7 +1312,7 @@
private Bundle _getProviderInfoLocked(String provider) {
LocationProviderProxy p = mProvidersByName.get(provider);
- if (p == null) {
+ if (p == null || !p.isEnabled()) {
return null;
}
@@ -1552,10 +1532,10 @@
if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
|| action.equals(Intent.ACTION_PACKAGE_RESTARTED)
- || action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) {
+ || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
synchronized (mLock) {
int uidList[] = null;
- if (action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) {
+ if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
} else {
uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)};
@@ -1618,7 +1598,7 @@
synchronized (mLock) {
for (int i = mProviders.size() - 1; i >= 0; i--) {
LocationProviderProxy provider = mProviders.get(i);
- if (provider.requiresNetwork()) {
+ if (provider.isEnabled() && provider.requiresNetwork()) {
provider.updateNetworkState(mNetworkState, info);
}
}
@@ -1669,13 +1649,8 @@
public String getFromLocation(double latitude, double longitude, int maxResults,
GeocoderParams params, List<Address> addrs) {
if (mGeocodeProvider != null) {
- try {
- return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
- params, addrs);
- } catch (RemoteException e) {
- Log.e(TAG, "getFromLocation failed", e);
- mGeocodeProvider = null;
- }
+ return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
+ params, addrs);
}
return null;
}
@@ -1687,14 +1662,9 @@
GeocoderParams params, List<Address> addrs) {
if (mGeocodeProvider != null) {
- try {
- return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
- lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
- maxResults, params, addrs);
- } catch (RemoteException e) {
- Log.e(TAG, "getFromLocationName failed", e);
- mGeocodeProvider = null;
- }
+ return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
+ lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
+ maxResults, params, addrs);
}
return null;
}
@@ -1737,7 +1707,7 @@
if (mProvidersByName.get(name) != null) {
throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
}
- addProvider(new LocationProviderProxy(name, provider));
+ addProvider(new LocationProviderProxy(mContext, name, 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 6382646..51abfc3 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -670,7 +670,6 @@
*/
public int mountVolume(String path) {
validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
-
int rc = MountServiceResultCode.OperationSucceeded;
try {
@@ -721,10 +720,21 @@
public int unmountVolume(String path) {
validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+ // Check if media has been mounted
+ String oldState = mLegacyState;
+ if (!oldState.equals(Environment.MEDIA_MOUNTED)) {
+ return VoldResponseCode.OpFailedVolNotMounted;
+ }
+ // Notify PackageManager of potential media removal and deal with
+ // return code later on. The caller of this api should be aware or have been
+ // notified that the applications installed on the media will be killed.
+ mPms.updateExternalMediaStatus(false);
try {
mConnector.doCommand(String.format("volume unmount %s", path));
return MountServiceResultCode.OperationSucceeded;
} catch (NativeDaemonConnectorException e) {
+ // Don't worry about mismatch in PackageManager since the
+ // call back will handle the status changes any way.
int code = e.getCode();
if (code == VoldResponseCode.OpFailedVolNotMounted) {
return MountServiceResultCode.OperationFailedVolumeNotMounted;
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 9a066d3..cf083c04 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -21,7 +21,6 @@
import android.os.Environment;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.util.Config;
import android.util.Log;
import java.io.IOException;
@@ -41,6 +40,7 @@
* protocol.
*/
final class NativeDaemonConnector implements Runnable {
+ private static final boolean LOCAL_LOGD = false;
private BlockingQueue<String> mResponseQueue;
private OutputStream mOutputStream;
@@ -110,7 +110,7 @@
for (int i = 0; i < count; i++) {
if (buffer[i] == 0) {
String event = new String(buffer, start, i - start);
-// Log.d(TAG, "Got packet {" + event + "}");
+ if (LOCAL_LOGD) Log.d(TAG, String.format("RCV <- {%s}", event));
String[] tokens = event.split(" ");
try {
@@ -177,7 +177,7 @@
*/
private void sendCommand(String command, String argument) {
synchronized (this) {
- Log.d(TAG, "sendCommand {" + command + "} {" + argument + "}");
+ if (LOCAL_LOGD) Log.d(TAG, String.format("SND -> {%s} {%s}", command, argument));
if (mOutputStream == null) {
Log.e(TAG, "No connection to daemon", new IllegalStateException());
} else {
@@ -210,7 +210,7 @@
while (!complete) {
try {
String line = mResponseQueue.take();
- Log.d(TAG, String.format("RSP -> {%s}", line));
+ if (LOCAL_LOGD) Log.d(TAG, String.format("RSP <- {%s}", line));
String[] tokens = line.split(" ");
try {
code = Integer.parseInt(tokens[0]);
@@ -250,13 +250,18 @@
String[] rdata = new String[rsp.size()-1];
int idx = 0;
- for (String line : rsp) {
+ for (int i = 0; i < rsp.size(); i++) {
+ String line = rsp.get(i);
try {
String[] tok = line.split(" ");
int code = Integer.parseInt(tok[0]);
if (code == expectedResponseCode) {
rdata[idx++] = line.substring(tok[0].length() + 1);
} else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
+ if (LOCAL_LOGD) Log.d(TAG, String.format("List terminated with {%s}", line));
+ if (i != rsp.size()) {
+ Log.w(TAG, String.format("Recv'd %d lines after list term", (rsp.size()-i)));
+ }
return rdata;
} else {
throw new NativeDaemonConnectorException(
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 02a0401..d989b6b 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -330,9 +330,9 @@
updateAdbNotification();
} else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
|| action.equals(Intent.ACTION_PACKAGE_RESTARTED)
- || action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) {
+ || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
String pkgList[] = null;
- if (action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) {
+ if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
} else {
Uri uri = intent.getData();
@@ -440,7 +440,7 @@
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
mContext.registerReceiver(mIntentReceiver, filter);
- IntentFilter sdFilter = new IntentFilter(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+ IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(mIntentReceiver, sdFilter);
SettingsObserver observer = new SettingsObserver(mHandler);
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java
index dbd1826..9551db5 100644
--- a/services/java/com/android/server/PackageManagerBackupAgent.java
+++ b/services/java/com/android/server/PackageManagerBackupAgent.java
@@ -40,6 +40,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* We back up the signatures of each package so that during a system restore,
@@ -100,6 +101,20 @@
return mRestoredSignatures.get(packageName);
}
+
+ public Set<String> getRestoredPackages() {
+ if (mRestoredSignatures == null) {
+ Log.w(TAG, "getRestoredPackages() before metadata read!");
+ return null;
+ }
+
+ // This is technically the set of packages on the originating handset
+ // that had backup agents at all, not limited to the set of packages
+ // that had actually contributed a restore dataset, but it's a
+ // close enough approximation for our purposes and does not require any
+ // additional involvement by the transport to obtain.
+ return mRestoredSignatures.keySet();
+ }
// The backed up data is the signature block for each app, keyed by
// the package name.
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 387f139..f27ef8e 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -2111,6 +2111,12 @@
File file = new File(dir, files[i]);
PackageParser.Package pkg = scanPackageLI(file,
flags|PackageParser.PARSE_MUST_BE_APK, scanMode);
+ // Don't mess around with apps in system partition.
+ if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0) {
+ // Delete the apk
+ Log.w(TAG, "Cleaning up failed install of " + file);
+ file.delete();
+ }
}
}
@@ -2353,6 +2359,13 @@
private PackageParser.Package scanPackageLI(
PackageParser.Package pkg, int parseFlags, int scanMode) {
File scanFile = new File(pkg.mScanPath);
+ if (scanFile == null || pkg.applicationInfo.sourceDir == null ||
+ pkg.applicationInfo.publicSourceDir == null) {
+ // Bail out. The resource and code paths haven't been set.
+ Log.w(TAG, " Code and resource paths haven't been set correctly");
+ mLastScanError = PackageManager.INSTALL_FAILED_INVALID_APK;
+ return null;
+ }
mScanningPath = scanFile;
if (pkg == null) {
mLastScanError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
@@ -4959,69 +4972,82 @@
File tmpPackageFile = new File(args.getCodePath());
boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
boolean onSd = ((pFlags & PackageManager.INSTALL_ON_SDCARD) != 0);
- boolean replacingExistingPackage = false;
+ boolean replace = false;
int scanMode = SCAN_MONITOR | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE
| (newInstall ? SCAN_NEW_INSTALL : 0);
// Result object to be returned
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
- main_flow: try {
- // Retrieve PackageSettings and parse package
- int parseFlags = PackageParser.PARSE_CHATTY |
- (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) |
- (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
- parseFlags |= mDefParseFlags;
- PackageParser pp = new PackageParser(tmpPackageFile.getPath());
- pp.setSeparateProcesses(mSeparateProcesses);
- final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
- null, mMetrics, parseFlags);
- if (pkg == null) {
- res.returnCode = pp.getParseError();
- break main_flow;
+ // Retrieve PackageSettings and parse package
+ int parseFlags = PackageParser.PARSE_CHATTY |
+ (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) |
+ (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
+ parseFlags |= mDefParseFlags;
+ PackageParser pp = new PackageParser(tmpPackageFile.getPath());
+ pp.setSeparateProcesses(mSeparateProcesses);
+ final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
+ null, mMetrics, parseFlags);
+ if (pkg == null) {
+ res.returnCode = pp.getParseError();
+ return;
+ }
+ String pkgName = res.name = pkg.packageName;
+ if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
+ if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
+ res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
+ return;
}
- String pkgName = res.name = pkg.packageName;
- if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
- if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
- res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
- break main_flow;
+ }
+ if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
+ res.returnCode = pp.getParseError();
+ return;
+ }
+ // Some preinstall checks
+ if (forwardLocked && onSd) {
+ // Make sure forward locked apps can only be installed
+ // on internal storage
+ Log.w(TAG, "Cannot install protected apps on sdcard");
+ res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+ return;
+ }
+ // Get rid of all references to package scan path via parser.
+ pp = null;
+ String oldCodePath = null;
+ boolean systemApp = false;
+ synchronized (mPackages) {
+ // Check if installing already existing package
+ if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0
+ && mPackages.containsKey(pkgName)) {
+ replace = true;
+ }
+ PackageSetting ps = mSettings.mPackages.get(pkgName);
+ if (ps != null) {
+ oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
+ if (ps.pkg != null && ps.pkg.applicationInfo != null) {
+ systemApp = (ps.pkg.applicationInfo.flags &
+ ApplicationInfo.FLAG_SYSTEM) != 0;
}
}
- if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
- res.returnCode = pp.getParseError();
- break main_flow;
- }
+ }
- // Get rid of all references to package scan path via parser.
- pp = null;
- String oldCodePath = null;
- synchronized (mPackages) {
- //check if installing already existing package
- if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0
- && mPackages.containsKey(pkgName)) {
- replacingExistingPackage = true;
- }
- PackageSetting ps = mSettings.mPackages.get(pkgName);
- if (ps != null) {
- oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
- }
- }
-
- if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {
- res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- break main_flow;
- }
- // Set application objects path explicitly after the rename
- setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
- if(replacingExistingPackage) {
- replacePackageLI(pkg, parseFlags, scanMode,
- installerPackageName, res);
- } else {
- installNewPackageLI(pkg, parseFlags, scanMode,
- installerPackageName,res);
- }
- } finally {
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- }
+ if (systemApp && onSd) {
+ // Disable updates to system apps on sdcard
+ Log.w(TAG, "Cannot install updates to system apps on sdcard");
+ res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+ return;
+ }
+ if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {
+ res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ return;
+ }
+ // Set application objects path explicitly after the rename
+ setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
+ if(replace) {
+ replacePackageLI(pkg, parseFlags, scanMode,
+ installerPackageName, res);
+ } else {
+ installNewPackageLI(pkg, parseFlags, scanMode,
+ installerPackageName,res);
}
}
@@ -8409,8 +8435,8 @@
}
public void updateExternalMediaStatus(final boolean mediaStatus) {
- final boolean DEBUG = true;
- if (DEBUG) Log.i(TAG, "updateExterMediaStatus::");
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
+ mediaStatus+", mMediaMounted=" + mMediaMounted);
if (mediaStatus == mMediaMounted) {
return;
}
@@ -8432,9 +8458,6 @@
HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
int uidList[] = new int[list.length];
int num = 0;
- for (int i = 0; i < uidList.length; i++) {
- uidList[i] = Process.LAST_APPLICATION_UID;
- }
synchronized (mPackages) {
Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_ON_SDCARD);
for (String cid : list) {
@@ -8456,24 +8479,34 @@
processCids.put(args, ps.codePathString);
int uid = ps.userId;
if (uid != -1) {
- int idx = Arrays.binarySearch(uidList, uid);
- if (idx < 0) {
- uidList[-idx] = uid;
- num++;
- }
+ uidList[num++] = uid;
}
}
}
- int uidArr[] = uidList;
- if ((num > 0) && (num < uidList.length)) {
+ int uidArr[] = null;
+ if (num > 0) {
+ // Sort uid list
+ Arrays.sort(uidList, 0, num);
+ // Throw away duplicates
uidArr = new int[num];
- for (int i = 0; i < num; i++) {
- uidArr[i] = uidList[i];
+ uidArr[0] = uidList[0];
+ int di = 0;
+ for (int i = 1; i < num; i++) {
+ if (uidList[i-1] != uidList[i]) {
+ uidArr[di++] = uidList[i];
+ }
+ }
+ if (true) {
+ for (int j = 0; j < num; j++) {
+ Log.i(TAG, "uidArr[" + j + "]=" + uidArr[j]);
+ }
}
}
if (mediaStatus) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
loadMediaPackages(processCids, uidArr);
} else {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
unloadMediaPackages(processCids, uidArr);
}
}
@@ -8486,9 +8519,11 @@
Bundle extras = new Bundle();
extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
pkgList.toArray(new String[size]));
- extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
- String action = mediaStatus ? Intent.ACTION_MEDIA_RESOURCES_AVAILABLE
- : Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE;
+ if (uidArr != null) {
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
+ }
+ String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
+ : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
sendPackageBroadcast(action, null, extras);
}
}
@@ -8497,10 +8532,11 @@
ArrayList<String> pkgList = new ArrayList<String>();
Set<SdInstallArgs> keys = processCids.keySet();
for (SdInstallArgs args : keys) {
- String cid = args.cid;
String codePath = processCids.get(args);
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to install pkg : "
+ + args.cid + " from " + args.cachePath);
if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) != PackageManager.INSTALL_SUCCEEDED) {
- Log.i(TAG, "Failed to install package: " + codePath + " from sdcard");
+ Log.e(TAG, "Failed to install package: " + codePath + " from sdcard");
continue;
}
// Parse package
@@ -8511,7 +8547,8 @@
final PackageParser.Package pkg = pp.parsePackage(new File(codePath),
codePath, mMetrics, parseFlags);
if (pkg == null) {
- Log.w(TAG, "Failed to install package : " + cid + " from sd card");
+ Log.e(TAG, "Trying to install pkg : "
+ + args.cid + " from " + args.cachePath);
continue;
}
setApplicationInfoPaths(pkg, codePath, codePath);
@@ -8532,22 +8569,24 @@
}
}
args.doPostInstall(retCode);
- pkgList.add(pkg.packageName);
}
// Send broadcasts first
- sendResourcesChangedBroadcast(true, pkgList, uidArr);
- Runtime.getRuntime().gc();
- // If something failed do we clean up here or next install?
+ if (pkgList.size() > 0) {
+ sendResourcesChangedBroadcast(true, pkgList, uidArr);
+ Runtime.getRuntime().gc();
+ // If something failed do we clean up here or next install?
+ }
}
void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[]) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages");
ArrayList<String> pkgList = new ArrayList<String>();
+ ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
Set<SdInstallArgs> keys = processCids.keySet();
for (SdInstallArgs args : keys) {
String cid = args.cid;
String pkgName = args.getPackageName();
- // STOPSHIP Send broadcast to apps to remove references
- // STOPSHIP Unmount package
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to unload pkg : " + pkgName);
// Delete package internally
PackageRemovedInfo outInfo = new PackageRemovedInfo();
synchronized (mInstallLock) {
@@ -8557,14 +8596,17 @@
pkgList.add(pkgName);
} else {
Log.e(TAG, "Failed to delete pkg from sdcard : " + pkgName);
+ failedList.add(args);
}
}
}
// Send broadcasts
- sendResourcesChangedBroadcast(false, pkgList, uidArr);
- Runtime.getRuntime().gc();
+ if (pkgList.size() > 0) {
+ sendResourcesChangedBroadcast(false, pkgList, uidArr);
+ Runtime.getRuntime().gc();
+ }
// Do clean up. Just unmount
- for (SdInstallArgs args : keys) {
+ for (SdInstallArgs args : failedList) {
synchronized (mInstallLock) {
args.doPostDeleteLI(false);
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ee1cc8d..6e9c21b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -273,6 +273,17 @@
}
try {
+ /*
+ * NotificationManagerService is dependant on MountService,
+ * (for media / usb notifications) so we must start MountService first.
+ */
+ Log.i(TAG, "Mount Service");
+ ServiceManager.addService("mount", new MountService(context));
+ } catch (Throwable e) {
+ Log.e(TAG, "Failure starting Mount Service", e);
+ }
+
+ try {
Log.i(TAG, "Notification Manager");
notification = new NotificationManagerService(context, statusBar, lights);
ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);
@@ -281,14 +292,6 @@
}
try {
- // MountService must start after NotificationManagerService
- Log.i(TAG, "Mount Service");
- ServiceManager.addService("mount", new MountService(context));
- } catch (Throwable e) {
- Log.e(TAG, "Failure starting Mount Service", e);
- }
-
- try {
Log.i(TAG, "Device Storage Monitor");
ServiceManager.addService(DeviceStorageMonitorService.SERVICE,
new DeviceStorageMonitorService(context));
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 5e6881c..98ded37 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -11941,7 +11941,7 @@
intent.getAction());
if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
|| intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
- || Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(intent.getAction())
+ || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())
|| uidRemoved) {
if (checkComponentPermission(
android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
@@ -11960,7 +11960,7 @@
} else {
// If resources are unvailble just force stop all
// those packages and flush the attribute cache as well.
- if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(intent.getAction())) {
+ if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
if (list != null && (list.length > 0)) {
for (String pkg : list) {
@@ -12146,7 +12146,7 @@
skipPackages = new String[] { pkgName };
}
}
- } else if (intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(intent.getAction())) {
+ } else if (intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
}
if (skipPackages != null && (skipPackages.length > 0)) {
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index 55041fb..c7c3335 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -1813,14 +1813,14 @@
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
filter.addDataScheme("package");
mContext.registerReceiver(this, filter);
- IntentFilter sdFilter = new IntentFilter(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+ IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(this, sdFilter);
}
@Override
public void onReceive(Context context, Intent intent) {
String pkgList[] = null;
- if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(intent.getAction())) {
+ if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
} else {
Uri data = intent.getData();
diff --git a/test-runner/android/test/SyncBaseInstrumentation.java b/test-runner/android/test/SyncBaseInstrumentation.java
index e8d72d9..7d418f0 100644
--- a/test-runner/android/test/SyncBaseInstrumentation.java
+++ b/test-runner/android/test/SyncBaseInstrumentation.java
@@ -46,7 +46,7 @@
*/
protected void syncProvider(Uri uri, String accountName, String authority) throws Exception {
Bundle extras = new Bundle();
- extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+ extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
Account account = new Account(accountName, "com.google");
ContentResolver.requestSync(account, authority, extras);
diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml
index 70d0e78..2b6b81e 100644
--- a/tests/AndroidTests/AndroidManifest.xml
+++ b/tests/AndroidTests/AndroidManifest.xml
@@ -28,6 +28,7 @@
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
+ <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="com.android.unit_tests.permission.TEST_GRANTED" />
<uses-permission android:name="com.google.android.googleapps.permission.ACCESS_GOOGLE_PASSWORD" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index 163ddd5..a1370ea 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -16,6 +16,8 @@
package com.android.unit_tests;
+import android.os.IMountService.Stub;
+
import android.net.Uri;
import android.os.FileUtils;
@@ -34,7 +36,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageInstallObserver;
-import android.content.pm.IPackageStatsObserver;
+import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageStats;
@@ -51,15 +53,27 @@
import android.util.Log;
import android.os.Environment;
import android.os.Handler;
+import android.os.IBinder;
+import android.os.IMountService;
+import android.os.MountServiceResultCode;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StatFs;
public class PackageManagerTests extends AndroidTestCase {
- private static final boolean localLOGV = false;
+ private static final boolean localLOGV = true;
public static final String TAG="PackageManagerTests";
- public final long MAX_WAIT_TIME=60*1000;
- public final long WAIT_TIME_INCR=10*1000;
+ public final long MAX_WAIT_TIME=120*1000;
+ public final long WAIT_TIME_INCR=20*1000;
+
+ void failStr(String errMsg) {
+ Log.w(TAG, "errMsg="+errMsg);
+ fail(errMsg);
+ }
+ void failStr(Exception e) {
+ Log.w(TAG, "e.getMessage="+e.getMessage());
+ Log.w(TAG, "e="+e);
+ }
@Override
protected void setUp() throws Exception {
@@ -146,6 +160,7 @@
try {
// Wait on observer
synchronized(observer) {
+ synchronized (receiver) {
getPm().installPackage(packageURI, observer, flags, null);
long waitTime = 0;
while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
@@ -158,7 +173,6 @@
if (observer.returnCode != PackageManager.INSTALL_SUCCEEDED) {
return false;
}
- synchronized (receiver) {
// Verify we received the broadcast
waitTime = 0;
while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
@@ -262,6 +276,7 @@
PackageParser.Package pkg = parsePackage(packageURI);
assertNotNull(pkg);
InstallReceiver receiver = new InstallReceiver(pkg.packageName);
+ InstallParams ip = null;
try {
try {
assertTrue(invokeInstallPackage(packageURI, flags,
@@ -271,13 +286,11 @@
}
// Verify installed information
assertInstall(pkg.packageName, flags);
- return new InstallParams(pkg, outFileName, packageURI);
+ ip = new InstallParams(pkg, outFileName, packageURI);
+ return ip;
} finally {
if (cleanUp) {
- getPm().deletePackage(pkg.packageName, null, 0);
- if (outFile != null && outFile.exists()) {
- outFile.delete();
- }
+ cleanUpInstall(ip);
}
}
}
@@ -300,28 +313,52 @@
/* ------------------------- Test replacing packages --------------*/
class ReplaceReceiver extends GenericReceiver {
String pkgName;
- boolean removed = false;
+ final static int INVALID = -1;
+ final static int REMOVED = 1;
+ final static int ADDED = 2;
+ final static int REPLACED = 3;
+ int removed = INVALID;
+ // for updated system apps only
+ boolean update = false;
ReplaceReceiver(String pkgName) {
this.pkgName = pkgName;
filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ if (update) {
+ filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ }
+ filter.addDataScheme("package");
super.setFilter(filter);
}
public boolean notifyNow(Intent intent) {
String action = intent.getAction();
- if (Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
- Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
- Uri data = intent.getData();
- String installedPkg = data.getEncodedSchemeSpecificPart();
- if (pkgName.equals(installedPkg)) {
- if (removed) {
- return true;
- } else {
- removed = true;
- }
+ Uri data = intent.getData();
+ String installedPkg = data.getEncodedSchemeSpecificPart();
+ if (pkgName == null || !pkgName.equals(installedPkg)) {
+ return false;
+ }
+ if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ removed = REMOVED;
+ } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ if (removed != REMOVED) {
+ return false;
}
+ boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+ if (!replacing) {
+ return false;
+ }
+ removed = ADDED;
+ if (!update) {
+ return true;
+ }
+ } else if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
+ if (removed != ADDED) {
+ return false;
+ }
+ removed = REPLACED;
+ return true;
}
return false;
}
@@ -335,29 +372,26 @@
*/
public void replaceFromRawResource(int flags) {
InstallParams ip = installFromRawResource(flags, false);
- boolean result = ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0);
+ boolean replace = ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0);
GenericReceiver receiver;
- if (result) {
+ if (replace) {
receiver = new ReplaceReceiver(ip.pkg.packageName);
+ Log.i(TAG, "Creating replaceReceiver");
} else {
receiver = new InstallReceiver(ip.pkg.packageName);
}
try {
try {
assertEquals(invokeInstallPackage(ip.packageURI, flags,
- ip.pkg.packageName, receiver), result);
- if (result) {
+ ip.pkg.packageName, receiver), replace);
+ if (replace) {
assertInstall(ip.pkg.packageName, flags);
}
} catch (Exception e) {
failStr("Failed with exception : " + e);
}
} finally {
- getPm().deletePackage(ip.pkg.packageName, null, 0);
- File outFile = new File(ip.outFileName);
- if (outFile != null && outFile.exists()) {
- outFile.delete();
- }
+ cleanUpInstall(ip);
}
}
@@ -376,12 +410,362 @@
replaceFromRawResource(PackageManager.INSTALL_ON_SDCARD);
}
- void failStr(String errMsg) {
- Log.w(TAG, "errMsg="+errMsg);
- fail(errMsg);
+ @MediumTest
+ public void testReplaceNormalInternal() {
+ replaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING);
}
- void failStr(Exception e) {
- Log.w(TAG, "e.getMessage="+e.getMessage());
- Log.w(TAG, "e="+e);
+
+ @MediumTest
+ public void testReplaceFwdLockedInternal() {
+ replaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
+ PackageManager.INSTALL_FORWARD_LOCK);
}
+
+ @MediumTest
+ public void testReplaceSdcard() {
+ replaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
+ PackageManager.INSTALL_ON_SDCARD);
+ }
+
+ /* -------------- Delete tests ---*/
+ class DeleteObserver extends IPackageDeleteObserver.Stub {
+
+ public boolean succeeded;
+ private boolean doneFlag = false;
+
+ public boolean isDone() {
+ return doneFlag;
+ }
+
+ public void packageDeleted(boolean succeeded) throws RemoteException {
+ synchronized(this) {
+ this.succeeded = succeeded;
+ doneFlag = true;
+ notifyAll();
+ }
+ }
+ }
+
+ class DeleteReceiver extends GenericReceiver {
+ String pkgName;
+
+ DeleteReceiver(String pkgName) {
+ this.pkgName = pkgName;
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ super.setFilter(filter);
+ }
+
+ public boolean notifyNow(Intent intent) {
+ String action = intent.getAction();
+ if (!Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ return false;
+ }
+ Uri data = intent.getData();
+ String installedPkg = data.getEncodedSchemeSpecificPart();
+ if (pkgName.equals(installedPkg)) {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ public boolean invokeDeletePackage(Uri packageURI, int flags,
+ final String pkgName, GenericReceiver receiver) throws Exception {
+ DeleteObserver observer = new DeleteObserver();
+ final boolean received = false;
+ mContext.registerReceiver(receiver, receiver.filter);
+ try {
+ // Wait on observer
+ synchronized(observer) {
+ synchronized (receiver) {
+ getPm().deletePackage(pkgName, observer, flags);
+ long waitTime = 0;
+ while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+ observer.wait(WAIT_TIME_INCR);
+ waitTime += WAIT_TIME_INCR;
+ }
+ if(!observer.isDone()) {
+ throw new Exception("Timed out waiting for packageInstalled callback");
+ }
+ // Verify we received the broadcast
+ waitTime = 0;
+ while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+ receiver.wait(WAIT_TIME_INCR);
+ waitTime += WAIT_TIME_INCR;
+ }
+ if(!receiver.isDone()) {
+ throw new Exception("Timed out waiting for PACKAGE_ADDED notification");
+ }
+ return receiver.received;
+ }
+ }
+ } finally {
+ mContext.unregisterReceiver(receiver);
+ }
+ }
+
+ public void deleteFromRawResource(int iFlags, int dFlags) {
+ InstallParams ip = installFromRawResource(iFlags, false);
+ boolean retainData = ((dFlags & PackageManager.DONT_DELETE_DATA) != 0);
+ GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
+ DeleteObserver observer = new DeleteObserver();
+ try {
+ assertTrue(invokeDeletePackage(ip.packageURI, dFlags,
+ ip.pkg.packageName, receiver));
+ ApplicationInfo info = null;
+ Log.i(TAG, "okay4");
+ try {
+ info = getPm().getApplicationInfo(ip.pkg.packageName,
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+ } catch (NameNotFoundException e) {
+ info = null;
+ }
+ if (retainData) {
+ assertNotNull(info);
+ assertEquals(info.packageName, ip.pkg.packageName);
+ File file = new File(info.dataDir);
+ assertTrue(file.exists());
+ } else {
+ assertNull(info);
+ }
+ } catch (Exception e) {
+ failStr(e);
+ } finally {
+ cleanUpInstall(ip);
+ }
+ }
+
+ @MediumTest
+ public void testDeleteNormalInternal() {
+ deleteFromRawResource(0, 0);
+ }
+
+ @MediumTest
+ public void testDeleteFwdLockedInternal() {
+ deleteFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, 0);
+ }
+
+ @MediumTest
+ public void testDeleteSdcard() {
+ deleteFromRawResource(PackageManager.INSTALL_ON_SDCARD, 0);
+ }
+
+ @MediumTest
+ public void testDeleteNormalInternalRetainData() {
+ deleteFromRawResource(0, PackageManager.DONT_DELETE_DATA);
+ }
+
+ @MediumTest
+ public void testDeleteFwdLockedInternalRetainData() {
+ deleteFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, PackageManager.DONT_DELETE_DATA);
+ }
+
+ @MediumTest
+ public void testDeleteSdcardRetainData() {
+ deleteFromRawResource(PackageManager.INSTALL_ON_SDCARD, PackageManager.DONT_DELETE_DATA);
+ }
+
+ /* sdcard mount/unmount tests ******/
+
+ class SdMountReceiver extends GenericReceiver {
+ String pkgNames[];
+ boolean status = true;
+
+ SdMountReceiver(String[] pkgNames) {
+ this.pkgNames = pkgNames;
+ IntentFilter filter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ super.setFilter(filter);
+ }
+
+ public boolean notifyNow(Intent intent) {
+ Log.i(TAG, "okay 1");
+ String action = intent.getAction();
+ if (!Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
+ return false;
+ }
+ String rpkgList[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ for (String pkg : pkgNames) {
+ boolean found = false;
+ for (String rpkg : rpkgList) {
+ if (rpkg.equals(pkg)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ status = false;
+ return true;
+ }
+ }
+ return true;
+ }
+ }
+
+ class SdUnMountReceiver extends GenericReceiver {
+ String pkgNames[];
+ boolean status = true;
+
+ SdUnMountReceiver(String[] pkgNames) {
+ this.pkgNames = pkgNames;
+ IntentFilter filter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ super.setFilter(filter);
+ }
+
+ public boolean notifyNow(Intent intent) {
+ String action = intent.getAction();
+ if (!Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+ return false;
+ }
+ String rpkgList[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ for (String pkg : pkgNames) {
+ boolean found = false;
+ for (String rpkg : rpkgList) {
+ if (rpkg.equals(pkg)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ status = false;
+ return true;
+ }
+ }
+ return true;
+ }
+ }
+
+ IMountService getMs() {
+ IBinder service = ServiceManager.getService("mount");
+ if (service != null) {
+ return IMountService.Stub.asInterface(service);
+ } else {
+ Log.e(TAG, "Can't get mount service");
+ }
+ return null;
+ }
+
+ boolean getMediaState() {
+ try {
+ String mPath = Environment.getExternalStorageDirectory().toString();
+ String state = getMs().getVolumeState(mPath);
+ return Environment.MEDIA_MOUNTED.equals(state);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ boolean mountMedia() {
+ if (getMediaState()) {
+ return true;
+ }
+ try {
+ String mPath = Environment.getExternalStorageDirectory().toString();
+ int ret = getMs().mountVolume(mPath);
+ return ret == MountServiceResultCode.OperationSucceeded;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ private boolean unmountMedia() {
+ if (!getMediaState()) {
+ return true;
+ }
+ try {
+ String mPath = Environment.getExternalStorageDirectory().toString();
+ int ret = getMs().unmountVolume(mPath);
+ return ret == MountServiceResultCode.OperationSucceeded;
+ } catch (RemoteException e) {
+ return true;
+ }
+ }
+
+ /*
+ * Install package on sdcard. Unmount and then mount the media.
+ * (Use PackageManagerService private api for now)
+ * Make sure the installed package is available.
+ * STOPSHIP will uncomment when MountService api's to mount/unmount
+ * are made asynchronous.
+ */
+ public void xxxtestMountSdNormalInternal() {
+ assertTrue(mountFromRawResource());
+ }
+
+ private boolean mountFromRawResource() {
+ // Install pkg on sdcard
+ InstallParams ip = installFromRawResource(PackageManager.INSTALL_ON_SDCARD |
+ PackageManager.INSTALL_REPLACE_EXISTING, false);
+ if (localLOGV) Log.i(TAG, "Installed pkg on sdcard");
+ boolean origState = getMediaState();
+ SdMountReceiver receiver = new SdMountReceiver(new String[]{ip.pkg.packageName});
+ try {
+ if (localLOGV) Log.i(TAG, "Unmounting media");
+ // Unmount media
+ assertTrue(unmountMedia());
+ if (localLOGV) Log.i(TAG, "Unmounted media");
+ try {
+ if (localLOGV) Log.i(TAG, "Sleeping for 10 second");
+ Thread.sleep(10*1000);
+ } catch (InterruptedException e) {
+ failStr(e);
+ }
+ // Register receiver here
+ PackageManager pm = getPm();
+ mContext.registerReceiver(receiver, receiver.filter);
+
+ // Wait on receiver
+ synchronized (receiver) {
+ if (localLOGV) Log.i(TAG, "Mounting media");
+ // Mount media again
+ assertTrue(mountMedia());
+ if (localLOGV) Log.i(TAG, "Mounted media");
+ if (localLOGV) Log.i(TAG, "Waiting for notification");
+ long waitTime = 0;
+ // Verify we received the broadcast
+ waitTime = 0;
+ while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+ receiver.wait(WAIT_TIME_INCR);
+ waitTime += WAIT_TIME_INCR;
+ }
+ if(!receiver.isDone()) {
+ failStr("Timed out waiting for EXTERNAL_APPLICATIONS notification");
+ }
+ return receiver.received;
+ }
+ } catch (InterruptedException e) {
+ failStr(e);
+ return false;
+ } finally {
+ mContext.unregisterReceiver(receiver);
+ // Restore original media state
+ if (origState) {
+ mountMedia();
+ } else {
+ unmountMedia();
+ }
+ if (localLOGV) Log.i(TAG, "Cleaning up install");
+ cleanUpInstall(ip);
+ }
+ }
+
+ void cleanUpInstall(InstallParams ip) {
+ if (ip == null) {
+ return;
+ }
+ Runtime.getRuntime().gc();
+ Log.i(TAG, "Deleting package : " + ip.pkg.packageName);
+ getPm().deletePackage(ip.pkg.packageName, null, 0);
+ File outFile = new File(ip.outFileName);
+ if (outFile != null && outFile.exists()) {
+ outFile.delete();
+ }
+ }
+ /*
+ * TODO's
+ * check version numbers for upgrades
+ * check permissions of installed packages
+ * how to do tests on updated system apps?
+ * verify updates to system apps cannot be installed on the sdcard.
+ */
}