summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--api/current.txt98
-rw-r--r--core/java/android/app/Application.java5
-rw-r--r--core/java/android/content/Context.java9
-rw-r--r--core/java/android/content/Intent.java25
-rw-r--r--core/java/android/hardware/location/GeofenceHardware.java178
-rw-r--r--core/java/android/hardware/location/GeofenceHardwareCallback.java15
-rw-r--r--core/java/android/hardware/location/GeofenceHardwareImpl.java178
-rw-r--r--core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java37
-rw-r--r--core/java/android/hardware/location/GeofenceHardwareRequest.java158
-rw-r--r--core/java/android/hardware/location/GeofenceHardwareService.java31
-rw-r--r--core/java/android/hardware/location/IGeofenceHardware.aidl16
-rw-r--r--core/java/android/hardware/location/IGeofenceHardwareCallback.aidl3
-rw-r--r--core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl24
-rw-r--r--core/java/android/os/IUserManager.aidl5
-rw-r--r--core/java/android/os/UserManager.java25
-rw-r--r--core/java/android/provider/Settings.java6
-rw-r--r--core/java/android/view/Surface.java6
-rw-r--r--core/java/android/view/SurfaceView.java34
-rw-r--r--core/java/android/view/View.java22
-rw-r--r--core/java/android/widget/RemoteViews.java2
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java20
-rw-r--r--core/jni/android/graphics/TextLayoutCache.cpp28
-rw-r--r--core/jni/android/graphics/TextLayoutCache.h9
-rw-r--r--core/res/AndroidManifest.xml3
-rw-r--r--core/res/res/values/config.xml6
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--data/keyboards/Vendor_0079_Product_0011.kl23
-rw-r--r--data/keyboards/Vendor_045e_Product_028e.kl4
-rw-r--r--data/keyboards/Vendor_046d_Product_c219.kl35
-rw-r--r--data/keyboards/Vendor_046d_Product_c21f.kl36
-rw-r--r--data/keyboards/Vendor_054c_Product_0268.kl10
-rw-r--r--data/keyboards/Vendor_0583_Product_2060.kl27
-rw-r--r--data/keyboards/Vendor_0a5c_Product_8502.kl33
-rw-r--r--data/keyboards/Vendor_1038_Product_1412.kl31
-rw-r--r--data/keyboards/Vendor_12bd_Product_d015.kl27
-rw-r--r--data/keyboards/Vendor_1689_Product_fd00.kl38
-rw-r--r--data/keyboards/Vendor_1689_Product_fd01.kl36
-rw-r--r--data/keyboards/Vendor_1689_Product_fe00.kl36
-rw-r--r--data/keyboards/Vendor_1bad_Product_f016.kl36
-rw-r--r--data/keyboards/Vendor_1bad_Product_f023.kl35
-rw-r--r--data/keyboards/Vendor_1bad_Product_f027.kl36
-rw-r--r--data/keyboards/Vendor_1bad_Product_f036.kl36
-rw-r--r--data/keyboards/Vendor_1d79_Product_0009.kl36
-rw-r--r--data/keyboards/Vendor_2378_Product_100a.kl35
-rw-r--r--docs/html/images/mediadrm_decryption_sequence.pngbin0 -> 67604 bytes
-rw-r--r--docs/html/images/mediadrm_overview.pngbin0 -> 35383 bytes
-rw-r--r--media/java/android/media/MediaDrm.java437
-rw-r--r--media/java/android/media/MediaDrmException.java2
-rw-r--r--media/java/android/media/RemoteControlClient.java21
-rw-r--r--media/jni/android_media_MediaDrm.cpp16
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java6
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindowManager.java31
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java26
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java2
-rw-r--r--services/java/com/android/server/LockSettingsService.java91
-rw-r--r--services/java/com/android/server/NotificationManagerService.java6
-rw-r--r--services/java/com/android/server/am/NativeCrashListener.java18
-rw-r--r--services/java/com/android/server/pm/UserManagerService.java60
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java1
-rw-r--r--tests/CanvasCompare/AndroidManifest.xml3
-rw-r--r--tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java244
-rw-r--r--tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java4
63 files changed, 2003 insertions, 460 deletions
diff --git a/Android.mk b/Android.mk
index 8115472..bd88877 100644
--- a/Android.mk
+++ b/Android.mk
@@ -126,6 +126,7 @@ LOCAL_SRC_FILES += \
core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
core/java/android/hardware/location/IGeofenceHardware.aidl \
core/java/android/hardware/location/IGeofenceHardwareCallback.aidl \
+ core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
core/java/android/hardware/usb/IUsbManager.aidl \
core/java/android/net/IConnectivityManager.aidl \
core/java/android/net/INetworkManagementEventObserver.aidl \
diff --git a/api/current.txt b/api/current.txt
index 082a395..ce3a0f0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5613,7 +5613,6 @@ package android.content {
method public abstract java.lang.String[] fileList();
method public abstract android.content.Context getApplicationContext();
method public abstract android.content.pm.ApplicationInfo getApplicationInfo();
- method public java.util.List<android.content.RestrictionEntry> getApplicationRestrictions();
method public abstract android.content.res.AssetManager getAssets();
method public abstract java.io.File getCacheDir();
method public abstract java.lang.ClassLoader getClassLoader();
@@ -6200,8 +6199,9 @@ package android.content {
field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
field public static final java.lang.String EXTRA_REMOTE_INTENT_TOKEN = "android.intent.extra.remote_intent_token";
field public static final java.lang.String EXTRA_REPLACING = "android.intent.extra.REPLACING";
- field public static final java.lang.String EXTRA_RESTRICTIONS = "android.intent.extra.restrictions";
+ field public static final java.lang.String EXTRA_RESTRICTIONS_BUNDLE = "android.intent.extra.restrictions_bundle";
field public static final java.lang.String EXTRA_RESTRICTIONS_INTENT = "android.intent.extra.restrictions_intent";
+ field public static final java.lang.String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
field public static final java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
field public static final java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
@@ -10471,13 +10471,14 @@ package android.hardware.input {
package android.hardware.location {
public final class GeofenceHardware {
- method public boolean addCircularFence(int, double, double, double, int, int, int, int, int, android.hardware.location.GeofenceHardwareCallback);
- method public int[] getMonitoringTypesAndStatus();
+ method public boolean addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback);
+ method public int[] getMonitoringTypes();
+ method public int getStatusOfMonitoringType(int);
method public boolean pauseGeofence(int, int);
- method public boolean registerForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareCallback);
+ method public boolean registerForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback);
method public boolean removeGeofence(int, int);
method public boolean resumeGeofence(int, int, int);
- method public boolean unregisterForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareCallback);
+ method public boolean unregisterForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback);
field public static final int GEOFENCE_ENTERED = 1; // 0x1
field public static final int GEOFENCE_ERROR_ID_EXISTS = 2; // 0x2
field public static final int GEOFENCE_ERROR_ID_UNKNOWN = 3; // 0x3
@@ -10496,13 +10497,33 @@ package android.hardware.location {
public abstract class GeofenceHardwareCallback {
ctor public GeofenceHardwareCallback();
method public void onGeofenceAdd(int, int);
- method public void onGeofenceChange(int, int, android.location.Location, long, int);
method public void onGeofencePause(int, int);
method public void onGeofenceRemove(int, int);
method public void onGeofenceResume(int, int);
+ method public void onGeofenceTransition(int, int, android.location.Location, long, int);
+ }
+
+ public abstract class GeofenceHardwareMonitorCallback {
+ ctor public GeofenceHardwareMonitorCallback();
method public void onMonitoringSystemChange(int, boolean, android.location.Location);
}
+ public final class GeofenceHardwareRequest {
+ ctor public GeofenceHardwareRequest();
+ method public static android.hardware.location.GeofenceHardwareRequest createCircularGeofence(double, double, double);
+ method public int getLastTransition();
+ method public double getLatitude();
+ method public double getLongitude();
+ method public int getMonitorTransitions();
+ method public int getNotificationResponsiveness();
+ method public double getRadius();
+ method public int getUnknownTimer();
+ method public void setLastTransition(int);
+ method public void setMonitorTransitions(int);
+ method public void setNotificationResponsiveness(int);
+ method public void setUnknownTimer(int);
+ }
+
}
package android.hardware.usb {
@@ -11796,6 +11817,66 @@ package android.media {
ctor public MediaCryptoException(java.lang.String);
}
+ public final class MediaDrm {
+ ctor public MediaDrm(java.util.UUID) throws android.media.MediaDrmException;
+ method public void closeSession(byte[]);
+ method public android.media.MediaDrm.CryptoSession getCryptoSession(byte[], java.lang.String, java.lang.String);
+ method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>);
+ method public byte[] getPropertyByteArray(java.lang.String);
+ method public java.lang.String getPropertyString(java.lang.String);
+ method public android.media.MediaDrm.ProvisionRequest getProvisionRequest();
+ method public java.util.List<byte[]> getSecureStops();
+ method public static final boolean isCryptoSchemeSupported(java.util.UUID);
+ method public byte[] openSession();
+ method public byte[] provideKeyResponse(byte[], byte[]);
+ method public void provideProvisionResponse(byte[]);
+ method public java.util.HashMap<java.lang.String, java.lang.String> queryKeyStatus(byte[]);
+ method public final void release();
+ method public void releaseSecureStops(byte[]);
+ method public void removeKeys(byte[]);
+ method public void restoreKeys(byte[], byte[]);
+ method public void setOnEventListener(android.media.MediaDrm.OnEventListener);
+ method public void setPropertyByteArray(java.lang.String, byte[]);
+ method public void setPropertyString(java.lang.String, java.lang.String);
+ field public static final int EVENT_KEY_EXPIRED = 3; // 0x3
+ field public static final int EVENT_KEY_REQUIRED = 2; // 0x2
+ field public static final int EVENT_PROVISION_REQUIRED = 1; // 0x1
+ field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
+ field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
+ field public static final int KEY_TYPE_RELEASE = 3; // 0x3
+ field public static final int KEY_TYPE_STREAMING = 1; // 0x1
+ field public static final java.lang.String PROPERTY_ALGORITHM = "algorithm";
+ field public static final java.lang.String PROPERTY_DESCRIPTION = "description";
+ field public static final java.lang.String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
+ field public static final java.lang.String PROPERTY_VENDOR = "vendor";
+ field public static final java.lang.String PROPERTY_VERSION = "version";
+ }
+
+ public final class MediaDrm.CryptoSession {
+ method public byte[] decrypt(byte[], byte[], byte[]);
+ method public byte[] encrypt(byte[], byte[], byte[]);
+ method public byte[] sign(byte[], byte[]);
+ method public boolean verify(byte[], byte[], byte[]);
+ }
+
+ public static final class MediaDrm.KeyRequest {
+ method public byte[] getData();
+ method public java.lang.String getDefaultUrl();
+ }
+
+ public static abstract interface MediaDrm.OnEventListener {
+ method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]);
+ }
+
+ public static final class MediaDrm.ProvisionRequest {
+ method public byte[] getData();
+ method public java.lang.String getDefaultUrl();
+ }
+
+ public final class MediaDrmException extends java.lang.Exception {
+ ctor public MediaDrmException(java.lang.String);
+ }
+
public final class MediaExtractor {
ctor public MediaExtractor();
method public boolean advance();
@@ -17551,7 +17632,7 @@ package android.os {
}
public class UserManager {
- method public static synchronized android.os.UserManager get(android.content.Context);
+ method public android.os.Bundle getApplicationRestrictions(java.lang.String);
method public long getSerialNumberForUser(android.os.UserHandle);
method public int getUserCount();
method public android.os.UserHandle getUserForSerialNumber(long);
@@ -30044,7 +30125,6 @@ package android.widget {
method public void setRelativeScrollPosition(int, int);
method public deprecated void setRemoteAdapter(int, int, android.content.Intent);
method public void setRemoteAdapter(int, android.content.Intent);
- method public void setRemoteAdapter(int, java.util.ArrayList<android.widget.RemoteViews>, int);
method public void setScrollPosition(int, int);
method public void setShort(int, java.lang.String, short);
method public void setString(int, java.lang.String, java.lang.String);
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 7b07438..0d7f0a7 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -134,11 +134,6 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {
}
}
- public List<RestrictionEntry> getApplicationRestrictions() {
- return ((UserManager) getSystemService(USER_SERVICE))
- .getApplicationRestrictions(getPackageName(), android.os.Process.myUserHandle());
- }
-
public void registerComponentCallbacks(ComponentCallbacks callback) {
synchronized (mComponentCallbacks) {
mComponentCallbacks.add(callback);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 03e241a..5bd28b9 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -293,15 +293,6 @@ public abstract class Context {
public abstract Context getApplicationContext();
/**
- * Returns the list of restrictions for the application, or null if there are no
- * restrictions.
- * @return
- */
- public List<RestrictionEntry> getApplicationRestrictions() {
- return getApplicationContext().getApplicationRestrictions();
- }
-
- /**
* Add a new {@link ComponentCallbacks} to the base application of the
* Context, which will be called at the same times as the ComponentCallbacks
* methods of activities and other components are called. Note that you
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 97ad7dd..1ab1eb8 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2417,11 +2417,16 @@ public class Intent implements Parcelable, Cloneable {
/**
* Broadcast to a specific application to query any supported restrictions to impose
- * on restricted users. The response should contain an extra {@link #EXTRA_RESTRICTIONS},
+ * on restricted users. The broadcast intent contains an extra
+ * {@link #EXTRA_RESTRICTIONS_BUNDLE} with the currently persisted
+ * restrictions as a Bundle of key/value pairs. The value types can be Boolean, String or
+ * String[] depending on the restriction type.<p/>
+ * The response should contain an extra {@link #EXTRA_RESTRICTIONS_LIST},
* which is of type <code>ArrayList&lt;RestrictionEntry&gt;</code>. It can also
* contain an extra {@link #EXTRA_RESTRICTIONS_INTENT}, which is of type <code>Intent</code>.
* The activity specified by that intent will be launched for a result which must contain
- * the extra {@link #EXTRA_RESTRICTIONS}. The returned restrictions will be persisted.
+ * the extra {@link #EXTRA_RESTRICTIONS_LIST}. The keys and values of the returned restrictions
+ * will be persisted.
* @see RestrictionEntry
*/
public static final String ACTION_GET_RESTRICTION_ENTRIES =
@@ -3160,7 +3165,8 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.extra.ALLOW_MULTIPLE";
/**
- * The userHandle carried with broadcast intents related to addition, removal and switching of users
+ * The userHandle carried with broadcast intents related to addition, removal and switching of
+ * users
* - {@link #ACTION_USER_ADDED}, {@link #ACTION_USER_REMOVED} and {@link #ACTION_USER_SWITCHED}.
* @hide
*/
@@ -3169,9 +3175,18 @@ public class Intent implements Parcelable, Cloneable {
/**
* Extra used in the response from a BroadcastReceiver that handles
- * {@link #ACTION_GET_RESTRICTION_ENTRIES}.
+ * {@link #ACTION_GET_RESTRICTION_ENTRIES}. The type of the extra is
+ * <code>ArrayList&lt;RestrictionEntry&gt;</code>.
+ */
+ public static final String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
+
+ /**
+ * Extra sent in the intent to the BroadcastReceiver that handles
+ * {@link #ACTION_GET_RESTRICTION_ENTRIES}. The type of the extra is a Bundle containing
+ * the restrictions as key/value pairs.
*/
- public static final String EXTRA_RESTRICTIONS = "android.intent.extra.restrictions";
+ public static final String EXTRA_RESTRICTIONS_BUNDLE =
+ "android.intent.extra.restrictions_bundle";
/**
* Extra used in the response from a BroadcastReceiver that handles
diff --git a/core/java/android/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java
index 35bbb9c..e67d0d7 100644
--- a/core/java/android/hardware/location/GeofenceHardware.java
+++ b/core/java/android/hardware/location/GeofenceHardware.java
@@ -129,6 +129,9 @@ public final class GeofenceHardware {
private HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>
mCallbacks = new HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>();
+ private HashMap<GeofenceHardwareMonitorCallback, GeofenceHardwareMonitorCallbackWrapper>
+ mMonitorCallbacks = new HashMap<GeofenceHardwareMonitorCallback,
+ GeofenceHardwareMonitorCallbackWrapper>();
/**
* @hide
*/
@@ -137,8 +140,29 @@ public final class GeofenceHardware {
}
/**
- * Returns all the hardware geofence monitoring systems and their status.
- * Status can be one of {@link #MONITOR_CURRENTLY_AVAILABLE},
+ * Returns all the hardware geofence monitoring systems which are supported
+ *
+ * <p> Call {@link #getStatusOfMonitoringType(int)} to know the current state
+ * of a monitoring system.
+ *
+ * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
+ * geofencing in hardware.
+ *
+ * @return An array of all the monitoring types.
+ * An array of length 0 is returned in case of errors.
+ */
+ public int[] getMonitoringTypes() {
+ try {
+ return mService.getMonitoringTypes();
+ } catch (RemoteException e) {
+ }
+ return new int[0];
+ }
+
+ /**
+ * Returns current status of a hardware geofence monitoring system.
+ *
+ * <p>Status can be one of {@link #MONITOR_CURRENTLY_AVAILABLE},
* {@link #MONITOR_CURRENTLY_UNAVAILABLE} or {@link #MONITOR_UNSUPPORTED}
*
* <p> Some supported hardware monitoring systems might not be available
@@ -147,18 +171,15 @@ public final class GeofenceHardware {
* geofences and will change from {@link #MONITOR_CURRENTLY_AVAILABLE} to
* {@link #MONITOR_CURRENTLY_UNAVAILABLE}.
*
- * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
- * geofencing in hardware.
- *
- * @return An array indexed by the various monitoring types and their status.
- * An array of length 0 is returned in case of errors.
+ * @param monitoringType
+ * @return Current status of the monitoring type.
*/
- public int[] getMonitoringTypesAndStatus() {
+ public int getStatusOfMonitoringType(int monitoringType) {
try {
- return mService.getMonitoringTypesAndStatus();
+ return mService.getStatusOfMonitoringType(monitoringType);
} catch (RemoteException e) {
+ return MONITOR_UNSUPPORTED;
}
- return new int[0];
}
/**
@@ -167,8 +188,10 @@ public final class GeofenceHardware {
* <p> When the device detects that is has entered, exited or is uncertain
* about the area specified by the geofence, the given callback will be called.
*
- * <p> The {@link GeofenceHardwareCallback#onGeofenceChange} callback will be called,
- * with the following parameters
+ * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+ * {@link GeofenceHardwareCallback#onGeofenceAdd} will be called with the result of the
+ * add call from the hardware. The {@link GeofenceHardwareCallback#onGeofenceAdd} will be
+ * called with the following parameters when a transition event occurs.
* <ul>
* <li> The geofence Id
* <li> The location object indicating the last known location.
@@ -195,43 +218,46 @@ public final class GeofenceHardware {
* which abstracts the hardware should be used instead. All the checks are done by the higher
* level public API. Any needed locking should be handled by the higher level API.
*
- * @param latitude Latitude of the area to be monitored.
- * @param longitude Longitude of the area to be monitored.
- * @param radius Radius (in meters) of the area to be monitored.
- * @param lastTransition The current state of the geofence. Can be one of
- * {@link #GEOFENCE_ENTERED}, {@link #GEOFENCE_EXITED},
- * {@link #GEOFENCE_UNCERTAIN}.
- * @param monitorTransitions Bitwise OR of {@link #GEOFENCE_ENTERED},
- * {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
- * @param notificationResponsivenes Defines the best-effort description
- * of how soon should the callback be called when the transition
- * associated with the Geofence is triggered. For instance, if
- * set to 1000 millseconds with {@link #GEOFENCE_ENTERED},
- * the callback will be called 1000 milliseconds within entering
- * the geofence. This parameter is defined in milliseconds.
- * @param unknownTimer The time limit after which the
- * {@link #GEOFENCE_UNCERTAIN} transition
- * should be triggered. This paramter is defined in milliseconds.
+ * <p> Create a geofence request object using the methods in {@link GeofenceHardwareRequest} to
+ * set all the characteristics of the geofence. Use the created GeofenceHardwareRequest object
+ * in this call.
+ *
+ * @param geofenceId The id associated with the geofence.
* @param monitoringType The type of the hardware subsystem that should be used
* to monitor the geofence.
+ * @param geofenceRequest The {@link GeofenceHardwareRequest} object associated with the
+ * geofence.
* @param callback {@link GeofenceHardwareCallback} that will be use to notify the
* transition.
- * @return true on success.
+ * @return true when the geofence is successfully sent to the hardware for addition.
+ * @throws IllegalArgumentException when the geofence request type is not supported.
*/
- public boolean addCircularFence(int geofenceId, double latitude, double longitude,
- double radius, int lastTransition,int monitorTransitions, int notificationResponsivenes,
- int unknownTimer, int monitoringType, GeofenceHardwareCallback callback) {
+ public boolean addGeofence(int geofenceId, int monitoringType, GeofenceHardwareRequest
+ geofenceRequest, GeofenceHardwareCallback callback) {
try {
- return mService.addCircularFence(geofenceId, latitude, longitude, radius,
- lastTransition, monitorTransitions, notificationResponsivenes, unknownTimer,
- monitoringType, getCallbackWrapper(callback));
+ if (geofenceRequest.getType() == GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) {
+ return mService.addCircularFence(geofenceId, monitoringType,
+ geofenceRequest.getLatitude(),
+ geofenceRequest.getLongitude(), geofenceRequest.getRadius(),
+ geofenceRequest.getLastTransition(),
+ geofenceRequest.getMonitorTransitions(),
+ geofenceRequest.getNotificationResponsiveness(),
+ geofenceRequest.getUnknownTimer(),
+ getCallbackWrapper(callback));
+ } else {
+ throw new IllegalArgumentException("Geofence Request type not supported");
+ }
} catch (RemoteException e) {
}
return false;
}
/**
- * Removes a geofence added by {@link #addCircularFence} call.
+ * Removes a geofence added by {@link #addGeofence} call.
+ *
+ * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+ * {@link GeofenceHardwareCallback#onGeofenceRemove} will be called with the result of the
+ * remove call from the hardware.
*
* <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
* {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
@@ -246,7 +272,7 @@ public final class GeofenceHardware {
* @param geofenceId The id of the geofence.
* @param monitoringType The type of the hardware subsystem that should be used
* to monitor the geofence.
- * @return true on success.
+ * @return true when the geofence is successfully sent to the hardware for removal. .
*/
public boolean removeGeofence(int geofenceId, int monitoringType) {
try {
@@ -257,7 +283,11 @@ public final class GeofenceHardware {
}
/**
- * Pauses the monitoring of a geofence added by {@link #addCircularFence} call.
+ * Pauses the monitoring of a geofence added by {@link #addGeofence} call.
+ *
+ * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+ * {@link GeofenceHardwareCallback#onGeofencePause} will be called with the result of the
+ * pause call from the hardware.
*
* <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
* {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
@@ -272,7 +302,7 @@ public final class GeofenceHardware {
* @param geofenceId The id of the geofence.
* @param monitoringType The type of the hardware subsystem that should be used
* to monitor the geofence.
- * @return true on success.
+ * @return true when the geofence is successfully sent to the hardware for pausing.
*/
public boolean pauseGeofence(int geofenceId, int monitoringType) {
try {
@@ -285,6 +315,10 @@ public final class GeofenceHardware {
/**
* Resumes the monitoring of a geofence added by {@link #pauseGeofence} call.
*
+ * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+ * {@link GeofenceHardwareCallback#onGeofenceResume} will be called with the result of the
+ * resume call from the hardware.
+ *
* <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
* {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
*
@@ -296,15 +330,15 @@ public final class GeofenceHardware {
* level public API. Any needed locking should be handled by the higher level API.
*
* @param geofenceId The id of the geofence.
- * @param monitorTransition Bitwise OR of {@link #GEOFENCE_ENTERED},
- * {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
* @param monitoringType The type of the hardware subsystem that should be used
* to monitor the geofence.
- * @return true on success.
+ * @param monitorTransition Bitwise OR of {@link #GEOFENCE_ENTERED},
+ * {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
+ * @return true when the geofence is successfully sent to the hardware for resumption.
*/
- public boolean resumeGeofence(int geofenceId, int monitorTransition, int monitoringType) {
+ public boolean resumeGeofence(int geofenceId, int monitoringType, int monitorTransition) {
try {
- return mService.resumeGeofence(geofenceId, monitorTransition, monitoringType);
+ return mService.resumeGeofence(geofenceId, monitoringType, monitorTransition);
} catch (RemoteException e) {
}
return false;
@@ -333,10 +367,10 @@ public final class GeofenceHardware {
* @return true on success
*/
public boolean registerForMonitorStateChangeCallback(int monitoringType,
- GeofenceHardwareCallback callback) {
+ GeofenceHardwareMonitorCallback callback) {
try {
return mService.registerForMonitorStateChangeCallback(monitoringType,
- getCallbackWrapper(callback));
+ getMonitorCallbackWrapper(callback));
} catch (RemoteException e) {
}
return false;
@@ -361,12 +395,12 @@ public final class GeofenceHardware {
* @return true on success
*/
public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
- GeofenceHardwareCallback callback) {
+ GeofenceHardwareMonitorCallback callback) {
boolean result = false;
try {
result = mService.unregisterForMonitorStateChangeCallback(monitoringType,
- getCallbackWrapper(callback));
- if (result) removeCallback(callback);
+ getMonitorCallbackWrapper(callback));
+ if (result) removeMonitorCallback(callback);
} catch (RemoteException e) {
}
@@ -391,24 +425,50 @@ public final class GeofenceHardware {
}
}
- class GeofenceHardwareCallbackWrapper extends IGeofenceHardwareCallback.Stub {
- private WeakReference<GeofenceHardwareCallback> mCallback;
+ private void removeMonitorCallback(GeofenceHardwareMonitorCallback callback) {
+ synchronized (mMonitorCallbacks) {
+ mMonitorCallbacks.remove(callback);
+ }
+ }
- GeofenceHardwareCallbackWrapper(GeofenceHardwareCallback c) {
- mCallback = new WeakReference<GeofenceHardwareCallback>(c);
+ private GeofenceHardwareMonitorCallbackWrapper getMonitorCallbackWrapper(
+ GeofenceHardwareMonitorCallback callback) {
+ synchronized (mMonitorCallbacks) {
+ GeofenceHardwareMonitorCallbackWrapper wrapper = mMonitorCallbacks.get(callback);
+ if (wrapper == null) {
+ wrapper = new GeofenceHardwareMonitorCallbackWrapper(callback);
+ mMonitorCallbacks.put(callback, wrapper);
+ }
+ return wrapper;
+ }
+ }
+
+ class GeofenceHardwareMonitorCallbackWrapper extends IGeofenceHardwareMonitorCallback.Stub {
+ private WeakReference<GeofenceHardwareMonitorCallback> mCallback;
+
+ GeofenceHardwareMonitorCallbackWrapper(GeofenceHardwareMonitorCallback c) {
+ mCallback = new WeakReference<GeofenceHardwareMonitorCallback>(c);
}
public void onMonitoringSystemChange(int monitoringType, boolean available,
Location location) {
- GeofenceHardwareCallback c = mCallback.get();
+ GeofenceHardwareMonitorCallback c = mCallback.get();
if (c != null) c.onMonitoringSystemChange(monitoringType, available, location);
}
+ }
+
+ class GeofenceHardwareCallbackWrapper extends IGeofenceHardwareCallback.Stub {
+ private WeakReference<GeofenceHardwareCallback> mCallback;
- public void onGeofenceChange(int geofenceId, int transition, Location location,
+ GeofenceHardwareCallbackWrapper(GeofenceHardwareCallback c) {
+ mCallback = new WeakReference<GeofenceHardwareCallback>(c);
+ }
+
+ public void onGeofenceTransition(int geofenceId, int transition, Location location,
long timestamp, int monitoringType) {
GeofenceHardwareCallback c = mCallback.get();
if (c != null) {
- c.onGeofenceChange(geofenceId, transition, location, timestamp,
+ c.onGeofenceTransition(geofenceId, transition, location, timestamp,
monitoringType);
}
}
@@ -428,7 +488,9 @@ public final class GeofenceHardware {
public void onGeofencePause(int geofenceId, int status) {
GeofenceHardwareCallback c = mCallback.get();
- if (c != null) c.onGeofencePause(geofenceId, status);
+ if (c != null) {
+ c.onGeofencePause(geofenceId, status);
+ }
}
public void onGeofenceResume(int geofenceId, int status) {
diff --git a/core/java/android/hardware/location/GeofenceHardwareCallback.java b/core/java/android/hardware/location/GeofenceHardwareCallback.java
index 8ab582a..6cad3da 100644
--- a/core/java/android/hardware/location/GeofenceHardwareCallback.java
+++ b/core/java/android/hardware/location/GeofenceHardwareCallback.java
@@ -22,19 +22,6 @@ import android.location.Location;
* The callback class associated with the APIs in {@link GeofenceHardware}
*/
public abstract class GeofenceHardwareCallback {
-
- /**
- * The callback called when the state of a monitoring system changes.
- * {@link GeofenceHardware#MONITORING_TYPE_GPS_HARDWARE} is an example of a
- * monitoring system.
- *
- * @param monitoringType The type of the monitoring system.
- * @param available Indicates whether the system is currently available or not.
- * @param location The last known location according to the monitoring system.
- */
- public void onMonitoringSystemChange(int monitoringType, boolean available, Location location) {
- }
-
/**
* The callback called when there is a transition to report for the specific
* geofence.
@@ -47,7 +34,7 @@ public abstract class GeofenceHardwareCallback {
* detected
* @param monitoringType Type of the monitoring system.
*/
- public void onGeofenceChange(int geofenceId, int transition, Location location,
+ public void onGeofenceTransition(int geofenceId, int transition, Location location,
long timestamp, int monitoringType) {
}
diff --git a/core/java/android/hardware/location/GeofenceHardwareImpl.java b/core/java/android/hardware/location/GeofenceHardwareImpl.java
index 21f1ea6..a62b660 100644
--- a/core/java/android/hardware/location/GeofenceHardwareImpl.java
+++ b/core/java/android/hardware/location/GeofenceHardwareImpl.java
@@ -21,8 +21,10 @@ import android.content.pm.PackageManager;
import android.location.IGpsGeofenceHardware;
import android.location.Location;
import android.location.LocationManager;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -48,8 +50,9 @@ public final class GeofenceHardwareImpl {
private PowerManager.WakeLock mWakeLock;
private SparseArray<IGeofenceHardwareCallback> mGeofences =
new SparseArray<IGeofenceHardwareCallback>();
- private ArrayList<IGeofenceHardwareCallback>[] mCallbacks =
+ private ArrayList<IGeofenceHardwareMonitorCallback>[] mCallbacks =
new ArrayList[GeofenceHardware.NUM_MONITORS];
+ private ArrayList<Reaper> mReapers = new ArrayList<Reaper>();
private IGpsGeofenceHardware mGpsService;
@@ -63,11 +66,18 @@ public final class GeofenceHardwareImpl {
private static final int RESUME_GEOFENCE_CALLBACK = 5;
private static final int ADD_GEOFENCE = 6;
private static final int REMOVE_GEOFENCE = 7;
+ private static final int GEOFENCE_CALLBACK_BINDER_DIED = 8;
// mCallbacksHandler message types
private static final int GPS_GEOFENCE_STATUS = 1;
private static final int CALLBACK_ADD = 2;
private static final int CALLBACK_REMOVE = 3;
+ private static final int MONITOR_CALLBACK_BINDER_DIED = 4;
+
+ // mReaperHandler message types
+ private static final int REAPER_GEOFENCE_ADDED = 1;
+ private static final int REAPER_MONITOR_CALLBACK_ADDED = 2;
+ private static final int REAPER_REMOVED = 3;
// The following constants need to match GpsLocationFlags enum in gps.h
private static final int LOCATION_INVALID = 0;
@@ -151,15 +161,28 @@ public final class GeofenceHardwareImpl {
}
}
- public int[] getMonitoringTypesAndStatus() {
+ public int[] getMonitoringTypes() {
synchronized (mSupportedMonitorTypes) {
- return mSupportedMonitorTypes;
+ if (mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE] !=
+ GeofenceHardware.MONITOR_UNSUPPORTED) {
+ return new int[] {GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE};
+ }
+ return new int[0];
+ }
+ }
+
+ public int getStatusOfMonitoringType(int monitoringType) {
+ synchronized (mSupportedMonitorTypes) {
+ if (monitoringType >= mSupportedMonitorTypes.length || monitoringType < 0) {
+ throw new IllegalArgumentException("Unknown monitoring type");
+ }
+ return mSupportedMonitorTypes[monitoringType];
}
}
- public boolean addCircularFence(int geofenceId, double latitude, double longitude,
- double radius, int lastTransition,int monitorTransitions, int notificationResponsivenes,
- int unknownTimer, int monitoringType, IGeofenceHardwareCallback callback) {
+ public boolean addCircularFence(int geofenceId, int monitoringType, double latitude,
+ double longitude, double radius, int lastTransition,int monitorTransitions,
+ int notificationResponsivenes, int unknownTimer, IGeofenceHardwareCallback callback) {
// This API is not thread safe. Operations on the same geofence need to be serialized
// by upper layers
if (DEBUG) {
@@ -190,7 +213,11 @@ public final class GeofenceHardwareImpl {
default:
result = false;
}
- if (!result) {
+ if (result) {
+ m = mReaperHandler.obtainMessage(REAPER_GEOFENCE_ADDED, callback);
+ m.arg1 = monitoringType;
+ mReaperHandler.sendMessage(m);
+ } else {
m = mGeofenceHandler.obtainMessage(REMOVE_GEOFENCE);
m.arg1 = geofenceId;
mGeofenceHandler.sendMessage(m);
@@ -245,7 +272,7 @@ public final class GeofenceHardwareImpl {
}
- public boolean resumeGeofence(int geofenceId, int monitorTransition, int monitoringType) {
+ public boolean resumeGeofence(int geofenceId, int monitoringType, int monitorTransition) {
// This API is not thread safe. Operations on the same geofence need to be serialized
// by upper layers
if (DEBUG) Log.d(TAG, "Resume Geofence: GeofenceId: " + geofenceId);
@@ -268,7 +295,12 @@ public final class GeofenceHardwareImpl {
}
public boolean registerForMonitorStateChangeCallback(int monitoringType,
- IGeofenceHardwareCallback callback) {
+ IGeofenceHardwareMonitorCallback callback) {
+ Message reaperMessage =
+ mReaperHandler.obtainMessage(REAPER_MONITOR_CALLBACK_ADDED, callback);
+ reaperMessage.arg1 = monitoringType;
+ mReaperHandler.sendMessage(reaperMessage);
+
Message m = mCallbacksHandler.obtainMessage(CALLBACK_ADD, callback);
m.arg1 = monitoringType;
mCallbacksHandler.sendMessage(m);
@@ -276,7 +308,7 @@ public final class GeofenceHardwareImpl {
}
public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
- IGeofenceHardwareCallback callback) {
+ IGeofenceHardwareMonitorCallback callback) {
Message m = mCallbacksHandler.obtainMessage(CALLBACK_REMOVE, callback);
m.arg1 = monitoringType;
mCallbacksHandler.sendMessage(m);
@@ -477,13 +509,25 @@ public final class GeofenceHardwareImpl {
"Location: " + geofenceTransition.mLocation + ":" + mGeofences);
try {
- callback.onGeofenceChange(
+ callback.onGeofenceTransition(
geofenceTransition.mGeofenceId, geofenceTransition.mTransition,
geofenceTransition.mLocation, geofenceTransition.mTimestamp,
GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE);
} catch (RemoteException e) {}
releaseWakeLock();
break;
+ case GEOFENCE_CALLBACK_BINDER_DIED:
+ // Find all geofences associated with this callback and remove them.
+ callback = (IGeofenceHardwareCallback) (msg.obj);
+ if (DEBUG) Log.d(TAG, "Geofence callback reaped:" + callback);
+ int monitoringType = msg.arg1;
+ for (int i = 0; i < mGeofences.size(); i++) {
+ if (mGeofences.valueAt(i).equals(callback)) {
+ geofenceId = mGeofences.keyAt(i);
+ removeGeofence(mGeofences.keyAt(i), monitoringType);
+ mGeofences.remove(geofenceId);
+ }
+ }
}
}
};
@@ -493,8 +537,8 @@ public final class GeofenceHardwareImpl {
@Override
public void handleMessage(Message msg) {
int monitoringType;
- ArrayList<IGeofenceHardwareCallback> callbackList;
- IGeofenceHardwareCallback callback;
+ ArrayList<IGeofenceHardwareMonitorCallback> callbackList;
+ IGeofenceHardwareMonitorCallback callback;
switch (msg.what) {
case GPS_GEOFENCE_STATUS:
@@ -508,7 +552,7 @@ public final class GeofenceHardwareImpl {
if (DEBUG) Log.d(TAG, "MonitoringSystemChangeCallback: GPS : " + available);
- for (IGeofenceHardwareCallback c: callbackList) {
+ for (IGeofenceHardwareMonitorCallback c: callbackList) {
try {
c.onMonitoringSystemChange(
GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, available,
@@ -519,22 +563,71 @@ public final class GeofenceHardwareImpl {
break;
case CALLBACK_ADD:
monitoringType = msg.arg1;
- callback = (IGeofenceHardwareCallback) msg.obj;
+ callback = (IGeofenceHardwareMonitorCallback) msg.obj;
callbackList = mCallbacks[monitoringType];
if (callbackList == null) {
- callbackList = new ArrayList<IGeofenceHardwareCallback>();
+ callbackList = new ArrayList<IGeofenceHardwareMonitorCallback>();
mCallbacks[monitoringType] = callbackList;
}
if (!callbackList.contains(callback)) callbackList.add(callback);
break;
case CALLBACK_REMOVE:
monitoringType = msg.arg1;
- callback = (IGeofenceHardwareCallback) msg.obj;
+ callback = (IGeofenceHardwareMonitorCallback) msg.obj;
callbackList = mCallbacks[monitoringType];
if (callbackList != null) {
callbackList.remove(callback);
}
break;
+ case MONITOR_CALLBACK_BINDER_DIED:
+ callback = (IGeofenceHardwareMonitorCallback) msg.obj;
+ if (DEBUG) Log.d(TAG, "Monitor callback reaped:" + callback);
+ callbackList = mCallbacks[msg.arg1];
+ if (callbackList != null && callbackList.contains(callback)) {
+ callbackList.remove(callback);
+ }
+ }
+ }
+ };
+
+ // All operations on mReaper
+ private Handler mReaperHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ Reaper r;
+ IGeofenceHardwareCallback callback;
+ IGeofenceHardwareMonitorCallback monitorCallback;
+ int monitoringType;
+
+ switch (msg.what) {
+ case REAPER_GEOFENCE_ADDED:
+ callback = (IGeofenceHardwareCallback) msg.obj;
+ monitoringType = msg.arg1;
+ r = new Reaper(callback, monitoringType);
+ if (!mReapers.contains(r)) {
+ mReapers.add(r);
+ IBinder b = callback.asBinder();
+ try {
+ b.linkToDeath(r, 0);
+ } catch (RemoteException e) {}
+ }
+ break;
+ case REAPER_MONITOR_CALLBACK_ADDED:
+ monitorCallback = (IGeofenceHardwareMonitorCallback) msg.obj;
+ monitoringType = msg.arg1;
+
+ r = new Reaper(monitorCallback, monitoringType);
+ if (!mReapers.contains(r)) {
+ mReapers.add(r);
+ IBinder b = monitorCallback.asBinder();
+ try {
+ b.linkToDeath(r, 0);
+ } catch (RemoteException e) {}
+ }
+ break;
+ case REAPER_REMOVED:
+ r = (Reaper) msg.obj;
+ mReapers.remove(r);
}
}
};
@@ -567,6 +660,57 @@ public final class GeofenceHardwareImpl {
return RESOLUTION_LEVEL_NONE;
}
+ class Reaper implements IBinder.DeathRecipient {
+ private IGeofenceHardwareMonitorCallback mMonitorCallback;
+ private IGeofenceHardwareCallback mCallback;
+ private int mMonitoringType;
+
+ Reaper(IGeofenceHardwareCallback c, int monitoringType) {
+ mCallback = c;
+ mMonitoringType = monitoringType;
+ }
+
+ Reaper(IGeofenceHardwareMonitorCallback c, int monitoringType) {
+ mMonitorCallback = c;
+ mMonitoringType = monitoringType;
+ }
+
+ @Override
+ public void binderDied() {
+ Message m;
+ if (mCallback != null) {
+ m = mGeofenceHandler.obtainMessage(GEOFENCE_CALLBACK_BINDER_DIED, mCallback);
+ m.arg1 = mMonitoringType;
+ mGeofenceHandler.sendMessage(m);
+ } else if (mMonitorCallback != null) {
+ m = mCallbacksHandler.obtainMessage(MONITOR_CALLBACK_BINDER_DIED, mMonitorCallback);
+ m.arg1 = mMonitoringType;
+ mCallbacksHandler.sendMessage(m);
+ }
+ Message reaperMessage = mReaperHandler.obtainMessage(REAPER_REMOVED, this);
+ mReaperHandler.sendMessage(reaperMessage);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + (mCallback != null ? mCallback.hashCode() : 0);
+ result = 31 * result + (mMonitorCallback != null ? mMonitorCallback.hashCode() : 0);
+ result = 31 * result + mMonitoringType;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) return false;
+ if (obj == this) return true;
+
+ Reaper rhs = (Reaper) obj;
+ return rhs.mCallback == mCallback && rhs.mMonitorCallback == mMonitorCallback &&
+ rhs.mMonitoringType == mMonitoringType;
+ }
+ }
+
int getAllowedResolutionLevel(int pid, int uid) {
if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
pid, uid) == PackageManager.PERMISSION_GRANTED) {
diff --git a/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java b/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java
new file mode 100644
index 0000000..b8e927e
--- /dev/null
+++ b/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 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.hardware.location;
+
+import android.location.Location;
+
+/**
+ * The callback class associated with the status change of hardware montiors
+ * in {@link GeofenceHardware}
+ */
+public abstract class GeofenceHardwareMonitorCallback {
+ /**
+ * The callback called when the state of a monitoring system changes.
+ * {@link GeofenceHardware#MONITORING_TYPE_GPS_HARDWARE} is an example of a
+ * monitoring system
+ *
+ * @param monitoringType The type of the monitoring system.
+ * @param available Indicates whether the system is currenty available or not.
+ * @param location The last known location according to the monitoring system.
+ */
+ public void onMonitoringSystemChange(int monitoringType, boolean available, Location location) {
+ }
+}
diff --git a/core/java/android/hardware/location/GeofenceHardwareRequest.java b/core/java/android/hardware/location/GeofenceHardwareRequest.java
new file mode 100644
index 0000000..6e7b592
--- /dev/null
+++ b/core/java/android/hardware/location/GeofenceHardwareRequest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2013 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.hardware.location;
+
+import android.location.Location;
+
+/**
+ * This class represents the characteristics of the geofence.
+ *
+ * <p> Use this in conjunction with {@link GeofenceHardware} APIs.
+ */
+
+public final class GeofenceHardwareRequest {
+ static final int GEOFENCE_TYPE_CIRCLE = 0;
+ private int mType;
+ private double mLatitude;
+ private double mLongitude;
+ private double mRadius;
+ private int mLastTransition = GeofenceHardware.GEOFENCE_UNCERTAIN;
+ private int mUnknownTimer = 30000; // 30 secs
+ private int mMonitorTransitions = GeofenceHardware.GEOFENCE_UNCERTAIN |
+ GeofenceHardware.GEOFENCE_ENTERED | GeofenceHardware.GEOFENCE_EXITED;
+ private int mNotificationResponsiveness = 5000; // 5 secs
+
+ private void setCircularGeofence(double latitude, double longitude, double radius) {
+ mLatitude = latitude;
+ mLongitude = longitude;
+ mRadius = radius;
+ mType = GEOFENCE_TYPE_CIRCLE;
+ }
+
+ /**
+ * Create a circular geofence.
+ *
+ * @param latitude Latitude of the geofence
+ * @param longitude Longitude of the geofence
+ * @param radius Radius of the geofence (in meters)
+ */
+ public static GeofenceHardwareRequest createCircularGeofence(double latitude,
+ double longitude, double radius) {
+ GeofenceHardwareRequest geofenceRequest = new GeofenceHardwareRequest();
+ geofenceRequest.setCircularGeofence(latitude, longitude, radius);
+ return geofenceRequest;
+ }
+
+ /**
+ * Set the last known transition of the geofence.
+ *
+ * @param lastTransition The current state of the geofence. Can be one of
+ * {@link GeofenceHardware#GEOFENCE_ENTERED}, {@link GeofenceHardware#GEOFENCE_EXITED},
+ * {@link GeofenceHardware#GEOFENCE_UNCERTAIN}.
+ */
+ public void setLastTransition(int lastTransition) {
+ mLastTransition = lastTransition;
+ }
+
+ /**
+ * Set the unknown timer for this geofence.
+ *
+ * @param unknownTimer The time limit after which the
+ * {@link GeofenceHardware#GEOFENCE_UNCERTAIN} transition
+ * should be triggered. This paramter is defined in milliseconds.
+ */
+ public void setUnknownTimer(int unknownTimer) {
+ mUnknownTimer = unknownTimer;
+ }
+
+ /**
+ * Set the transitions to be monitored.
+ *
+ * @param monitorTransitions Bitwise OR of {@link GeofenceHardware#GEOFENCE_ENTERED},
+ * {@link GeofenceHardware#GEOFENCE_EXITED}, {@link GeofenceHardware#GEOFENCE_UNCERTAIN}
+ */
+ public void setMonitorTransitions(int monitorTransitions) {
+ mMonitorTransitions = monitorTransitions;
+ }
+
+ /**
+ * Set the notification responsiveness of the geofence.
+ *
+ * @param notificationResponsiveness (milliseconds) Defines the best-effort description
+ * of how soon should the callback be called when the transition
+ * associated with the Geofence is triggered. For instance, if
+ * set to 1000 millseconds with {@link GeofenceHardware#GEOFENCE_ENTERED},
+ * the callback will be called 1000 milliseconds within entering
+ * the geofence.
+ */
+ public void setNotificationResponsiveness(int notificationResponsiveness) {
+ mNotificationResponsiveness = notificationResponsiveness;
+ }
+
+ /**
+ * Returns the latitude of this geofence.
+ */
+ public double getLatitude() {
+ return mLatitude;
+ }
+
+ /**
+ * Returns the longitude of this geofence.
+ */
+ public double getLongitude() {
+ return mLongitude;
+ }
+
+ /**
+ * Returns the radius of this geofence.
+ */
+ public double getRadius() {
+ return mRadius;
+ }
+
+ /**
+ * Returns transitions monitored for this geofence.
+ */
+ public int getMonitorTransitions() {
+ return mMonitorTransitions;
+ }
+
+ /**
+ * Returns the unknownTimer of this geofence.
+ */
+ public int getUnknownTimer() {
+ return mUnknownTimer;
+ }
+
+ /**
+ * Returns the notification responsiveness of this geofence.
+ */
+ public int getNotificationResponsiveness() {
+ return mNotificationResponsiveness;
+ }
+
+ /**
+ * Returns the last transition of this geofence.
+ */
+ public int getLastTransition() {
+ return mLastTransition;
+ }
+
+ int getType() {
+ return mType;
+ }
+}
diff --git a/core/java/android/hardware/location/GeofenceHardwareService.java b/core/java/android/hardware/location/GeofenceHardwareService.java
index 0eccee6..3bc70ee 100644
--- a/core/java/android/hardware/location/GeofenceHardwareService.java
+++ b/core/java/android/hardware/location/GeofenceHardwareService.java
@@ -68,23 +68,28 @@ public class GeofenceHardwareService extends Service {
mGeofenceHardwareImpl.setGpsHardwareGeofence(service);
}
- public int[] getMonitoringTypesAndStatus() {
+ public int[] getMonitoringTypes() {
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to access hardware geofence");
- return mGeofenceHardwareImpl.getMonitoringTypesAndStatus();
+ return mGeofenceHardwareImpl.getMonitoringTypes();
}
- public boolean addCircularFence(int id, double lat, double longitude, double radius,
- int lastTransition, int monitorTransitions, int
- notificationResponsiveness, int unknownTimer, int monitoringType,
- IGeofenceHardwareCallback callback) {
+ public int getStatusOfMonitoringType(int monitoringType) {
+ mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
+ "Location Hardware permission not granted to access hardware geofence");
+
+ return mGeofenceHardwareImpl.getStatusOfMonitoringType(monitoringType);
+ }
+ public boolean addCircularFence(int id, int monitoringType, double lat, double longitude,
+ double radius, int lastTransition, int monitorTransitions, int
+ notificationResponsiveness, int unknownTimer, IGeofenceHardwareCallback callback) {
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to access hardware geofence");
checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
- return mGeofenceHardwareImpl.addCircularFence(id, lat, longitude, radius,
- lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer,
- monitoringType, callback);
+ return mGeofenceHardwareImpl.addCircularFence(id, monitoringType, lat, longitude,
+ radius, lastTransition, monitorTransitions, notificationResponsiveness,
+ unknownTimer, callback);
}
public boolean removeGeofence(int id, int monitoringType) {
@@ -103,16 +108,16 @@ public class GeofenceHardwareService extends Service {
return mGeofenceHardwareImpl.pauseGeofence(id, monitoringType);
}
- public boolean resumeGeofence(int id, int monitorTransitions, int monitoringType) {
+ public boolean resumeGeofence(int id, int monitoringType, int monitorTransitions) {
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to access hardware geofence");
checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
- return mGeofenceHardwareImpl.resumeGeofence(id, monitorTransitions, monitoringType);
+ return mGeofenceHardwareImpl.resumeGeofence(id, monitoringType, monitorTransitions);
}
public boolean registerForMonitorStateChangeCallback(int monitoringType,
- IGeofenceHardwareCallback callback) {
+ IGeofenceHardwareMonitorCallback callback) {
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to access hardware geofence");
@@ -122,7 +127,7 @@ public class GeofenceHardwareService extends Service {
}
public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
- IGeofenceHardwareCallback callback) {
+ IGeofenceHardwareMonitorCallback callback) {
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to access hardware geofence");
diff --git a/core/java/android/hardware/location/IGeofenceHardware.aidl b/core/java/android/hardware/location/IGeofenceHardware.aidl
index 4ba02b8..6900070 100644
--- a/core/java/android/hardware/location/IGeofenceHardware.aidl
+++ b/core/java/android/hardware/location/IGeofenceHardware.aidl
@@ -18,19 +18,21 @@ package android.hardware.location;
import android.location.IGpsGeofenceHardware;
import android.hardware.location.IGeofenceHardwareCallback;
+import android.hardware.location.IGeofenceHardwareMonitorCallback;
/** @hide */
interface IGeofenceHardware {
void setGpsGeofenceHardware(in IGpsGeofenceHardware service);
- int[] getMonitoringTypesAndStatus();
- boolean addCircularFence(int id, double lat, double longitude, double radius,
- int lastTransition, int monitorTransitions, int notificationResponsiveness,
- int unknownTimer, int monitoringType, in IGeofenceHardwareCallback callback);
+ int[] getMonitoringTypes();
+ int getStatusOfMonitoringType(int monitoringType);
+ boolean addCircularFence(int id, int monitoringType, double lat, double longitude,
+ double radius, int lastTransition, int monitorTransitions,
+ int notificationResponsiveness, int unknownTimer,in IGeofenceHardwareCallback callback);
boolean removeGeofence(int id, int monitoringType);
boolean pauseGeofence(int id, int monitoringType);
- boolean resumeGeofence(int id, int monitorTransitions, int monitoringType);
+ boolean resumeGeofence(int id, int monitoringType, int monitorTransitions);
boolean registerForMonitorStateChangeCallback(int monitoringType,
- IGeofenceHardwareCallback callback);
+ IGeofenceHardwareMonitorCallback callback);
boolean unregisterForMonitorStateChangeCallback(int monitoringType,
- IGeofenceHardwareCallback callback);
+ IGeofenceHardwareMonitorCallback callback);
}
diff --git a/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl b/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl
index 678fc49..3a8f430 100644
--- a/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl
+++ b/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl
@@ -20,8 +20,7 @@ import android.location.Location;
/** @hide */
oneway interface IGeofenceHardwareCallback {
- void onMonitoringSystemChange(int monitoringType, boolean available, in Location location);
- void onGeofenceChange(int geofenceId, int transition, in Location location,
+ void onGeofenceTransition(int geofenceId, int transition, in Location location,
long timestamp, int monitoringType);
void onGeofenceAdd(int geofenceId, int status);
void onGeofenceRemove(int geofenceId, int status);
diff --git a/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl b/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl
new file mode 100644
index 0000000..0b6e04b
--- /dev/null
+++ b/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 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.hardware.location;
+
+import android.location.Location;
+
+/** @hide */
+oneway interface IGeofenceHardwareMonitorCallback {
+ void onMonitoringSystemChange(int monitoringType, boolean available, in Location location);
+}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 2e8092a..a11358a 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -42,7 +42,8 @@ interface IUserManager {
int getUserHandle(int userSerialNumber);
Bundle getUserRestrictions(int userHandle);
void setUserRestrictions(in Bundle restrictions, int userHandle);
- void setApplicationRestrictions(in String packageName, in List<RestrictionEntry> entries,
+ void setApplicationRestrictions(in String packageName, in Bundle restrictions,
int userHandle);
- List<RestrictionEntry> getApplicationRestrictions(in String packageName, int userHandle);
+ Bundle getApplicationRestrictions(in String packageName);
+ Bundle getApplicationRestrictionsForUser(in String packageName, int userHandle);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index e580e2b..df065e9 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -142,6 +142,7 @@ public class UserManager {
private static UserManager sInstance = null;
+ /** @hide */
public synchronized static UserManager get(Context context) {
if (sInstance == null) {
sInstance = (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -578,13 +579,29 @@ public class UserManager {
return -1;
}
+ /**
+ * Returns a Bundle containing any saved application restrictions for this user, for the
+ * given package name. Only an application with this package name can call this method.
+ * @param packageName the package name of the calling application
+ * @return a Bundle with the restrictions as key/value pairs, or null if there are no
+ * saved restrictions. The values can be of type Boolean, String or String[], depending
+ * on the restriction type, as defined by the application.
+ */
+ public Bundle getApplicationRestrictions(String packageName) {
+ try {
+ return mService.getApplicationRestrictions(packageName);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not get application restrictions for package " + packageName);
+ }
+ return null;
+ }
/**
* @hide
*/
- public List<RestrictionEntry> getApplicationRestrictions(String packageName, UserHandle user) {
+ public Bundle getApplicationRestrictions(String packageName, UserHandle user) {
try {
- return mService.getApplicationRestrictions(packageName, user.getIdentifier());
+ return mService.getApplicationRestrictionsForUser(packageName, user.getIdentifier());
} catch (RemoteException re) {
Log.w(TAG, "Could not get application restrictions for user " + user.getIdentifier());
}
@@ -594,10 +611,10 @@ public class UserManager {
/**
* @hide
*/
- public void setApplicationRestrictions(String packageName, List<RestrictionEntry> entries,
+ public void setApplicationRestrictions(String packageName, Bundle restrictions,
UserHandle user) {
try {
- mService.setApplicationRestrictions(packageName, entries, user.getIdentifier());
+ mService.setApplicationRestrictions(packageName, restrictions, user.getIdentifier());
} catch (RemoteException re) {
Log.w(TAG, "Could not set application restrictions for user " + user.getIdentifier());
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 88ee414..3df4e99 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3260,6 +3260,7 @@ public final class Settings {
/**
* This preference contains the string that shows for owner info on LockScreen.
* @hide
+ * @deprecated
*/
public static final String LOCK_SCREEN_OWNER_INFO = "lock_screen_owner_info";
@@ -3287,6 +3288,7 @@ public final class Settings {
/**
* This preference enables showing the owner info on LockScreen.
* @hide
+ * @deprecated
*/
public static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
"lock_screen_owner_info_enabled";
@@ -4102,9 +4104,7 @@ public final class Settings {
MOUNT_UMS_AUTOSTART,
MOUNT_UMS_PROMPT,
MOUNT_UMS_NOTIFY_ENABLED,
- UI_NIGHT_MODE,
- LOCK_SCREEN_OWNER_INFO,
- LOCK_SCREEN_OWNER_INFO_ENABLED
+ UI_NIGHT_MODE
};
/**
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index edfef56..4989c3a 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -220,14 +220,14 @@ public class Surface implements Parcelable {
/**
* Gets a {@link Canvas} for drawing into this surface.
*
- * After drawing into the provided {@link Canvas}, the caller should
+ * After drawing into the provided {@link Canvas}, the caller must
* invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
*
* @param inOutDirty A rectangle that represents the dirty region that the caller wants
* to redraw. This function may choose to expand the dirty rectangle if for example
* the surface has been resized or if the previous contents of the surface were
- * not available. The caller should redraw the entire dirty region as represented
- * by the contents of the dirty rect upon return from this function.
+ * not available. The caller must redraw the entire dirty region as represented
+ * by the contents of the inOutDirty rectangle upon return from this function.
* The caller may also pass <code>null</code> instead, in the case where the
* entire surface should be redrawn.
* @return A canvas for drawing into the surface.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 14fa9cb..793fb5e 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -755,12 +755,36 @@ public class SurfaceView extends View {
mHandler.sendMessage(msg);
}
+ /**
+ * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
+ *
+ * After drawing into the provided {@link Canvas}, the caller must
+ * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+ *
+ * The caller must redraw the entire surface.
+ * @return A canvas for drawing into the surface.
+ */
public Canvas lockCanvas() {
return internalLockCanvas(null);
}
- public Canvas lockCanvas(Rect dirty) {
- return internalLockCanvas(dirty);
+ /**
+ * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
+ *
+ * After drawing into the provided {@link Canvas}, the caller must
+ * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+ *
+ * @param inOutDirty A rectangle that represents the dirty region that the caller wants
+ * to redraw. This function may choose to expand the dirty rectangle if for example
+ * the surface has been resized or if the previous contents of the surface were
+ * not available. The caller must redraw the entire dirty region as represented
+ * by the contents of the inOutDirty rectangle upon return from this function.
+ * The caller may also pass <code>null</code> instead, in the case where the
+ * entire surface should be redrawn.
+ * @return A canvas for drawing into the surface.
+ */
+ public Canvas lockCanvas(Rect inOutDirty) {
+ return internalLockCanvas(inOutDirty);
}
private final Canvas internalLockCanvas(Rect dirty) {
@@ -810,6 +834,12 @@ public class SurfaceView extends View {
return null;
}
+ /**
+ * Posts the new contents of the {@link Canvas} to the surface and
+ * releases the {@link Canvas}.
+ *
+ * @param canvas The canvas previously obtained from {@link #lockCanvas}.
+ */
public void unlockCanvasAndPost(Canvas canvas) {
mSurface.unlockCanvasAndPost(canvas);
mSurfaceLock.unlock();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4fb2431..be26d20 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13380,18 +13380,32 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Sets a rectangular area on this view to which the view will be clipped
- * it is drawn. Setting the value to null will remove the clip bounds
+ * when it is drawn. Setting the value to null will remove the clip bounds
* and the view will draw normally, using its full bounds.
*
* @param clipBounds The rectangular area, in the local coordinates of
* this view, to which future drawing operations will be clipped.
*/
public void setClipBounds(Rect clipBounds) {
- mClipBounds = clipBounds;
if (clipBounds != null) {
- invalidate(clipBounds);
+ if (clipBounds.equals(mClipBounds)) {
+ return;
+ }
+ if (mClipBounds == null) {
+ invalidate();
+ mClipBounds = new Rect(clipBounds);
+ } else {
+ invalidate(Math.min(mClipBounds.left, clipBounds.left),
+ Math.min(mClipBounds.top, clipBounds.top),
+ Math.max(mClipBounds.right, clipBounds.right),
+ Math.max(mClipBounds.bottom, clipBounds.bottom));
+ mClipBounds.set(clipBounds);
+ }
} else {
- invalidate();
+ if (mClipBounds != null) {
+ invalidate();
+ mClipBounds = null;
+ }
}
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 83e2e79..07e66b7 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2108,6 +2108,8 @@ public class RemoteViews implements Parcelable, Filter {
* RemoteViews. This count cannot change during the life-cycle of a given widget, so this
* parameter should account for the maximum possible number of types that may appear in the
* See {@link Adapter#getViewTypeCount()}.
+ *
+ * @hide
*/
public void setRemoteAdapter(int viewId, ArrayList<RemoteViews> list, int viewTypeCount) {
addAction(new SetRemoteViewsAdapterList(viewId, list, viewTypeCount));
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 555c7c2..d3ead26 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -140,6 +140,10 @@ public class LockPatternUtils {
public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
+ private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
+ private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
+ Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
+
private final Context mContext;
private final ContentResolver mContentResolver;
private DevicePolicyManager mDevicePolicyManager;
@@ -526,6 +530,22 @@ public class LockPatternUtils {
}
}
+ public void setOwnerInfo(String info, int userId) {
+ setString(LOCK_SCREEN_OWNER_INFO, info, userId);
+ }
+
+ public void setOwnerInfoEnabled(boolean enabled) {
+ setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled);
+ }
+
+ public String getOwnerInfo(int userId) {
+ return getString(LOCK_SCREEN_OWNER_INFO);
+ }
+
+ public boolean isOwnerInfoEnabled() {
+ return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false);
+ }
+
/**
* Compute the password quality from the given password string.
*/
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 1ace23e..17f205d 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -339,23 +339,11 @@ uint32_t TextLayoutValue::getElapsedTime() {
}
TextLayoutShaper::TextLayoutShaper() {
- init();
-
mBuffer = hb_buffer_create();
}
-void TextLayoutShaper::init() {
- mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
-}
-
-void TextLayoutShaper::unrefTypefaces() {
- SkSafeUnref(mDefaultTypeface);
-}
-
TextLayoutShaper::~TextLayoutShaper() {
hb_buffer_destroy(mBuffer);
-
- unrefTypefaces();
}
void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
@@ -839,23 +827,27 @@ size_t TextLayoutShaper::shapeFontRun(const SkPaint* paint) {
}
if (baseGlyphCount != 0) {
+ SkTypeface::Style style = SkTypeface::kNormal;
+ if (typeface != NULL) {
+ style = typeface->style();
+ }
typeface = typefaceForScript(paint, typeface, hb_buffer_get_script(mBuffer));
if (!typeface) {
baseGlyphCount = 0;
- typeface = mDefaultTypeface;
- SkSafeRef(typeface);
+ typeface = SkFontHost::CreateTypeface(NULL, NULL, style);
#if DEBUG_GLYPHS
ALOGD("Using Default Typeface");
#endif
}
} else {
if (!typeface) {
- typeface = mDefaultTypeface;
+ typeface = SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
#if DEBUG_GLYPHS
- ALOGD("Using Default Typeface");
+ ALOGD("Using Default Typeface (normal style)");
#endif
+ } else {
+ SkSafeRef(typeface);
}
- SkSafeRef(typeface);
}
mShapingPaint.setTypeface(typeface);
@@ -899,8 +891,6 @@ void TextLayoutShaper::purgeCaches() {
hb_face_destroy(mCachedHBFaces.valueAt(i));
}
mCachedHBFaces.clear();
- unrefTypefaces();
- init();
}
TextLayoutEngine::TextLayoutEngine() {
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index f9b9900..5414a11 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -197,18 +197,10 @@ private:
SkPaint mShapingPaint;
/**
- * Skia default typeface to be returned if we cannot resolve script
- */
- SkTypeface* mDefaultTypeface;
-
- /**
* Cache of Harfbuzz faces
*/
KeyedVector<SkFontID, hb_face_t*> mCachedHBFaces;
- void init();
- void unrefTypefaces();
-
SkTypeface* typefaceForScript(const SkPaint* paint, SkTypeface* typeface,
hb_script_t script);
@@ -228,7 +220,6 @@ private:
hb_face_t* referenceCachedHBFace(SkTypeface* typeface);
bool isComplexScript(hb_script_t script);
-
}; // TextLayoutShaper
/**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6b4fe79..514178d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -918,7 +918,8 @@
<permission android:name="android.permission.RECORD_AUDIO"
android:permissionGroup="android.permission-group.MICROPHONE"
android:protectionLevel="dangerous"
- android:label="@string/permlab_recordAudio" />
+ android:label="@string/permlab_recordAudio"
+ android:description="@string/permdesc_recordAudio" />
<!-- =========================================== -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cc50d8a..84e300a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -345,6 +345,12 @@
A value of -1 means no change in orientation by default. -->
<integer name="config_carDockRotation">-1</integer>
+ <!-- The number of degrees to rotate the display when the device has HDMI connected
+ but is not in a dock. A value of -1 means no change in orientation by default.
+ Use -1 except on older devices whose Hardware Composer HAL does not
+ provide full support for multiple displays. -->
+ <integer name="config_undockedHdmiRotation">-1</integer>
+
<!-- Control the default UI mode type to use when there is no other type override
happening. One of the following values (See Configuration.java):
1 UI_MODE_TYPE_NORMAL
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 45ea182..5e75390 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1584,6 +1584,7 @@
<java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
<java-symbol type="integer" name="config_screenBrightnessDim" />
<java-symbol type="integer" name="config_shutdownBatteryTemperature" />
+ <java-symbol type="integer" name="config_undockedHdmiRotation" />
<java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
<java-symbol type="layout" name="am_compat_mode_dialog" />
<java-symbol type="layout" name="launch_warning" />
diff --git a/data/keyboards/Vendor_0079_Product_0011.kl b/data/keyboards/Vendor_0079_Product_0011.kl
new file mode 100644
index 0000000..2ae2a01
--- /dev/null
+++ b/data/keyboards/Vendor_0079_Product_0011.kl
@@ -0,0 +1,23 @@
+# Copyright (C) 2013 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.
+
+# Classic NES Controller
+
+key 289 BUTTON_A
+key 290 BUTTON_B
+key 297 BUTTON_START
+key 296 BUTTON_SELECT
+
+axis 0x00 HAT_X
+axis 0x01 HAT_Y
diff --git a/data/keyboards/Vendor_045e_Product_028e.kl b/data/keyboards/Vendor_045e_Product_028e.kl
index 99f046a..ca6fa59 100644
--- a/data/keyboards/Vendor_045e_Product_028e.kl
+++ b/data/keyboards/Vendor_045e_Product_028e.kl
@@ -22,9 +22,9 @@ key 307 BUTTON_X
key 308 BUTTON_Y
key 310 BUTTON_L1
key 311 BUTTON_R1
-key 314 BUTTON_SELECT
+key 314 BUTTON_BACK
key 315 BUTTON_START
-key 316 BUTTON_MODE
+key 316 BUTTON_HOME
key 317 BUTTON_THUMBL
key 318 BUTTON_THUMBR
diff --git a/data/keyboards/Vendor_046d_Product_c219.kl b/data/keyboards/Vendor_046d_Product_c219.kl
new file mode 100644
index 0000000..431dd03
--- /dev/null
+++ b/data/keyboards/Vendor_046d_Product_c219.kl
@@ -0,0 +1,35 @@
+# Copyright (C) 2013 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.
+
+# Logitech Logitech Cordless RumblePad 2
+
+key 305 BUTTON_A
+key 306 BUTTON_B
+key 304 BUTTON_X
+key 307 BUTTON_Y
+key 308 BUTTON_L1
+key 309 BUTTON_R1
+key 310 BUTTON_L2
+key 311 BUTTON_R2
+key 313 BUTTON_START
+key 312 BUTTON_BACK
+key 314 BUTTON_THUMBL
+key 315 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_046d_Product_c21f.kl b/data/keyboards/Vendor_046d_Product_c21f.kl
new file mode 100644
index 0000000..981d864
--- /dev/null
+++ b/data/keyboards/Vendor_046d_Product_c21f.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 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.
+
+# Logitech Wireless Gamepad F710
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_054c_Product_0268.kl b/data/keyboards/Vendor_054c_Product_0268.kl
index f8ac6a3..62c5f4d 100644
--- a/data/keyboards/Vendor_054c_Product_0268.kl
+++ b/data/keyboards/Vendor_054c_Product_0268.kl
@@ -23,10 +23,10 @@ key 0x127 DPAD_LEFT
key 0x120 BUTTON_SELECT
key 0x123 BUTTON_START
-key 0x12f BUTTON_A
-key 0x12c BUTTON_B
-key 0x12e BUTTON_X
-key 0x12d BUTTON_Y
+key 0x12e BUTTON_A
+key 0x12d BUTTON_B
+key 0x12f BUTTON_X
+key 0x12c BUTTON_Y
key 0x12a BUTTON_L1
key 0x12b BUTTON_R1
key 0x128 BUTTON_L2
@@ -35,7 +35,7 @@ key 0x121 BUTTON_THUMBL
key 0x122 BUTTON_THUMBR
# PS key
-key 0x2d0 BUTTON_1
+key 0x2d0 BUTTON_HOME
# Left Analog Stick
axis 0x00 X
diff --git a/data/keyboards/Vendor_0583_Product_2060.kl b/data/keyboards/Vendor_0583_Product_2060.kl
new file mode 100644
index 0000000..92c8a14
--- /dev/null
+++ b/data/keyboards/Vendor_0583_Product_2060.kl
@@ -0,0 +1,27 @@
+# Copyright (C) 2013 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.
+
+# ION GO PAD
+
+key 288 BUTTON_A
+key 289 BUTTON_B
+key 290 BUTTON_X
+key 291 BUTTON_Y
+key 294 BUTTON_L1
+key 295 BUTTON_R1
+key 292 BUTTON_L2
+key 293 BUTTON_R2
+
+axis 0x00 HAT_X
+axis 0x01 HAT_Y
diff --git a/data/keyboards/Vendor_0a5c_Product_8502.kl b/data/keyboards/Vendor_0a5c_Product_8502.kl
new file mode 100644
index 0000000..0084969
--- /dev/null
+++ b/data/keyboards/Vendor_0a5c_Product_8502.kl
@@ -0,0 +1,33 @@
+# Copyright (C) 2013 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.
+
+# Snakebyte
+
+key 289 BUTTON_A
+key 290 BUTTON_B
+key 288 BUTTON_X
+key 291 BUTTON_Y
+key 292 BUTTON_L1
+key 293 BUTTON_R1
+key 294 BUTTON_L2
+key 295 BUTTON_R2
+key 297 BUTTON_START
+key 296 BUTTON_SELECT
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1038_Product_1412.kl b/data/keyboards/Vendor_1038_Product_1412.kl
new file mode 100644
index 0000000..551b0bd
--- /dev/null
+++ b/data/keyboards/Vendor_1038_Product_1412.kl
@@ -0,0 +1,31 @@
+# Copyright (C) 2013 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.
+
+# Steelseries Free
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 316 BUTTON_SELECT
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_12bd_Product_d015.kl b/data/keyboards/Vendor_12bd_Product_d015.kl
new file mode 100644
index 0000000..557d62f
--- /dev/null
+++ b/data/keyboards/Vendor_12bd_Product_d015.kl
@@ -0,0 +1,27 @@
+# Copyright (C) 2013 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.
+
+# Hitgaming SNES Retro
+
+key 306 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 304 BUTTON_Y
+key 308 BUTTON_L1
+key 309 BUTTON_R1
+key 313 BUTTON_START
+key 312 BUTTON_SELECT
+
+axis 0x00 HAT_X
+axis 0x01 HAT_Y
diff --git a/data/keyboards/Vendor_1689_Product_fd00.kl b/data/keyboards/Vendor_1689_Product_fd00.kl
new file mode 100644
index 0000000..6ce14ed
--- /dev/null
+++ b/data/keyboards/Vendor_1689_Product_fd00.kl
@@ -0,0 +1,38 @@
+# Copyright (C) 2013 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.
+
+# Razer Onza Tournament Edition
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 307 BUTTON_L1
+key 308 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+key 706 DPAD_UP
+key 705 DPAD_RIGHT
+key 707 DPAD_DOWN
+key 704 DPAD_LEFT
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
diff --git a/data/keyboards/Vendor_1689_Product_fd01.kl b/data/keyboards/Vendor_1689_Product_fd01.kl
new file mode 100644
index 0000000..8144515
--- /dev/null
+++ b/data/keyboards/Vendor_1689_Product_fd01.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 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.
+
+# Razer Xbox 360 Gamepad
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 308 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1689_Product_fe00.kl b/data/keyboards/Vendor_1689_Product_fe00.kl
new file mode 100644
index 0000000..90fe4af
--- /dev/null
+++ b/data/keyboards/Vendor_1689_Product_fe00.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 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.
+
+# Razer Sabertooth Elite
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f016.kl b/data/keyboards/Vendor_1bad_Product_f016.kl
new file mode 100644
index 0000000..b72fd5c
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f016.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 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.
+
+# Madcatz Gamepad
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f023.kl b/data/keyboards/Vendor_1bad_Product_f023.kl
new file mode 100644
index 0000000..c1588b2
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f023.kl
@@ -0,0 +1,35 @@
+# Copyright (C) 2013 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.
+
+# Mad Catz MLG GamePad for Xbox 360
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f027.kl b/data/keyboards/Vendor_1bad_Product_f027.kl
new file mode 100644
index 0000000..ea0aa7a
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f027.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 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.
+
+# MadCatz FPS Pro
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f036.kl b/data/keyboards/Vendor_1bad_Product_f036.kl
new file mode 100644
index 0000000..8cd906a
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f036.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 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.
+
+# MadCatz Generic XBox Controller
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1d79_Product_0009.kl b/data/keyboards/Vendor_1d79_Product_0009.kl
new file mode 100644
index 0000000..78fe2cd
--- /dev/null
+++ b/data/keyboards/Vendor_1d79_Product_0009.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 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.
+
+# Nyko Playpad / Playpad Pro
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 158 BUTTON_BACK
+key 172 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x09 RTRIGGER
+axis 0x0a LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_2378_Product_100a.kl b/data/keyboards/Vendor_2378_Product_100a.kl
new file mode 100644
index 0000000..d9cd171
--- /dev/null
+++ b/data/keyboards/Vendor_2378_Product_100a.kl
@@ -0,0 +1,35 @@
+# Copyright (C) 2013 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.
+
+# OnLive, Inc. OnLive Wireless Controller
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_SELECT
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/docs/html/images/mediadrm_decryption_sequence.png b/docs/html/images/mediadrm_decryption_sequence.png
new file mode 100644
index 0000000..2bd95ea
--- /dev/null
+++ b/docs/html/images/mediadrm_decryption_sequence.png
Binary files differ
diff --git a/docs/html/images/mediadrm_overview.png b/docs/html/images/mediadrm_overview.png
new file mode 100644
index 0000000..dd66bce
--- /dev/null
+++ b/docs/html/images/mediadrm_overview.png
Binary files differ
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 6872278..31fbc4a 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -29,25 +29,69 @@ import android.os.Parcel;
import android.util.Log;
/**
- * MediaDrm can be used in conjunction with {@link android.media.MediaCrypto}
- * to obtain keys for decrypting protected media data.
- *
- * Crypto schemes are assigned 16 byte UUIDs,
- * the method {@link #isCryptoSchemeSupported} can be used to query if a given
- * scheme is supported on the device.
- *
+ * MediaDrm can be used to obtain keys for decrypting protected media streams, in
+ * conjunction with {@link android.media.MediaCrypto}. The MediaDrm APIs
+ * are designed to support the ISO/IEC 23001-7: Common Encryption standard, but
+ * may also be used to implement other encryption schemes.
+ * <p>
+ * Encrypted content is prepared using an encryption server and stored in a content
+ * library. The encrypted content is streamed or downloaded from the content library to
+ * client devices via content servers. Licenses to view the content are obtained from
+ * a License Server.
+ * <p>
+ * <p><img src="../../../images/mediadrm_overview.png"
+ * alt="MediaDrm Overview diagram"
+ * border="0" /></p>
+ * <p>
+ * Keys are requested from the license server using a key request. The key
+ * response is delivered to the client app, which provides the response to the
+ * MediaDrm API.
+ * <p>
+ * A Provisioning server may be required to distribute device-unique credentials to
+ * the devices.
+ * <p>
+ * Enforcing requirements related to the number of devices that may play content
+ * simultaneously can be performed either through key renewal or using the secure
+ * stop methods.
+ * <p>
+ * The following sequence diagram shows the interactions between the objects
+ * involved while playing back encrypted content:
+ * <p>
+ * <p><img src="../../../images/mediadrm_decryption_sequence.png"
+ * alt="MediaDrm Overview diagram"
+ * border="0" /></p>
+ * <p>
+ * The app first constructs {@link android.media.MediaExtractor} and
+ * {@link android.media.MediaCodec} objects. It accesses the DRM-scheme-identifying UUID,
+ * typically from metadata in the content, and uses this UUID to construct an instance
+ * of a MediaDrm object that is able to support the DRM scheme required by the content.
+ * Crypto schemes are assigned 16 byte UUIDs. The method {@link #isCryptoSchemeSupported}
+ * can be used to query if a given scheme is supported on the device.
+ * <p>
+ * The app calls {@link #openSession} to generate a sessionId that will uniquely identify
+ * the session in subsequent interactions. The app next uses the MediaDrm object to
+ * obtain a key request message and send it to the license server, then provide
+ * the server's response to the MediaDrm object.
+ * <p>
+ * Once the app has a sessionId, it can construct a MediaCrypto object from the UUID and
+ * sessionId. The MediaCrypto object is registered with the MediaCodec in the
+ * {@link MediaCodec.#configure} method to enable the codec to decrypt content.
+ * <p>
+ * When the app has constructed {@link android.media.MediaExtractor},
+ * {@link android.media.MediaCodec} and {@link android.media.MediaCrypto} objects,
+ * it proceeds to pull samples from the extractor and queue them into the decoder. For
+ * encrypted content, the samples returned from the extractor remain encrypted, they
+ * are only decrypted when the samples are delivered to the decoder.
+ * <p>
* <a name="Callbacks"></a>
* <h3>Callbacks</h3>
- * <p>Applications may want to register for informational events in order
- * to be informed of some internal state update during playback or streaming.
+ * <p>Applications should register for informational events in order
+ * to be informed of key state updates during playback or streaming.
* Registration for these events is done via a call to
- * {@link #setOnEventListener(OnInfoListener)}setOnInfoListener,
- * In order to receive the respective callback
- * associated with this listener, applications are required to create
+ * {@link #setOnEventListener}. In order to receive the respective
+ * callback associated with this listener, applications are required to create
* MediaDrm objects on a thread with its own Looper running (main UI
* thread by default has a Looper running).
- *
- * @hide -- don't expose yet
*/
public final class MediaDrm {
@@ -116,7 +160,7 @@ public final class MediaDrm {
/**
* Interface definition for a callback to be invoked when a drm event
- * occurs.
+ * occurs
*/
public interface OnEventListener
{
@@ -132,10 +176,30 @@ public final class MediaDrm {
void onEvent(MediaDrm md, byte[] sessionId, int event, int extra, byte[] data);
}
- public static final int MEDIA_DRM_EVENT_PROVISION_REQUIRED = 1;
- public static final int MEDIA_DRM_EVENT_KEY_REQUIRED = 2;
- public static final int MEDIA_DRM_EVENT_KEY_EXPIRED = 3;
- public static final int MEDIA_DRM_EVENT_VENDOR_DEFINED = 4;
+ /**
+ * This event type indicates that the app needs to request a certificate from
+ * the provisioning server. The request message data is obtained using
+ * {@link #getProvisionRequest}
+ */
+ public static final int EVENT_PROVISION_REQUIRED = 1;
+
+ /**
+ * This event type indicates that the app needs to request keys from a license
+ * server. The request message data is obtained using {@link #getKeyRequest}.
+ */
+ public static final int EVENT_KEY_REQUIRED = 2;
+
+ /**
+ * This event type indicates that the licensed usage duration for keys in a session
+ * has expired. The keys are no longer valid.
+ */
+ public static final int EVENT_KEY_EXPIRED = 3;
+
+ /**
+ * This event may indicate some specific vendor-defined condition, see your
+ * DRM provider documentation for details
+ */
+ public static final int EVENT_VENDOR_DEFINED = 4;
private static final int DRM_EVENT = 200;
@@ -183,7 +247,7 @@ public final class MediaDrm {
}
/*
- * Called from native code when an interesting event happens. This method
+ * This method is called from native code when an event occurs. This method
* just uses the EventHandler system to post the event back to the main app thread.
* We use a weak reference to the original MediaPlayer object so that the native
* code is safe from the object disappearing from underneath it. (This is
@@ -203,89 +267,117 @@ public final class MediaDrm {
}
/**
- * Open a new session with the MediaDrm object. A session ID is returned.
+ * Open a new session with the MediaDrm object. A session ID is returned.
*/
- public native byte[] openSession() throws MediaDrmException;
+ public native byte[] openSession();
/**
- * Close a session on the MediaDrm object that was previously opened
- * with {@link #openSession}.
+ * Close a session on the MediaDrm object that was previously opened
+ * with {@link #openSession}.
*/
- public native void closeSession(byte[] sessionId) throws MediaDrmException;
+ public native void closeSession(byte[] sessionId);
- public static final int MEDIA_DRM_KEY_TYPE_STREAMING = 1;
- public static final int MEDIA_DRM_KEY_TYPE_OFFLINE = 2;
- public static final int MEDIA_DRM_KEY_TYPE_RELEASE = 3;
+ /**
+ * This key request type species that the keys will be for online use, they will
+ * not be saved to the device for subsequent use when the device is not connected
+ * to a network.
+ */
+ public static final int KEY_TYPE_STREAMING = 1;
+
+ /**
+ * This key request type specifies that the keys will be for offline use, they
+ * will be saved to the device for use when the device is not connected to a network.
+ */
+ public static final int KEY_TYPE_OFFLINE = 2;
+
+ /**
+ * This key request type specifies that previously saved offline keys should be released.
+ */
+ public static final int KEY_TYPE_RELEASE = 3;
+
+ /**
+ * Contains the opaque data an app uses to request keys from a license server
+ */
+ public final static class KeyRequest {
+ KeyRequest() {}
+
+ /**
+ * Get the opaque message data
+ */
+ public byte[] getData() { return mData; }
+
+ /**
+ * Get the default URL to use when sending the key request message to a
+ * server, if known. The app may prefer to use a different license
+ * server URL from other sources.
+ */
+ public String getDefaultUrl() { return mDefaultUrl; }
- public final class KeyRequest {
- public KeyRequest() {}
- public byte[] data;
- public String defaultUrl;
+ private byte[] mData;
+ private String mDefaultUrl;
};
/**
* A key request/response exchange occurs between the app and a license server
* to obtain or release keys used to decrypt encrypted content.
+ * <p>
* getKeyRequest() is used to obtain an opaque key request byte array that is
* delivered to the license server. The opaque key request byte array is returned
* in KeyRequest.data. The recommended URL to deliver the key request to is
* returned in KeyRequest.defaultUrl.
- *
+ * <p>
* After the app has received the key request response from the server,
* it should deliver to the response to the DRM engine plugin using the method
* {@link #provideKeyResponse}.
*
* @param scope may be a sessionId or a keySetId, depending on the specified keyType.
- * When the keyType is MEDIA_DRM_KEY_TYPE_STREAMING or MEDIA_DRM_KEY_TYPE_OFFLINE,
+ * When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE,
* scope should be set to the sessionId the keys will be provided to. When the keyType
- * is MEDIA_DRM_KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys
+ * is KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys
* being released. Releasing keys from a device invalidates them for all sessions.
* @param init container-specific data, its meaning is interpreted based on the
* mime type provided in the mimeType parameter. It could contain, for example,
* the content ID, key ID or other data obtained from the content metadata that is
* required in generating the key request. init may be null when keyType is
- * MEDIA_DRM_KEY_TYPE_RELEASE.
+ * KEY_TYPE_RELEASE.
* @param mimeType identifies the mime type of the content
* @param keyType specifes the type of the request. The request may be to acquire
* keys for streaming or offline content, or to release previously acquired
* keys, which are identified by a keySetId.
-
* @param optionalParameters are included in the key request message to
* allow a client application to provide additional message parameters to the server.
*/
public native KeyRequest getKeyRequest(byte[] scope, byte[] init,
String mimeType, int keyType,
- HashMap<String, String> optionalParameters)
- throws MediaDrmException;
+ HashMap<String, String> optionalParameters);
+
/**
* A key response is received from the license server by the app, then it is
* provided to the DRM engine plugin using provideKeyResponse. The byte array
* returned is a keySetId that can be used to later restore the keys to a new
- * session with the method {@link restoreKeys}, enabling offline key use.
+ * session with the method {@link #restoreKeys}, enabling offline key use.
*
* @param sessionId the session ID for the DRM session
* @param response the byte array response from the server
*/
- public native byte[] provideKeyResponse(byte[] sessionId, byte[] response)
- throws MediaDrmException;
+ public native byte[] provideKeyResponse(byte[] sessionId, byte[] response);
/**
* Restore persisted offline keys into a new session. keySetId identifies the
- * keys to load, obtained from a prior call to {@link provideKeyResponse}.
+ * keys to load, obtained from a prior call to {@link #provideKeyResponse}.
*
* @param sessionId the session ID for the DRM session
* @param keySetId identifies the saved key set to restore
*/
- public native void restoreKeys(byte[] sessionId, byte[] keySetId)
- throws MediaDrmException;
+ public native void restoreKeys(byte[] sessionId, byte[] keySetId);
/**
* Remove the current keys from a session.
*
* @param sessionId the session ID for the DRM session
*/
- public native void removeKeys(byte[] sessionId) throws MediaDrmException;
+ public native void removeKeys(byte[] sessionId);
/**
* Request an informative description of the key status for the session. The status is
@@ -296,25 +388,41 @@ public final class MediaDrm {
*
* @param sessionId the session ID for the DRM session
*/
- public native HashMap<String, String> queryKeyStatus(byte[] sessionId)
- throws MediaDrmException;
+ public native HashMap<String, String> queryKeyStatus(byte[] sessionId);
+
+ /**
+ * Contains the opaque data an app uses to request a certificate from a provisioning
+ * server
+ */
+ public final static class ProvisionRequest {
+ ProvisionRequest() {}
+
+ /**
+ * Get the opaque message data
+ */
+ public byte[] getData() { return mData; }
+
+ /**
+ * Get the default URL to use when sending the provision request
+ * message to a server, if known. The app may prefer to use a different
+ * provisioning server URL obtained from other sources.
+ */
+ public String getDefaultUrl() { return mDefaultUrl; }
- public final class ProvisionRequest {
- public ProvisionRequest() {}
- public byte[] data;
- public String defaultUrl;
+ private byte[] mData;
+ private String mDefaultUrl;
}
/**
* A provision request/response exchange occurs between the app and a provisioning
* server to retrieve a device certificate. If provisionining is required, the
- * MEDIA_DRM_EVENT_PROVISION_REQUIRED event will be sent to the event handler.
+ * EVENT_PROVISION_REQUIRED event will be sent to the event handler.
* getProvisionRequest is used to obtain the opaque provision request byte array that
* should be delivered to the provisioning server. The provision request byte array
* is returned in ProvisionRequest.data. The recommended URL to deliver the provision
* request to is returned in ProvisionRequest.defaultUrl.
*/
- public native ProvisionRequest getProvisionRequest() throws MediaDrmException;
+ public native ProvisionRequest getProvisionRequest();
/**
* After a provision response is received by the app, it is provided to the DRM
@@ -323,92 +431,91 @@ public final class MediaDrm {
* @param response the opaque provisioning response byte array to provide to the
* DRM engine plugin.
*/
- public native void provideProvisionResponse(byte[] response)
- throws MediaDrmException;
+ public native void provideProvisionResponse(byte[] response);
/**
- * A means of enforcing the contractual requirement for a concurrent stream limit
- * per subscriber across devices is provided via SecureStop. SecureStop is a means
- * of securely monitoring the lifetime of sessions. Since playback on a device can
- * be interrupted due to reboot, power failure, etc. a means of persisting the
- * lifetime information on the device is needed.
- *
- * A signed version of the sessionID is written to persistent storage on the device
- * when each MediaCrypto object is created. The sessionID is signed by the device
- * private key to prevent tampering.
- *
+ * A means of enforcing limits on the number of concurrent streams per subscriber
+ * across devices is provided via SecureStop. This is achieved by securely
+ * monitoring the lifetime of sessions.
+ * <p>
+ * Information from the server related to the current playback session is written
+ * to persistent storage on the device when each MediaCrypto object is created.
+ * <p>
* In the normal case, playback will be completed, the session destroyed and the
- * Secure Stops will be queried. The App queries secure stops and forwards the
+ * Secure Stops will be queried. The app queries secure stops and forwards the
* secure stop message to the server which verifies the signature and notifies the
* server side database that the session destruction has been confirmed. The persisted
* record on the client is only removed after positive confirmation that the server
* received the message using releaseSecureStops().
*/
- public native List<byte[]> getSecureStops() throws MediaDrmException;
+ public native List<byte[]> getSecureStops();
/**
* Process the SecureStop server response message ssRelease. After authenticating
- * the message, remove the SecureStops identiied in the response.
+ * the message, remove the SecureStops identified in the response.
*
* @param ssRelease the server response indicating which secure stops to release
*/
- public native void releaseSecureStops(byte[] ssRelease)
- throws MediaDrmException;
+ public native void releaseSecureStops(byte[] ssRelease);
/**
- * Read a DRM engine plugin property value, given the property name string. There are
- * several forms of property access functions, depending on the data type returned.
- *
+ * String property name: identifies the maker of the DRM engine plugin
+ */
+ public static final String PROPERTY_VENDOR = "vendor";
+
+ /**
+ * String property name: identifies the version of the DRM engine plugin
+ */
+ public static final String PROPERTY_VERSION = "version";
+
+ /**
+ * String property name: describes the DRM engine plugin
+ */
+ public static final String PROPERTY_DESCRIPTION = "description";
+
+ /**
+ * String property name: a comma-separated list of cipher and mac algorithms
+ * supported by CryptoSession. The list may be empty if the DRM engine
+ * plugin does not support CryptoSession operations.
+ */
+ public static final String PROPERTY_ALGORITHM = "algorithm";
+
+ /**
+ * Read a DRM engine plugin String property value, given the property name string.
+ * <p>
* Standard fields names are:
- * vendor String - identifies the maker of the DRM engine plugin
- * version String - identifies the version of the DRM engine plugin
- * description String - describes the DRM engine plugin
- * deviceUniqueId byte[] - The device unique identifier is established during device
- * provisioning and provides a means of uniquely identifying
- * each device
- * algorithms String - a comma-separate list of cipher and mac algorithms supported
- * by CryptoSession. The list may be empty if the DRM engine
- * plugin does not support CryptoSession operations.
+ * {@link #PROPERTY_VENDOR}, {@link #PROPERTY_VERSION},
+ * {@link #PROPERTY_DESCRIPTION}, {@link #PROPERTY_ALGORITHM}
*/
- public native String getPropertyString(String propertyName)
- throws MediaDrmException;
+ public native String getPropertyString(String propertyName);
- public native byte[] getPropertyByteArray(String propertyName)
- throws MediaDrmException;
/**
- * Write a DRM engine plugin property value. There are several forms of
- * property setting functions, depending on the data type being set.
+ * The device unique identifier is established during device provisioning and
+ * provides a means of uniquely identifying each device
*/
- public native void setPropertyString(String propertyName, String value)
- throws MediaDrmException;
+ public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
+
+ /**
+ * Read a DRM engine plugin byte array property value, given the property name string.
+ * <p>
+ * Standard fields names are {@link #PROPERTY_DEVICE_UNIQUE_ID}
+ */
+ public native byte[] getPropertyByteArray(String propertyName);
- public native void setPropertyByteArray(String propertyName, byte[] value)
- throws MediaDrmException;
/**
- * In addition to supporting decryption of DASH Common Encrypted Media, the
- * MediaDrm APIs provide the ability to securely deliver session keys from
- * an operator's session key server to a client device, based on the factory-installed
- * root of trust, and provide the ability to do encrypt, decrypt, sign and verify
- * with the session key on arbitrary user data.
- *
- * The CryptoSession class implements generic encrypt/decrypt/sign/verify methods
- * based on the established session keys. These keys are exchanged using the
- * getKeyRequest/provideKeyResponse methods.
- *
- * Applications of this capability could include securing various types of
- * purchased or private content, such as applications, books and other media,
- * photos or media delivery protocols.
- *
- * Operators can create session key servers that are functionally similar to a
- * license key server, except that instead of receiving license key requests and
- * providing encrypted content keys which are used specifically to decrypt A/V media
- * content, the session key server receives session key requests and provides
- * encrypted session keys which can be used for general purpose crypto operations.
+ * Set a DRM engine plugin String property value.
+ */
+ public native void setPropertyString(String propertyName, String value);
+
+ /**
+ * Set a DRM engine plugin byte array property value.
*/
+ public native void setPropertyByteArray(String propertyName, byte[] value);
+
private static final native void setCipherAlgorithmNative(MediaDrm drm, byte[] sessionId,
String algorithm);
@@ -429,61 +536,112 @@ public final class MediaDrm {
byte[] keyId, byte[] message,
byte[] signature);
+ /**
+ * In addition to supporting decryption of DASH Common Encrypted Media, the
+ * MediaDrm APIs provide the ability to securely deliver session keys from
+ * an operator's session key server to a client device, based on the factory-installed
+ * root of trust, and then perform encrypt, decrypt, sign and verify operations
+ * with the session key on arbitrary user data.
+ * <p>
+ * The CryptoSession class implements generic encrypt/decrypt/sign/verify methods
+ * based on the established session keys. These keys are exchanged using the
+ * getKeyRequest/provideKeyResponse methods.
+ * <p>
+ * Applications of this capability could include securing various types of
+ * purchased or private content, such as applications, books and other media,
+ * photos or media delivery protocols.
+ * <p>
+ * Operators can create session key servers that are functionally similar to a
+ * license key server, except that instead of receiving license key requests and
+ * providing encrypted content keys which are used specifically to decrypt A/V media
+ * content, the session key server receives session key requests and provides
+ * encrypted session keys which can be used for general purpose crypto operations.
+ * <p>
+ * A CryptoSession is obtained using {@link #getCryptoSession}
+ */
public final class CryptoSession {
private MediaDrm mDrm;
private byte[] mSessionId;
- /**
- * Construct a CryptoSession which can be used to encrypt, decrypt,
- * sign and verify messages or data using the session keys established
- * for the session using methods {@link getKeyRequest} and
- * {@link provideKeyResponse} using a session key server.
- *
- * @param sessionId the session ID for the session containing keys
- * to be used for encrypt, decrypt, sign and/or verify
- *
- * @param cipherAlgorithm the algorithm to use for encryption and
- * decryption ciphers. The algorithm string conforms to JCA Standard
- * Names for Cipher Transforms and is case insensitive. For example
- * "AES/CBC/PKCS5Padding".
- *
- * @param macAlgorithm the algorithm to use for sign and verify
- * The algorithm string conforms to JCA Standard Names for Mac
- * Algorithms and is case insensitive. For example "HmacSHA256".
- *
- * The list of supported algorithms for a DRM engine plugin can be obtained
- * using the method {@link getPropertyString("algorithms")}
- */
-
- public CryptoSession(MediaDrm drm, byte[] sessionId,
- String cipherAlgorithm, String macAlgorithm)
- throws MediaDrmException {
+ CryptoSession(MediaDrm drm, byte[] sessionId,
+ String cipherAlgorithm, String macAlgorithm)
+ {
mSessionId = sessionId;
mDrm = drm;
setCipherAlgorithmNative(drm, sessionId, cipherAlgorithm);
setMacAlgorithmNative(drm, sessionId, macAlgorithm);
}
+ /**
+ * Encrypt data using the CryptoSession's cipher algorithm
+ *
+ * @param keyid specifies which key to use
+ * @param input the data to encrypt
+ * @param iv the initialization vector to use for the cipher
+ */
public byte[] encrypt(byte[] keyid, byte[] input, byte[] iv) {
return encryptNative(mDrm, mSessionId, keyid, input, iv);
}
+ /**
+ * Decrypt data using the CryptoSessions's cipher algorithm
+ *
+ * @param keyid specifies which key to use
+ * @param input the data to encrypt
+ * @param iv the initialization vector to use for the cipher
+ */
public byte[] decrypt(byte[] keyid, byte[] input, byte[] iv) {
return decryptNative(mDrm, mSessionId, keyid, input, iv);
}
+ /**
+ * Sign data using the CryptoSessions's mac algorithm.
+ *
+ * @param keyid specifies which key to use
+ * @param message the data for which a signature is to be computed
+ */
public byte[] sign(byte[] keyid, byte[] message) {
return signNative(mDrm, mSessionId, keyid, message);
}
+
+ /**
+ * Verify a signature using the CryptoSessions's mac algorithm. Return true
+ * if the signatures match, false if they do no.
+ *
+ * @param keyid specifies which key to use
+ * @param message the data to verify
+ * @param signature the reference signature which will be compared with the
+ * computed signature
+ */
public boolean verify(byte[] keyid, byte[] message, byte[] signature) {
return verifyNative(mDrm, mSessionId, keyid, message, signature);
}
};
+ /**
+ * Obtain a CryptoSession object which can be used to encrypt, decrypt,
+ * sign and verify messages or data using the session keys established
+ * for the session using methods {@link #getKeyRequest} and
+ * {@link #provideKeyResponse} using a session key server.
+ *
+ * @param sessionId the session ID for the session containing keys
+ * to be used for encrypt, decrypt, sign and/or verify
+ * @param cipherAlgorithm the algorithm to use for encryption and
+ * decryption ciphers. The algorithm string conforms to JCA Standard
+ * Names for Cipher Transforms and is case insensitive. For example
+ * "AES/CBC/NoPadding".
+ * @param macAlgorithm the algorithm to use for sign and verify
+ * The algorithm string conforms to JCA Standard Names for Mac
+ * Algorithms and is case insensitive. For example "HmacSHA256".
+ * <p>
+ * The list of supported algorithms for a DRM engine plugin can be obtained
+ * using the method {@link #getPropertyString} with the property name
+ * "algorithms".
+ */
public CryptoSession getCryptoSession(byte[] sessionId,
String cipherAlgorithm,
String macAlgorithm)
- throws MediaDrmException {
+ {
return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm);
}
@@ -495,8 +653,7 @@ public final class MediaDrm {
public native final void release();
private static native final void native_init();
- private native final void native_setup(Object mediadrm_this, byte[] uuid)
- throws MediaDrmException;
+ private native final void native_setup(Object mediadrm_this, byte[] uuid);
private native final void native_finalize();
diff --git a/media/java/android/media/MediaDrmException.java b/media/java/android/media/MediaDrmException.java
index 6f81f90..d6f5ff4 100644
--- a/media/java/android/media/MediaDrmException.java
+++ b/media/java/android/media/MediaDrmException.java
@@ -19,8 +19,6 @@ package android.media;
/**
* Exception thrown if MediaDrm object could not be instantiated for
* whatever reason.
- *
- * @hide -- don't expose yet
*/
public final class MediaDrmException extends Exception {
public MediaDrmException(String detailMessage) {
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 4a5e82e..61a0134 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -999,7 +999,7 @@ public class RemoteControlClient
if (mEventHandler != null) {
// signal new client
mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN);
- mEventHandler.dispatchMessage(
+ mEventHandler.sendMessage(
mEventHandler.obtainMessage(MSG_NEW_INTERNAL_CLIENT_GEN,
/*arg1*/ generationId, /*arg2, ignored*/ 0));
// send the information
@@ -1007,12 +1007,12 @@ public class RemoteControlClient
mEventHandler.removeMessages(MSG_REQUEST_METADATA);
mEventHandler.removeMessages(MSG_REQUEST_TRANSPORTCONTROL);
mEventHandler.removeMessages(MSG_REQUEST_ARTWORK);
- mEventHandler.dispatchMessage(
+ mEventHandler.sendMessage(
mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE));
- mEventHandler.dispatchMessage(
+ mEventHandler.sendMessage(
mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL));
- mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA));
- mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK));
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA));
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK));
}
}
@@ -1020,7 +1020,7 @@ public class RemoteControlClient
// only post messages, we can't block here
if (mEventHandler != null) {
mEventHandler.removeMessages(MSG_NEW_CURRENT_CLIENT_GEN);
- mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
MSG_NEW_CURRENT_CLIENT_GEN, clientGeneration, 0/*ignored*/));
}
}
@@ -1028,7 +1028,7 @@ public class RemoteControlClient
public void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
// only post messages, we can't block here
if ((mEventHandler != null) && (rcd != null)) {
- mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
MSG_PLUG_DISPLAY, w, h, rcd));
}
}
@@ -1036,7 +1036,7 @@ public class RemoteControlClient
public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) {
// only post messages, we can't block here
if ((mEventHandler != null) && (rcd != null)) {
- mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
MSG_UNPLUG_DISPLAY, rcd));
}
}
@@ -1044,7 +1044,7 @@ public class RemoteControlClient
public void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h) {
// only post messages, we can't block here
if ((mEventHandler != null) && (rcd != null)) {
- mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
MSG_UPDATE_DISPLAY_ARTWORK_SIZE, w, h, rcd));
}
}
@@ -1053,7 +1053,7 @@ public class RemoteControlClient
// only post messages, we can't block here
if (mEventHandler != null) {
mEventHandler.removeMessages(MSG_SEEK_TO);
- mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
MSG_SEEK_TO, generationId /* arg1 */, 0 /* arg2, ignored */,
new Long(timeMs)));
}
@@ -1145,6 +1145,7 @@ public class RemoteControlClient
break;
case MSG_SEEK_TO:
onSeekTo(msg.arg1, ((Long)msg.obj).longValue());
+ break;
default:
Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
}
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index c32ba9d..d9d466e 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -458,22 +458,22 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) {
"(Ljava/lang/Object;IILjava/lang/Object;)V");
jfieldID field;
- GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_PROVISION_REQUIRED", "I");
+ GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
- GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_REQUIRED", "I");
+ GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
- GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_EXPIRED", "I");
+ GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
- GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_VENDOR_DEFINED", "I");
+ GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
- GET_FIELD_ID(gFields.keyRequest.data, clazz, "data", "[B");
- GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
+ GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
+ GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
- GET_FIELD_ID(gFields.provisionRequest.data, clazz, "data", "[B");
- GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
+ GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
+ GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
FIND_CLASS(clazz, "java/util/ArrayList");
GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
index 9146ccd..2c25236 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -30,6 +30,7 @@ import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -54,7 +55,10 @@ public class UsbDebuggingActivity extends AlertActivity
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
+ if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0) {
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
+ }
+
Intent intent = getIntent();
String fingerprints = intent.getStringExtra("fingerprints");
mKey = intent.getStringExtra("key");
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 7cb6b09..7f3fc43 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -251,8 +251,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mLidOpenRotation;
int mCarDockRotation;
int mDeskDockRotation;
- int mHdmiRotation;
- boolean mHdmiRotationLock;
+ int mUndockedHdmiRotation;
+ int mDemoHdmiRotation;
+ boolean mDemoHdmiRotationLock;
int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
int mUserRotation = Surface.ROTATION_0;
@@ -854,6 +855,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
com.android.internal.R.integer.config_carDockRotation);
mDeskDockRotation = readRotation(
com.android.internal.R.integer.config_deskDockRotation);
+ mUndockedHdmiRotation = readRotation(
+ com.android.internal.R.integer.config_undockedHdmiRotation);
mCarDockEnablesAccelerometer = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_carDockEnablesAccelerometer);
mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean(
@@ -1024,11 +1027,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// For demo purposes, allow the rotation of the HDMI display to be controlled.
// By default, HDMI locks rotation to landscape.
if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
- mHdmiRotation = mPortraitRotation;
+ mDemoHdmiRotation = mPortraitRotation;
} else {
- mHdmiRotation = mLandscapeRotation;
+ mDemoHdmiRotation = mLandscapeRotation;
}
- mHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
+ mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
}
@Override
@@ -4200,10 +4203,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// enable 180 degree rotation while docked.
preferredRotation = mDeskDockEnablesAccelerometer
? sensorRotation : mDeskDockRotation;
- } else if (mHdmiPlugged && mHdmiRotationLock) {
- // Ignore sensor when plugged into HDMI.
+ } else if (mHdmiPlugged && mDemoHdmiRotationLock) {
+ // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
// Note that the dock orientation overrides the HDMI orientation.
- preferredRotation = mHdmiRotation;
+ preferredRotation = mDemoHdmiRotation;
+ } else if (mHdmiPlugged && mDockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
+ && mUndockedHdmiRotation >= 0) {
+ // Ignore sensor when plugged into HDMI and an undocked orientation has
+ // been specified in the configuration (only for legacy devices without
+ // full multi-display support).
+ // Note that the dock orientation overrides the HDMI orientation.
+ preferredRotation = mUndockedHdmiRotation;
} else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
// Application just wants to remain locked in the last rotation.
preferredRotation = lastRotation;
@@ -4967,7 +4977,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pw.print(" mSeascapeRotation="); pw.println(mSeascapeRotation);
pw.print(prefix); pw.print("mPortraitRotation="); pw.print(mPortraitRotation);
pw.print(" mUpsideDownRotation="); pw.println(mUpsideDownRotation);
- pw.print(prefix); pw.print("mHdmiRotation="); pw.print(mHdmiRotation);
- pw.print(" mHdmiRotationLock="); pw.println(mHdmiRotationLock);
+ pw.print(prefix); pw.print("mDemoHdmiRotation="); pw.print(mDemoHdmiRotation);
+ pw.print(" mDemoHdmiRotationLock="); pw.println(mDemoHdmiRotationLock);
+ pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation);
}
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
index 77359ff..9b58803 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
@@ -23,12 +23,16 @@ import android.content.ContentResolver;
import android.content.Context;
import android.os.BatteryManager;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.Slog;
import android.view.View;
import android.widget.TextView;
@@ -37,6 +41,8 @@ import libcore.util.MutableInt;
import java.lang.ref.WeakReference;
import com.android.internal.R;
+import com.android.internal.widget.ILockSettings;
+import com.android.internal.widget.LockPatternUtils;
/***
* Manages a number of views inside of the given layout. See below for a list of widgets.
@@ -57,6 +63,8 @@ class KeyguardMessageArea extends TextView {
static final int SECURITY_MESSAGE_DURATION = 5000;
protected static final int FADE_DURATION = 750;
+ private static final String TAG = "KeyguardMessageArea";
+
// are we showing battery information?
boolean mShowingBatteryInfo = false;
@@ -82,6 +90,9 @@ class KeyguardMessageArea extends TextView {
CharSequence mMessage;
boolean mShowingMessage;
+ private CharSequence mSeparator;
+ private LockPatternUtils mLockPatternUtils;
+
Runnable mClearMessageRunnable = new Runnable() {
@Override
public void run() {
@@ -156,8 +167,6 @@ class KeyguardMessageArea extends TextView {
}
};
- private CharSequence mSeparator;
-
public KeyguardMessageArea(Context context) {
this(context, null);
}
@@ -165,6 +174,8 @@ class KeyguardMessageArea extends TextView {
public KeyguardMessageArea(Context context, AttributeSet attrs) {
super(context, attrs);
+ mLockPatternUtils = new LockPatternUtils(context);
+
// This is required to ensure marquee works
setSelected(true);
@@ -228,11 +239,12 @@ class KeyguardMessageArea extends TextView {
String getOwnerInfo() {
ContentResolver res = getContext().getContentResolver();
- final boolean ownerInfoEnabled = Settings.Secure.getIntForUser(res,
- Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
- return ownerInfoEnabled && !mShowingMessage ?
- Settings.Secure.getStringForUser(res, Settings.Secure.LOCK_SCREEN_OWNER_INFO,
- UserHandle.USER_CURRENT) : null;
+ String info = null;
+ final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled();
+ if (ownerInfoEnabled && !mShowingMessage) {
+ info = mLockPatternUtils.getOwnerInfo(mLockPatternUtils.getCurrentUser());
+ }
+ return info;
}
private CharSequence getChargeInfo(MutableInt icon) {
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index a28c387..f872cc3 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1595,7 +1595,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
ApplicationInfo ai = mIPackageManager.getApplicationInfo(imm.getPackageName(),
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
mSettings.getCurrentUserId());
- if (ai.enabledSetting
+ if (ai != null && ai.enabledSetting
== PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
diff --git a/services/java/com/android/server/LockSettingsService.java b/services/java/com/android/server/LockSettingsService.java
index e20a21f..41cc4d7 100644
--- a/services/java/com/android/server/LockSettingsService.java
+++ b/services/java/com/android/server/LockSettingsService.java
@@ -19,6 +19,11 @@ package com.android.server;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+
+import static android.content.Context.USER_SERVICE;
+import static android.Manifest.permission.READ_PROFILE;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
@@ -27,8 +32,10 @@ import android.os.Environment;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
+import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
import android.util.Slog;
@@ -40,6 +47,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
+import java.util.List;
/**
* Keeps the lock pattern/password data and related settings for each user.
@@ -79,23 +87,52 @@ public class LockSettingsService extends ILockSettings.Stub {
private void migrateOldData() {
try {
- if (getString("migrated", null, 0) != null) {
- // Already migrated
- return;
+ // These Settings moved before multi-user was enabled, so we only have to do it for the
+ // root user.
+ if (getString("migrated", null, 0) == null) {
+ final ContentResolver cr = mContext.getContentResolver();
+ for (String validSetting : VALID_SETTINGS) {
+ String value = Settings.Secure.getString(cr, validSetting);
+ if (value != null) {
+ setString(validSetting, value, 0);
+ }
+ }
+ // No need to move the password / pattern files. They're already in the right place.
+ setString("migrated", "true", 0);
+ Slog.i(TAG, "Migrated lock settings to new location");
}
- final ContentResolver cr = mContext.getContentResolver();
- for (String validSetting : VALID_SETTINGS) {
- String value = Settings.Secure.getString(cr, validSetting);
- if (value != null) {
- setString(validSetting, value, 0);
+ // These Settings changed after multi-user was enabled, hence need to be moved per user.
+ if (getString("migrated_user_specific", null, 0) == null) {
+ final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
+ final ContentResolver cr = mContext.getContentResolver();
+ List<UserInfo> users = um.getUsers();
+ for (int user = 0; user < users.size(); user++) {
+ int userId = users.get(user).getUserHandle().getIdentifier();
+ for (String perUserSetting : MIGRATE_SETTINGS_PER_USER) {
+ // Handle Strings
+ String value = Settings.Secure.getStringForUser(cr, perUserSetting, userId);
+ if (value != null) {
+ setString(perUserSetting, value, userId);
+ Settings.Secure.putStringForUser(cr, perUserSetting, "", userId);
+ continue;
+ }
+
+ // Handle integers
+ try {
+ int ivalue = Settings.Secure.getIntForUser(cr, perUserSetting, userId);
+ setLong(perUserSetting, ivalue, userId);
+ Settings.Secure.putIntForUser(cr, perUserSetting, 0, userId);
+ } catch (SettingNotFoundException e) {
+ }
+ }
}
+ // No need to move the password / pattern files. They're already in the right place.
+ setString("migrated_user_specific", "true", 0);
+ Slog.i(TAG, "Migrated per-user lock settings to new location");
}
- // No need to move the password / pattern files. They're already in the right place.
- setString("migrated", "true", 0);
- Slog.i(TAG, "Migrated lock settings to new location");
} catch (RemoteException re) {
- Slog.e(TAG, "Unable to migrate old data");
+ Slog.e(TAG, "Unable to migrate old data", re);
}
}
@@ -115,12 +152,16 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- private static final void checkReadPermission(int userId) {
+ private final void checkReadPermission(String requestedKey, int userId) {
final int callingUid = Binder.getCallingUid();
- if (UserHandle.getAppId(callingUid) != android.os.Process.SYSTEM_UID
- && UserHandle.getUserId(callingUid) != userId) {
- throw new SecurityException("uid=" + callingUid
- + " not authorized to read settings of user " + userId);
+ for (int i = 0; i < READ_PROFILE_PROTECTED_SETTINGS.length; i++) {
+ String key = READ_PROFILE_PROTECTED_SETTINGS[i];
+ if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_PROFILE)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("uid=" + callingUid
+ + " needs permission " + READ_PROFILE + " to read "
+ + requestedKey + " for user " + userId);
+ }
}
}
@@ -147,7 +188,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
- //checkReadPermission(userId);
+ checkReadPermission(key, userId);
String value = readFromDb(key, null, userId);
return TextUtils.isEmpty(value) ?
@@ -156,7 +197,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public long getLong(String key, long defaultValue, int userId) throws RemoteException {
- //checkReadPermission(userId);
+ checkReadPermission(key, userId);
String value = readFromDb(key, null, userId);
return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
@@ -164,7 +205,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public String getString(String key, String defaultValue, int userId) throws RemoteException {
- //checkReadPermission(userId);
+ checkReadPermission(key, userId);
return readFromDb(key, defaultValue, userId);
}
@@ -404,5 +445,13 @@ public class LockSettingsService extends ILockSettings.Stub {
Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
Secure.LOCK_PATTERN_VISIBLE,
Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
- };
+ };
+
+ private static final String[] MIGRATE_SETTINGS_PER_USER = new String[] {
+ Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
+ Secure.LOCK_SCREEN_OWNER_INFO
+ };
+
+ // These are protected with a read permission
+ private static final String[] READ_PROFILE_PROTECTED_SETTINGS = MIGRATE_SETTINGS_PER_USER;
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index fa18e76..3bebf91 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -1676,8 +1676,12 @@ public class NotificationManagerService extends INotificationManager.Stub
.getSystemService(Context.AUDIO_SERVICE);
// sound
+
+ // should we use the default notification sound? (indicated either by DEFAULT_SOUND
+ // or because notification.sound is pointing at Settings.System.NOTIFICATION_SOUND)
final boolean useDefaultSound =
- (notification.defaults & Notification.DEFAULT_SOUND) != 0;
+ (notification.defaults & Notification.DEFAULT_SOUND) != 0
+ || Settings.System.DEFAULT_NOTIFICATION_URI.equals(notification.sound);
Uri soundUri = null;
boolean hasValidSound = false;
diff --git a/services/java/com/android/server/am/NativeCrashListener.java b/services/java/com/android/server/am/NativeCrashListener.java
index 0688c50..de439d7 100644
--- a/services/java/com/android/server/am/NativeCrashListener.java
+++ b/services/java/com/android/server/am/NativeCrashListener.java
@@ -43,13 +43,14 @@ import java.net.InetUnixAddress;
class NativeCrashListener extends Thread {
static final String TAG = "NativeCrashListener";
static final boolean DEBUG = false;
+ static final boolean MORE_DEBUG = DEBUG && false;
// Must match the path defined in debuggerd.c.
static final String DEBUGGERD_SOCKET_PATH = "/data/system/ndebugsocket";
// Use a short timeout on socket operations and abandon the connection
// on hard errors
- static final long SOCKET_TIMEOUT_MILLIS = 1000; // 1 second
+ static final long SOCKET_TIMEOUT_MILLIS = 2000; // 2 seconds
final ActivityManagerService mAm;
@@ -124,9 +125,9 @@ class NativeCrashListener extends Thread {
InetSocketAddress peer = new InetSocketAddress();
FileDescriptor peerFd = null;
try {
- if (DEBUG) Slog.v(TAG, "Waiting for debuggerd connection");
+ if (MORE_DEBUG) Slog.v(TAG, "Waiting for debuggerd connection");
peerFd = Libcore.os.accept(serverFd, peer);
- if (DEBUG) Slog.v(TAG, "Got debuggerd socket " + peerFd);
+ if (MORE_DEBUG) Slog.v(TAG, "Got debuggerd socket " + peerFd);
if (peerFd != null) {
// Only the superuser is allowed to talk to us over this socket
StructUcred credentials =
@@ -145,7 +146,12 @@ class NativeCrashListener extends Thread {
if (peerFd != null) {
try {
Libcore.os.write(peerFd, ackSignal, 0, 1);
- } catch (Exception e) { /* we don't care about failures here */ }
+ } catch (Exception e) {
+ /* we don't care about failures here */
+ if (MORE_DEBUG) {
+ Slog.d(TAG, "Exception writing ack: " + e.getMessage());
+ }
+ }
}
}
}
@@ -183,7 +189,7 @@ class NativeCrashListener extends Thread {
// Read the crash report from the debuggerd connection
void consumeNativeCrashData(FileDescriptor fd) {
- if (DEBUG) Slog.i(TAG, "debuggerd connected");
+ if (MORE_DEBUG) Slog.i(TAG, "debuggerd connected");
final byte[] buf = new byte[4096];
final ByteArrayOutputStream os = new ByteArrayOutputStream(4096);
@@ -218,7 +224,7 @@ class NativeCrashListener extends Thread {
// get some data
bytes = Libcore.os.read(fd, buf, 0, buf.length);
if (bytes > 0) {
- if (DEBUG) {
+ if (MORE_DEBUG) {
String s = new String(buf, 0, bytes, "UTF-8");
Slog.v(TAG, "READ=" + bytes + "> " + s);
}
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index df90a56..11c6dab 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -88,8 +88,13 @@ public class UserManagerService extends IUserManager.Stub {
private static final String TAG_ENTRY = "entry";
private static final String TAG_VALUE = "value";
private static final String ATTR_KEY = "key";
+ private static final String ATTR_VALUE_TYPE = "type";
private static final String ATTR_MULTIPLE = "m";
+ private static final String ATTR_TYPE_STRING_ARRAY = "sa";
+ private static final String ATTR_TYPE_STRING = "s";
+ private static final String ATTR_TYPE_BOOLEAN = "b";
+
private static final String USER_INFO_DIR = "system" + File.separator + "users";
private static final String USER_LIST_FILENAME = "userlist.xml";
private static final String USER_PHOTO_FILENAME = "photo.png";
@@ -965,7 +970,12 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
- public List<RestrictionEntry> getApplicationRestrictions(String packageName, int userId) {
+ public Bundle getApplicationRestrictions(String packageName) {
+ return getApplicationRestrictionsForUser(packageName, UserHandle.getCallingUserId());
+ }
+
+ @Override
+ public Bundle getApplicationRestrictionsForUser(String packageName, int userId) {
if (UserHandle.getCallingUserId() != userId
|| !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
checkManageUsersPermission("Only system can get restrictions for other users/apps");
@@ -977,7 +987,7 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
- public void setApplicationRestrictions(String packageName, List<RestrictionEntry> entries,
+ public void setApplicationRestrictions(String packageName, Bundle restrictions,
int userId) {
if (UserHandle.getCallingUserId() != userId
|| !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
@@ -985,7 +995,7 @@ public class UserManagerService extends IUserManager.Stub {
}
synchronized (mPackagesLock) {
// Write the restrictions to XML
- writeApplicationRestrictionsLocked(packageName, entries, userId);
+ writeApplicationRestrictionsLocked(packageName, restrictions, userId);
}
}
@@ -1001,9 +1011,9 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- private List<RestrictionEntry> readApplicationRestrictionsLocked(String packageName,
+ private Bundle readApplicationRestrictionsLocked(String packageName,
int userId) {
- final ArrayList<RestrictionEntry> entries = new ArrayList<RestrictionEntry>();
+ final Bundle restrictions = new Bundle();
final ArrayList<String> values = new ArrayList<String>();
FileInputStream fis = null;
@@ -1023,12 +1033,13 @@ public class UserManagerService extends IUserManager.Stub {
if (type != XmlPullParser.START_TAG) {
Slog.e(LOG_TAG, "Unable to read restrictions file "
+ restrictionsFile.getBaseFile());
- return entries;
+ return restrictions;
}
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_ENTRY)) {
String key = parser.getAttributeValue(null, ATTR_KEY);
+ String valType = parser.getAttributeValue(null, ATTR_VALUE_TYPE);
String multiple = parser.getAttributeValue(null, ATTR_MULTIPLE);
if (multiple != null) {
int count = Integer.parseInt(multiple);
@@ -1041,14 +1052,13 @@ public class UserManagerService extends IUserManager.Stub {
}
String [] valueStrings = new String[values.size()];
values.toArray(valueStrings);
- Slog.d(LOG_TAG, "Got RestrictionEntry " + key + "," + valueStrings);
- RestrictionEntry entry = new RestrictionEntry(key, valueStrings);
- entries.add(entry);
+ restrictions.putStringArray(key, valueStrings);
+ } else if (ATTR_TYPE_BOOLEAN.equals(valType)) {
+ restrictions.putBoolean(key, Boolean.parseBoolean(
+ parser.nextText().trim()));
} else {
String value = parser.nextText().trim();
- Slog.d(LOG_TAG, "Got RestrictionEntry " + key + "," + value);
- RestrictionEntry entry = new RestrictionEntry(key, value);
- entries.add(entry);
+ restrictions.putString(key, value);
}
}
}
@@ -1063,11 +1073,11 @@ public class UserManagerService extends IUserManager.Stub {
}
}
}
- return entries;
+ return restrictions;
}
private void writeApplicationRestrictionsLocked(String packageName,
- List<RestrictionEntry> entries, int userId) {
+ Bundle restrictions, int userId) {
FileOutputStream fos = null;
AtomicFile restrictionsFile = new AtomicFile(
new File(Environment.getUserSystemDirectory(userId),
@@ -1084,18 +1094,24 @@ public class UserManagerService extends IUserManager.Stub {
serializer.startTag(null, TAG_RESTRICTIONS);
- for (RestrictionEntry entry : entries) {
+ for (String key : restrictions.keySet()) {
+ Object value = restrictions.get(key);
serializer.startTag(null, TAG_ENTRY);
- serializer.attribute(null, ATTR_KEY, entry.getKey());
- if (entry.getSelectedString() != null || entry.getAllSelectedStrings() == null) {
- String value = entry.getSelectedString();
- serializer.text(value != null ? value : "");
+ serializer.attribute(null, ATTR_KEY, key);
+
+ if (value instanceof Boolean) {
+ serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BOOLEAN);
+ serializer.text(value.toString());
+ } else if (value == null || value instanceof String) {
+ serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING);
+ serializer.text(value != null ? (String) value : "");
} else {
- String[] values = entry.getAllSelectedStrings();
+ serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING_ARRAY);
+ String[] values = (String[]) value;
serializer.attribute(null, ATTR_MULTIPLE, Integer.toString(values.length));
- for (String value : values) {
+ for (String choice : values) {
serializer.startTag(null, TAG_VALUE);
- serializer.text(value != null ? value : "");
+ serializer.text(choice != null ? choice : "");
serializer.endTag(null, TAG_VALUE);
}
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 1d1fda5..bc442ce 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -5490,6 +5490,7 @@ public class WindowManagerService extends IWindowManager.Stub
ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
matrix.postTranslate(-FloatMath.ceil(frame.left*scale), -FloatMath.ceil(frame.top*scale));
Canvas canvas = new Canvas(bm);
+ canvas.drawColor(0xFF000000);
canvas.drawBitmap(rawss, matrix, null);
canvas.setBitmap(null);
diff --git a/tests/CanvasCompare/AndroidManifest.xml b/tests/CanvasCompare/AndroidManifest.xml
index 1cb8c37..b55e290 100644
--- a/tests/CanvasCompare/AndroidManifest.xml
+++ b/tests/CanvasCompare/AndroidManifest.xml
@@ -15,8 +15,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.test.hwuicompare" >
- <!-- for perfhud -->
<uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:label="@string/app_name"
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java
index e0ff1dc..1ed4723 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java
@@ -16,11 +16,20 @@
package com.android.test.hwuicompare;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.TreeSet;
-import com.android.test.hwuicompare.R;
+import org.json.JSONException;
+import org.json.JSONObject;
import android.os.Bundle;
+import android.os.Environment;
import android.os.Trace;
import android.util.Log;
import android.widget.ImageView;
@@ -31,20 +40,31 @@ public class AutomaticActivity extends CompareActivity {
private static final float ERROR_DISPLAY_THRESHOLD = 0.01f;
protected static final boolean DRAW_BITMAPS = false;
- private ImageView mSoftwareImageView = null;
- private ImageView mHardwareImageView = null;
+ /**
+ * Threshold of error change required to consider a test regressed/improved
+ */
+ private static final float ERROR_CHANGE_THRESHOLD = 0.001f;
- private static final float[] ERROR_CUTOFFS = {0, 0.005f, 0.01f, 0.02f, 0.05f, 0.1f, 0.25f, 0.5f, 1f, 2f};
- private float[] mErrorRates = new float[ERROR_CUTOFFS.length];
+ private static final float[] ERROR_CUTOFFS = {
+ 0, 0.005f, 0.01f, 0.02f, 0.05f, 0.1f, 0.25f, 0.5f, 1f, 2f
+ };
+
+ private final float[] mErrorRates = new float[ERROR_CUTOFFS.length];
private float mTotalTests = 0;
private float mTotalError = 0;
+ private int mTestsRegressed = 0;
+ private int mTestsImproved = 0;
- public abstract static class TestCallback {
+ private ImageView mSoftwareImageView = null;
+ private ImageView mHardwareImageView = null;
+
+
+ public abstract static class FinalCallback {
abstract void report(String name, float value);
- void complete() {}
+ void complete() {};
}
- private ArrayList<TestCallback> mTestCallbacks = new ArrayList<TestCallback>();
+ private final ArrayList<FinalCallback> mFinalCallbacks = new ArrayList<FinalCallback>();
Runnable mRunnable = new Runnable() {
@Override
@@ -64,32 +84,11 @@ public class AutomaticActivity extends CompareActivity {
float error = mErrorCalculator.calcErrorRS(mSoftwareBitmap, mHardwareBitmap);
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
- if (error > ERROR_DISPLAY_THRESHOLD) {
- String modname = "";
- for (String s : DisplayModifier.getLastAppliedModifications()) {
- modname = modname.concat(s + ".");
- }
- Log.d(LOG_TAG, String.format("error for %s was %2.9f", modname, error));
- }
- for (int i = 0; i < ERROR_CUTOFFS.length; i++) {
- if (error <= ERROR_CUTOFFS[i]) break;
- mErrorRates[i]++;
- }
- mTotalError += error;
- mTotalTests++;
+ final String[] modifierNames = DisplayModifier.getLastAppliedModifications();
+ handleError(modifierNames, error);
if (DisplayModifier.step()) {
- for (TestCallback c : mTestCallbacks) {
- c.report("averageError", (mTotalError / mTotalTests));
- for (int i = 1; i < ERROR_CUTOFFS.length; i++) {
- c.report(String.format("error over %1.3f", ERROR_CUTOFFS[i]),
- mErrorRates[i]/mTotalTests);
- }
- c.complete();
- }
-
- Toast.makeText(getApplicationContext(), "done!", Toast.LENGTH_SHORT).show();
- finish();
+ finishTest();
} else {
mHardwareView.invalidate();
if (DRAW_BITMAPS) {
@@ -116,11 +115,186 @@ public class AutomaticActivity extends CompareActivity {
mHardwareImageView = (ImageView) findViewById(R.id.hardware_image_view);
onCreateCommon(mRunnable);
- mTestCallbacks.add(new TestCallback() {
+ beginTest();
+ }
+
+ private static class TestResult {
+ TestResult(String label, float error) {
+ mLabel = label;
+ mTotalError = error;
+ mCount = 1;
+ }
+ public void addInto(float error) {
+ mTotalError += error;
+ mCount++;
+ }
+ public float getAverage() {
+ return mTotalError / mCount;
+ }
+ final String mLabel;
+ float mTotalError;
+ int mCount;
+ }
+
+ JSONObject mOutputJson = null;
+ JSONObject mInputJson = null;
+ final HashMap<String, TestResult> mModifierResults = new HashMap<String, TestResult>();
+ final HashMap<String, TestResult> mIndividualResults = new HashMap<String, TestResult>();
+ final HashMap<String, TestResult> mModifierDiffResults = new HashMap<String, TestResult>();
+ final HashMap<String, TestResult> mIndividualDiffResults = new HashMap<String, TestResult>();
+ private void beginTest() {
+ mFinalCallbacks.add(new FinalCallback() {
+ @Override
void report(String name, float value) {
Log.d(LOG_TAG, name + " " + value);
};
});
+
+ File inputFile = new File(Environment.getExternalStorageDirectory(),
+ "CanvasCompareInput.json");
+ if (inputFile.exists() && inputFile.canRead() && inputFile.length() > 0) {
+ try {
+ FileInputStream inputStream = new FileInputStream(inputFile);
+ Log.d(LOG_TAG, "Parsing input file...");
+ StringBuffer content = new StringBuffer((int)inputFile.length());
+ byte[] buffer = new byte[1024];
+ while (inputStream.read(buffer) != -1) {
+ content.append(new String(buffer));
+ }
+ mInputJson = new JSONObject(content.toString());
+ inputStream.close();
+ Log.d(LOG_TAG, "Parsed input file with " + mInputJson.length() + " entries");
+ } catch (JSONException e) {
+ Log.e(LOG_TAG, "error parsing input json", e);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "error reading input json from sd", e);
+ }
+ }
+
+ mOutputJson = new JSONObject();
+ }
+
+ private static void logTestResultHash(String label, HashMap<String, TestResult> map) {
+ Log.d(LOG_TAG, "---------------");
+ Log.d(LOG_TAG, label + ":");
+ Log.d(LOG_TAG, "---------------");
+ TreeSet<TestResult> set = new TreeSet<TestResult>(new Comparator<TestResult>() {
+ @Override
+ public int compare(TestResult lhs, TestResult rhs) {
+ if (lhs == rhs) return 0; // don't need to worry about complex equality
+
+ int cmp = Float.compare(lhs.getAverage(), rhs.getAverage());
+ if (cmp != 0) {
+ return cmp;
+ }
+ return lhs.mLabel.compareTo(rhs.mLabel);
+ }
+ });
+
+ for (TestResult t : map.values()) {
+ set.add(t);
+ }
+
+ for (TestResult t : set.descendingSet()) {
+ if (Math.abs(t.getAverage()) > ERROR_DISPLAY_THRESHOLD) {
+ Log.d(LOG_TAG, String.format("%2.4f : %s", t.getAverage(), t.mLabel));
+ }
+ }
+ Log.d(LOG_TAG, "");
+ }
+
+ private void finishTest() {
+ for (FinalCallback c : mFinalCallbacks) {
+ c.report("averageError", (mTotalError / mTotalTests));
+ for (int i = 1; i < ERROR_CUTOFFS.length; i++) {
+ c.report(String.format("tests with error over %1.3f", ERROR_CUTOFFS[i]),
+ mErrorRates[i]);
+ }
+ if (mInputJson != null) {
+ c.report("tests regressed", mTestsRegressed);
+ c.report("tests improved", mTestsImproved);
+ }
+ c.complete();
+ }
+
+ try {
+ if (mOutputJson != null) {
+ String outputString = mOutputJson.toString(4);
+ File outputFile = new File(Environment.getExternalStorageDirectory(),
+ "CanvasCompareOutput.json");
+ FileOutputStream outputStream = new FileOutputStream(outputFile);
+ outputStream.write(outputString.getBytes());
+ outputStream.close();
+ Log.d(LOG_TAG, "Saved output file with " + mOutputJson.length() + " entries");
+ }
+ } catch (JSONException e) {
+ Log.e(LOG_TAG, "error during JSON stringify", e);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "error storing JSON output on sd", e);
+ }
+
+ logTestResultHash("Modifier change vs previous", mModifierDiffResults);
+ logTestResultHash("Invidual test change vs previous", mIndividualDiffResults);
+ logTestResultHash("Modifier average test results", mModifierResults);
+ logTestResultHash("Individual test results", mIndividualResults);
+
+ Toast.makeText(getApplicationContext(), "done!", Toast.LENGTH_SHORT).show();
+ finish();
+ }
+
+ /**
+ * Inserts the error value into all TestResult objects, associated with each of its modifiers
+ */
+ private static void addForAllModifiers(String fullName, float error, String[] modifierNames,
+ HashMap<String, TestResult> modifierResults) {
+ for (String modifierName : modifierNames) {
+ TestResult r = modifierResults.get(fullName);
+ if (r == null) {
+ modifierResults.put(modifierName, new TestResult(modifierName, error));
+ } else {
+ r.addInto(error);
+ }
+ }
+ }
+
+ private void handleError(final String[] modifierNames, final float error) {
+ String fullName = "";
+ for (String s : modifierNames) {
+ fullName = fullName.concat("." + s);
+ }
+ fullName = fullName.substring(1);
+
+ float deltaError = 0;
+ if (mInputJson != null) {
+ try {
+ deltaError = error - (float)mInputJson.getDouble(fullName);
+ } catch (JSONException e) {
+ Log.w(LOG_TAG, "Warning: unable to read from input json", e);
+ }
+ if (deltaError > ERROR_CHANGE_THRESHOLD) mTestsRegressed++;
+ if (deltaError < -ERROR_CHANGE_THRESHOLD) mTestsImproved++;
+ mIndividualDiffResults.put(fullName, new TestResult(fullName, deltaError));
+ addForAllModifiers(fullName, deltaError, modifierNames, mModifierDiffResults);
+ }
+
+ mIndividualResults.put(fullName, new TestResult(fullName, error));
+ addForAllModifiers(fullName, error, modifierNames, mModifierResults);
+
+ try {
+ if (mOutputJson != null) {
+ mOutputJson.put(fullName, error);
+ }
+ } catch (JSONException e) {
+ Log.e(LOG_TAG, "exception during JSON recording", e);
+ mOutputJson = null;
+ }
+
+ for (int i = 0; i < ERROR_CUTOFFS.length; i++) {
+ if (error <= ERROR_CUTOFFS[i]) break;
+ mErrorRates[i]++;
+ }
+ mTotalError += error;
+ mTotalTests++;
}
@Override
@@ -130,7 +304,7 @@ public class AutomaticActivity extends CompareActivity {
}
// FOR TESTING
- public void setCallback(TestCallback c) {
- mTestCallbacks.add(c);
+ public void setFinalCallback(FinalCallback c) {
+ mFinalCallbacks.add(c);
}
}
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java
index 6ea8237..1ff153c 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java
@@ -1,6 +1,6 @@
package com.android.test.hwuicompare;
-import com.android.test.hwuicompare.AutomaticActivity.TestCallback;
+import com.android.test.hwuicompare.AutomaticActivity.FinalCallback;
import android.os.Bundle;
import android.test.ActivityInstrumentationTestCase2;
@@ -18,7 +18,7 @@ public class Test extends ActivityInstrumentationTestCase2<AutomaticActivity> {
super.setUp();
mBundle = new Bundle();
mActivity = getActivity();
- mActivity.setCallback(new TestCallback() {
+ mActivity.setFinalCallback(new FinalCallback() {
@Override
void report(String key, float value) {