Merge "Slightly more legible background for notification panel."
diff --git a/api/current.xml b/api/current.xml
index 87394ce..2427376 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -19042,6 +19042,19 @@
<parameter name="items" type="android.animation.Animator...">
</parameter>
</method>
+<method name="playSequentially"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="items" type="java.util.List<android.animation.Animator>">
+</parameter>
+</method>
<method name="playTogether"
return="void"
abstract="false"
@@ -19055,6 +19068,19 @@
<parameter name="items" type="android.animation.Animator...">
</parameter>
</method>
+<method name="playTogether"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="items" type="java.util.Collection<android.animation.Animator>">
+</parameter>
+</method>
<method name="setDuration"
return="android.animation.AnimatorSet"
abstract="false"
@@ -249335,7 +249361,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
</parameter>
</method>
</interface>
@@ -249367,6 +249393,25 @@
</package>
<package name="dalvik.bytecode"
>
+<class name="OpcodeInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="MAXIMUM_VALUE"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<interface name="Opcodes"
abstract="true"
static="false"
@@ -249722,7 +249767,7 @@
value="236"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250063,7 +250108,7 @@
value="238"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250074,7 +250119,7 @@
value="239"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250371,7 +250416,7 @@
value="244"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250382,7 +250427,7 @@
value="242"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250415,7 +250460,7 @@
value="243"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250426,7 +250471,7 @@
value="232"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250525,7 +250570,7 @@
value="240"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250602,7 +250647,7 @@
value="250"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250613,7 +250658,7 @@
value="251"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250646,7 +250691,7 @@
value="248"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250657,7 +250702,7 @@
value="249"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250734,7 +250779,7 @@
value="247"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250745,7 +250790,7 @@
value="245"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250778,7 +250823,7 @@
value="246"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250789,7 +250834,7 @@
value="233"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -251537,7 +251582,7 @@
value="234"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -251746,7 +251791,7 @@
value="235"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -251856,7 +251901,7 @@
value="237"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -334583,7 +334628,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="minSize" type="int">
+<parameter name="numElements" type="int">
</parameter>
</constructor>
<constructor name="ArrayDeque"
@@ -334849,7 +334894,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="obj" type="java.lang.Object">
+<parameter name="o" type="java.lang.Object">
</parameter>
</method>
<method name="removeLast"
@@ -334873,7 +334918,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="obj" type="java.lang.Object">
+<parameter name="o" type="java.lang.Object">
</parameter>
</method>
<method name="size"
@@ -339631,6 +339676,19 @@
>
<implements name="java.util.Queue">
</implements>
+<method name="add"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
<method name="addFirst"
return="void"
abstract="true"
@@ -339657,6 +339715,19 @@
<parameter name="e" type="E">
</parameter>
</method>
+<method name="contains"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
<method name="descendingIterator"
return="java.util.Iterator<E>"
abstract="true"
@@ -339668,6 +339739,17 @@
visibility="public"
>
</method>
+<method name="element"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getFirst"
return="E"
abstract="true"
@@ -339690,6 +339772,30 @@
visibility="public"
>
</method>
+<method name="iterator"
+ return="java.util.Iterator<E>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="offer"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
<method name="offerFirst"
return="boolean"
abstract="true"
@@ -339716,6 +339822,17 @@
<parameter name="e" type="E">
</parameter>
</method>
+<method name="peek"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="peekFirst"
return="E"
abstract="true"
@@ -339738,6 +339855,17 @@
visibility="public"
>
</method>
+<method name="poll"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="pollFirst"
return="E"
abstract="true"
@@ -339784,6 +339912,30 @@
<parameter name="e" type="E">
</parameter>
</method>
+<method name="remove"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="remove"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
<method name="removeFirst"
return="E"
abstract="true"
@@ -339832,6 +339984,17 @@
<parameter name="o" type="java.lang.Object">
</parameter>
</method>
+<method name="size"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
</interface>
<class name="Dictionary"
extends="java.lang.Object"
@@ -343756,11 +343919,24 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="endKey" type="K">
+<parameter name="toKey" type="K">
</parameter>
<parameter name="inclusive" type="boolean">
</parameter>
</method>
+<method name="headMap"
+ return="java.util.SortedMap<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="toKey" type="K">
+</parameter>
+</method>
<method name="higherEntry"
return="java.util.Map.Entry<K, V>"
abstract="true"
@@ -343867,13 +344043,28 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="startKey" type="K">
+<parameter name="fromKey" type="K">
</parameter>
-<parameter name="startInclusive" type="boolean">
+<parameter name="fromInclusive" type="boolean">
</parameter>
-<parameter name="endKey" type="K">
+<parameter name="toKey" type="K">
</parameter>
-<parameter name="endInclusive" type="boolean">
+<parameter name="toInclusive" type="boolean">
+</parameter>
+</method>
+<method name="subMap"
+ return="java.util.SortedMap<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromKey" type="K">
+</parameter>
+<parameter name="toKey" type="K">
</parameter>
</method>
<method name="tailMap"
@@ -343886,11 +344077,24 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="startKey" type="K">
+<parameter name="fromKey" type="K">
</parameter>
<parameter name="inclusive" type="boolean">
</parameter>
</method>
+<method name="tailMap"
+ return="java.util.SortedMap<K, V>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromKey" type="K">
+</parameter>
+</method>
</interface>
<interface name="NavigableSet"
abstract="true"
@@ -343959,9 +344163,22 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="end" type="E">
+<parameter name="toElement" type="E">
</parameter>
-<parameter name="endInclusive" type="boolean">
+<parameter name="inclusive" type="boolean">
+</parameter>
+</method>
+<method name="headSet"
+ return="java.util.SortedSet<E>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="toElement" type="E">
</parameter>
</method>
<method name="higher"
@@ -343977,6 +344194,17 @@
<parameter name="e" type="E">
</parameter>
</method>
+<method name="iterator"
+ return="java.util.Iterator<E>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="lower"
return="E"
abstract="true"
@@ -344022,13 +344250,28 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="start" type="E">
+<parameter name="fromElement" type="E">
</parameter>
-<parameter name="startInclusive" type="boolean">
+<parameter name="fromInclusive" type="boolean">
</parameter>
-<parameter name="end" type="E">
+<parameter name="toElement" type="E">
</parameter>
-<parameter name="endInclusive" type="boolean">
+<parameter name="toInclusive" type="boolean">
+</parameter>
+</method>
+<method name="subSet"
+ return="java.util.SortedSet<E>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromElement" type="E">
+</parameter>
+<parameter name="toElement" type="E">
</parameter>
</method>
<method name="tailSet"
@@ -344041,9 +344284,22 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="start" type="E">
+<parameter name="fromElement" type="E">
</parameter>
-<parameter name="startInclusive" type="boolean">
+<parameter name="inclusive" type="boolean">
+</parameter>
+</method>
+<method name="tailSet"
+ return="java.util.SortedSet<E>"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromElement" type="E">
</parameter>
</method>
</interface>
@@ -344705,6 +344961,19 @@
>
<implements name="java.util.Collection">
</implements>
+<method name="add"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
<method name="element"
return="E"
abstract="true"
@@ -344726,7 +344995,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="peek"
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index b96391a..6e589e4 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -21,6 +21,7 @@
import android.content.res.XmlResourceParser;
import android.content.res.Resources.NotFoundException;
import android.util.AttributeSet;
+import android.util.TypedValue;
import android.util.Xml;
import android.view.animation.AnimationUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -195,72 +196,95 @@
anim = new ValueAnimator();
}
TypeEvaluator evaluator = null;
- boolean hasFrom = a.hasValue(com.android.internal.R.styleable.Animator_valueFrom);
- boolean hasTo = a.hasValue(com.android.internal.R.styleable.Animator_valueTo);
- switch (valueType) {
+ int valueFromIndex = com.android.internal.R.styleable.Animator_valueFrom;
+ int valueToIndex = com.android.internal.R.styleable.Animator_valueTo;
- case VALUE_TYPE_FLOAT: {
- float valueFrom;
- float valueTo;
- if (hasFrom) {
- valueFrom = a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f);
- if (hasTo) {
- valueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f);
- anim.setFloatValues(valueFrom, valueTo);
- } else {
- anim.setFloatValues(valueFrom);
- }
+ boolean getFloats = (valueType == VALUE_TYPE_FLOAT);
+
+ TypedValue tvFrom = a.peekValue(valueFromIndex);
+ boolean hasFrom = (tvFrom != null);
+ int fromType = hasFrom ? tvFrom.type : 0;
+ TypedValue tvTo = a.peekValue(valueToIndex);
+ boolean hasTo = (tvTo != null);
+ int toType = hasTo ? tvTo.type : 0;
+
+ if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+ (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) ||
+ (hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+ (toType <= TypedValue.TYPE_LAST_COLOR_INT))) {
+ // special case for colors: ignore valueType and get ints
+ getFloats = false;
+ anim.setEvaluator(new RGBEvaluator());
+ }
+
+ if (getFloats) {
+ float valueFrom;
+ float valueTo;
+ if (hasFrom) {
+ if (fromType == TypedValue.TYPE_DIMENSION) {
+ valueFrom = a.getDimension(valueFromIndex, 0f);
} else {
- valueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f);
- anim.setFloatValues(valueTo);
+ valueFrom = a.getFloat(valueFromIndex, 0f);
}
- }
- break;
-
- case VALUE_TYPE_COLOR:
- evaluator = new RGBEvaluator();
- anim.setEvaluator(evaluator);
- // fall through to pick up values
- case VALUE_TYPE_INT: {
- int valueFrom;
- int valueTo;
- if (hasFrom) {
- valueFrom = a.getInteger(com.android.internal.R.styleable.Animator_valueFrom, 0);
- if (hasTo) {
- valueTo = a.getInteger(com.android.internal.R.styleable.Animator_valueTo, 0);
- anim.setIntValues(valueFrom, valueTo);
+ if (hasTo) {
+ if (toType == TypedValue.TYPE_DIMENSION) {
+ valueTo = a.getDimension(valueToIndex, 0f);
} else {
- anim.setIntValues(valueFrom);
+ valueTo = a.getFloat(valueToIndex, 0f);
}
+ anim.setFloatValues(valueFrom, valueTo);
} else {
- valueTo = a.getInteger(com.android.internal.R.styleable.Animator_valueTo, 0);
+ anim.setFloatValues(valueFrom);
+ }
+ } else {
+ if (toType == TypedValue.TYPE_DIMENSION) {
+ valueTo = a.getDimension(valueToIndex, 0f);
+ } else {
+ valueTo = a.getFloat(valueToIndex, 0f);
+ }
+ anim.setFloatValues(valueTo);
+ }
+ } else {
+ int valueFrom;
+ int valueTo;
+ if (hasFrom) {
+ if (fromType == TypedValue.TYPE_DIMENSION) {
+ valueFrom = (int) a.getDimension(valueFromIndex, 0f);
+ } else if ((fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+ (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+ valueFrom = a.getColor(valueFromIndex, 0);
+ } else {
+ valueFrom = a.getInt(valueFromIndex, 0);
+ }
+ if (hasTo) {
+ if (toType == TypedValue.TYPE_DIMENSION) {
+ valueTo = (int) a.getDimension(valueToIndex, 0f);
+ } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+ (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+ valueTo = a.getColor(valueToIndex, 0);
+ } else {
+ valueTo = a.getInt(valueToIndex, 0);
+ }
+ anim.setIntValues(valueFrom, valueTo);
+ } else {
+ anim.setIntValues(valueFrom);
+ }
+ } else {
+ if (hasTo) {
+ if (toType == TypedValue.TYPE_DIMENSION) {
+ valueTo = (int) a.getDimension(valueToIndex, 0f);
+ } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+ (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+ valueTo = a.getColor(valueToIndex, 0);
+ } else {
+ valueTo = a.getInt(valueToIndex, 0);
+ }
anim.setIntValues(valueTo);
}
}
- break;
-
- case VALUE_TYPE_CUSTOM: {
- // TODO: How to get an 'Object' value?
- float valueFrom;
- float valueTo;
- if (hasFrom) {
- valueFrom = a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f);
- if (hasTo) {
- valueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f);
- anim.setFloatValues(valueFrom, valueTo);
- } else {
- anim.setFloatValues(valueFrom);
- }
- } else {
- valueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f);
- anim.setFloatValues(valueTo);
- }
- }
- break;
}
-
anim.setDuration(duration);
anim.setStartDelay(startDelay);
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index f5420d1..154e084 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -17,7 +17,9 @@
package android.animation;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
/**
* This class plays a set of {@link Animator} objects in the specified order. Animations
@@ -117,10 +119,29 @@
}
/**
+ * Sets up this AnimatorSet to play all of the supplied animations at the same time.
+ *
+ * @param items The animations that will be started simultaneously.
+ */
+ public void playTogether(Collection<Animator> items) {
+ if (items != null && items.size() > 0) {
+ mNeedsSort = true;
+ Builder builder = null;
+ for (Animator anim : items) {
+ if (builder == null) {
+ builder = play(anim);
+ } else {
+ builder.with(anim);
+ }
+ }
+ }
+ }
+
+ /**
* Sets up this AnimatorSet to play each of the supplied animations when the
* previous animation ends.
*
- * @param items The aniamtions that will be started one after another.
+ * @param items The animations that will be started one after another.
*/
public void playSequentially(Animator... items) {
if (items != null) {
@@ -136,6 +157,25 @@
}
/**
+ * Sets up this AnimatorSet to play each of the supplied animations when the
+ * previous animation ends.
+ *
+ * @param items The animations that will be started one after another.
+ */
+ public void playSequentially(List<Animator> items) {
+ if (items != null && items.size() > 0) {
+ mNeedsSort = true;
+ if (items.size() == 1) {
+ play(items.get(0));
+ } else {
+ for (int i = 0; i < items.size() - 1; ++i) {
+ play(items.get(i)).before(items.get(i+1));
+ }
+ }
+ }
+ }
+
+ /**
* Returns the current list of child Animator objects controlled by this
* AnimatorSet. This is a copy of the internal list; modifications to the returned list
* will not affect the AnimatorSet, although changes to the underlying Animator objects
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 32ff3b3..8c55bf3 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -220,25 +220,47 @@
* </p>
*
* <h4>{@link android.hardware.Sensor#TYPE_GRAVITY Sensor.TYPE_GRAVITY}:</h4>
- * A three dimensional vector indicating the direction and magnitude of gravity. Units
- * are m/s^2. The coordinate system is the same as is used by the acceleration sensor.
+ * <p>A three dimensional vector indicating the direction and magnitude of gravity. Units
+ * are m/s^2. The coordinate system is the same as is used by the acceleration sensor.</p>
+ * <p><b>Note:</b> When the device is at rest, the output of the gravity sensor should be identical
+ * to that of the accelerometer.</p>
*
* <h4>{@link android.hardware.Sensor#TYPE_LINEAR_ACCELERATION Sensor.TYPE_LINEAR_ACCELERATION}:</h4>
* A three dimensional vector indicating acceleration along each device axis, not including
* gravity. All values have units of m/s^2. The coordinate system is the same as is used by the
- * acceleration sensor.
+ * acceleration sensor.
+ * <p>The output of the accelerometer, gravity and linear-acceleration sensors must obey the
+ * following relation:</p>
+ * <p><ul>acceleration = gravity + linear-acceleration</ul></p>
*
* <h4>{@link android.hardware.Sensor#TYPE_ROTATION_VECTOR Sensor.TYPE_ROTATION_VECTOR}:</h4>
- * The rotation vector represents the orientation of the device as a combination of an angle
- * and an axis, in which the device has rotated through an angle theta around an axis
- * <x, y, z>. The three elements of the rotation vector are
- * <x*sin(theta/2), y*sin(theta/2), z*sin(theta/2)>, such that the magnitude of the rotation
- * vector is equal to sin(theta/2), and the direction of the rotation vector is equal to the
- * direction of the axis of rotation. The three elements of the rotation vector are equal to
- * the last three components of a unit quaternion
- * <cos(theta/2), x*sin(theta/2), y*sin(theta/2), z*sin(theta/2)>. Elements of the rotation
- * vector are unitless. The x,y, and z axis are defined in the same way as the acceleration
- * sensor.
+ * <p>The rotation vector represents the orientation of the device as a combination of an <i>angle</i>
+ * and an <i>axis</i>, in which the device has rotated through an angle θ around an axis
+ * <x, y, z>.</p>
+ * <p>The three elements of the rotation vector are
+ * <x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)>, such that the magnitude of the rotation
+ * vector is equal to sin(θ/2), and the direction of the rotation vector is equal to the
+ * direction of the axis of rotation.</p>
+ * </p>The three elements of the rotation vector are equal to
+ * the last three components of a <b>unit</b> quaternion
+ * <cos(θ/2), x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)>.</p>
+ * <p>Elements of the rotation vector are unitless.
+ * The x,y, and z axis are defined in the same way as the acceleration
+ * sensor.</p>
+ * <ul>
+ * <p>
+ * values[0]: x*sin(θ/2)
+ * </p>
+ * <p>
+ * values[1]: y*sin(θ/2)
+ * </p>
+ * <p>
+ * values[2]: z*sin(θ/2)
+ * </p>
+ * <p>
+ * values[3]: cos(θ/2) <i>(optional: only if value.length = 4)</i>
+ * </p>
+ * </ul>
*
* <h4>{@link android.hardware.Sensor#TYPE_ORIENTATION
* Sensor.TYPE_ORIENTATION}:</h4> All values are angles in degrees.
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index c178aee..1b799ae 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -1938,13 +1938,18 @@
* @param R an array of floats in which to store the rotation matrix
*/
public static void getRotationMatrixFromVector(float[] R, float[] rotationVector) {
- float q0 = (float)Math.sqrt(1 - rotationVector[0]*rotationVector[0] -
- rotationVector[1]*rotationVector[1] -
- rotationVector[2]*rotationVector[2]);
+
+ float q0;
float q1 = rotationVector[0];
float q2 = rotationVector[1];
float q3 = rotationVector[2];
+ if (rotationVector.length == 4) {
+ q0 = rotationVector[3];
+ } else {
+ q0 = (float)Math.sqrt(1 - q1*q1 - q2*q2 - q3*q3);
+ }
+
float sq_q1 = 2 * q1 * q1;
float sq_q2 = 2 * q2 * q2;
float sq_q3 = 2 * q3 * q3;
@@ -1995,10 +2000,12 @@
* @param Q an array of floats in which to store the computed quaternion
*/
public static void getQuaternionFromVector(float[] Q, float[] rv) {
- float w = (float)Math.sqrt(1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2]);
- //In this case, the w component of the quaternion is known to be a positive number
-
- Q[0] = w;
+ if (rv.length == 4) {
+ Q[0] = rv[3];
+ } else {
+ //In this case, the w component of the quaternion is known to be a positive number
+ Q[0] = (float)Math.sqrt(1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2]);
+ }
Q[1] = rv[0];
Q[2] = rv[1];
Q[3] = rv[2];
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 1c295a7..9c3bc9d 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -40,6 +40,7 @@
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
import org.apache.harmony.dalvik.ddmc.DdmServer;
+import dalvik.bytecode.OpcodeInfo;
import dalvik.bytecode.Opcodes;
import dalvik.system.VMDebug;
@@ -786,7 +787,7 @@
* @hide
*/
public static long countInstancesOfClass(Class cls) {
- return VMDebug.countInstancesOfClass(cls);
+ return VMDebug.countInstancesOfClass(cls, true);
}
/**
@@ -865,7 +866,7 @@
* </pre>
*/
public static class InstructionCount {
- private static final int NUM_INSTR = 256;
+ private static final int NUM_INSTR = OpcodeInfo.MAXIMUM_VALUE + 1;
private int[] mCounts;
@@ -909,8 +910,11 @@
*/
public int globalTotal() {
int count = 0;
- for (int i = 0; i < NUM_INSTR; i++)
+
+ for (int i = 0; i < NUM_INSTR; i++) {
count += mCounts[i];
+ }
+
return count;
}
@@ -921,27 +925,16 @@
public int globalMethodInvocations() {
int count = 0;
- //count += mCounts[Opcodes.OP_EXECUTE_INLINE];
- count += mCounts[Opcodes.OP_INVOKE_VIRTUAL];
- count += mCounts[Opcodes.OP_INVOKE_SUPER];
- count += mCounts[Opcodes.OP_INVOKE_DIRECT];
- count += mCounts[Opcodes.OP_INVOKE_STATIC];
- count += mCounts[Opcodes.OP_INVOKE_INTERFACE];
- count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_RANGE];
- count += mCounts[Opcodes.OP_INVOKE_SUPER_RANGE];
- count += mCounts[Opcodes.OP_INVOKE_DIRECT_RANGE];
- count += mCounts[Opcodes.OP_INVOKE_STATIC_RANGE];
- count += mCounts[Opcodes.OP_INVOKE_INTERFACE_RANGE];
- //count += mCounts[Opcodes.OP_INVOKE_DIRECT_EMPTY];
- count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK];
- count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK_RANGE];
- count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK];
- count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK_RANGE];
+ for (int i = 0; i < NUM_INSTR; i++) {
+ if (OpcodeInfo.isInvoke(i)) {
+ count += mCounts[i];
+ }
+ }
+
return count;
}
}
-
/**
* A Map of typed debug properties.
*/
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 754d073..6414936 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -847,6 +847,13 @@
}
};
+ // Note: only access this once verifying the thread has a Looper.
+ private static final ThreadLocal<Handler> threadHandler = new ThreadLocal<Handler>() {
+ @Override protected Handler initialValue() {
+ return new Handler();
+ }
+ };
+
private static boolean tooManyViolationsThisLoop() {
return violationsBeingTimed.get().size() >= MAX_OFFENSES_PER_LOOP;
}
@@ -954,7 +961,6 @@
return;
}
- MessageQueue queue = Looper.myQueue();
final ArrayList<ViolationInfo> records = violationsBeingTimed.get();
if (records.size() >= MAX_OFFENSES_PER_LOOP) {
// Not worth measuring. Too many offenses in one loop.
@@ -977,9 +983,30 @@
}
}
- queue.addIdleHandler(new MessageQueue.IdleHandler() {
- public boolean queueIdle() {
+ // We post a runnable to a Handler (== delay 0 ms) for
+ // measuring the end time of a violation instead of using
+ // an IdleHandler (as was previously used) because an
+ // IdleHandler may not run for quite a long period of time
+ // if an ongoing animation is happening and continually
+ // posting ASAP (0 ms) animation steps. Animations are
+ // throttled back to 60fps via SurfaceFlinger/View
+ // invalidates, _not_ by posting frame updates every 16
+ // milliseconds.
+ threadHandler.get().post(new Runnable() {
+ public void run() {
long loopFinishTime = SystemClock.uptimeMillis();
+
+ // Note: we do this early, before handling the
+ // violation below, as handling the violation
+ // may include PENALTY_DEATH and we don't want
+ // to keep the red border on.
+ if (windowManager != null) {
+ try {
+ windowManager.showStrictModeViolation(false);
+ } catch (RemoteException unused) {
+ }
+ }
+
for (int n = 0; n < records.size(); ++n) {
ViolationInfo v = records.get(n);
v.violationNumThisLoop = n + 1;
@@ -988,13 +1015,6 @@
handleViolation(v);
}
records.clear();
- if (windowManager != null) {
- try {
- windowManager.showStrictModeViolation(false);
- } catch (RemoteException unused) {
- }
- }
- return false; // remove this idle handler from the array
}
});
}
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 0d012d6..d724320 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -190,7 +190,9 @@
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int initialScrollX = -1, initialScrollY = -1;
- if (event.getAction() == MotionEvent.ACTION_UP) {
+ final int action = event.getAction();
+
+ if (action == MotionEvent.ACTION_UP) {
initialScrollX = Touch.getInitialScrollX(widget, buffer);
initialScrollY = Touch.getInitialScrollY(widget, buffer);
}
@@ -198,7 +200,7 @@
boolean handled = Touch.onTouchEvent(widget, buffer, event);
if (widget.isFocused() && !widget.didTouchFocusSelect()) {
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (action == MotionEvent.ACTION_DOWN) {
boolean cap = isCap(buffer);
if (cap) {
int offset = widget.getOffset((int) event.getX(), (int) event.getY());
@@ -211,7 +213,7 @@
// mode once the view detected it needed to scroll.
widget.getParent().requestDisallowInterceptTouchEvent(true);
}
- } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ } else if (action == MotionEvent.ACTION_MOVE) {
boolean cap = isCap(buffer);
if (cap && handled) {
@@ -231,7 +233,7 @@
Selection.extendSelection(buffer, offset);
return true;
}
- } else if (event.getAction() == MotionEvent.ACTION_UP) {
+ } else if (action == MotionEvent.ACTION_UP) {
// If we have scrolled, then the up shouldn't move the cursor,
// but we do need to make sure the cursor is still visible at
// the current scroll offset to avoid the scroll jumping later
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 6f4abef..24a9f87 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -94,13 +94,18 @@
*/
abstract void setup(int width, int height);
+ interface HardwareDrawCallbacks {
+ void onHardwarePreDraw(Canvas canvas);
+ void onHardwarePostDraw(Canvas canvas);
+ }
+
/**
* Draws the specified view.
*
* @param view The view to draw.
* @param attachInfo AttachInfo tied to the specified view.
*/
- abstract void draw(View view, View.AttachInfo attachInfo, int yOffset);
+ abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks);
/**
* Creates a new display list that can be used to record batches of
@@ -456,7 +461,7 @@
}
@Override
- void draw(View view, View.AttachInfo attachInfo, int yOffset) {
+ void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
if (canDraw()) {
attachInfo.mDrawingTime = SystemClock.uptimeMillis();
attachInfo.mIgnoreDirtyState = true;
@@ -473,11 +478,12 @@
Canvas canvas = mCanvas;
int saveCount = canvas.save();
- canvas.translate(0, -yOffset);
+ callbacks.onHardwarePreDraw(canvas);
try {
view.draw(canvas);
} finally {
+ callbacks.onHardwarePostDraw(canvas);
canvas.restoreToCount(saveCount);
}
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index cb7d0e2..77083a9 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -25,7 +25,9 @@
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PointF;
@@ -57,6 +59,8 @@
import android.view.View.MeasureSpec;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.Interpolator;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.Scroller;
@@ -79,7 +83,8 @@
* {@hide}
*/
@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
-public final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Callbacks {
+public final class ViewRoot extends Handler implements ViewParent,
+ View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
private static final String TAG = "ViewRoot";
private static final boolean DBG = false;
private static final boolean SHOW_FPS = false;
@@ -213,6 +218,10 @@
int mScrollY;
int mCurScrollY;
Scroller mScroller;
+ Bitmap mResizeBitmap;
+ long mResizeBitmapStartTime;
+ int mResizeBitmapDuration;
+ static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
final ViewConfiguration mViewConfiguration;
@@ -626,6 +635,13 @@
return mAppVisible ? mView.getVisibility() : View.GONE;
}
+ void disposeResizeBitmap() {
+ if (mResizeBitmap != null) {
+ mResizeBitmap.recycle();
+ mResizeBitmap = null;
+ }
+ }
+
private void performTraversals() {
// cache mView since it is used so much below...
final View host = mView;
@@ -734,6 +750,48 @@
ensureTouchModeLocally(mAddedTouchMode);
} else {
if (!mAttachInfo.mContentInsets.equals(mPendingContentInsets)) {
+ if (mWidth > 0 && mHeight > 0 &&
+ mSurface != null && mSurface.isValid() &&
+ mAttachInfo.mHardwareRenderer != null &&
+ mAttachInfo.mHardwareRenderer.isEnabled() &&
+ lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
+
+ disposeResizeBitmap();
+
+ boolean completed = false;
+ try {
+ mResizeBitmap = Bitmap.createBitmap(mWidth, mHeight,
+ Bitmap.Config.ARGB_8888);
+ mResizeBitmap.setHasAlpha(false);
+ Canvas canvas = new Canvas(mResizeBitmap);
+ int yoff;
+ final boolean scrolling = mScroller != null
+ && mScroller.computeScrollOffset();
+ if (scrolling) {
+ yoff = mScroller.getCurrY();
+ mScroller.abortAnimation();
+ } else {
+ yoff = mScrollY;
+ }
+ canvas.translate(0, -yoff);
+ if (mTranslator != null) {
+ mTranslator.translateCanvas(canvas);
+ }
+ canvas.setScreenDensity(mAttachInfo.mScalingRequired
+ ? DisplayMetrics.DENSITY_DEVICE : 0);
+ mView.draw(canvas);
+ mResizeBitmapStartTime = SystemClock.uptimeMillis();
+ mResizeBitmapDuration = mView.getResources().getInteger(
+ com.android.internal.R.integer.config_mediumAnimTime);
+ completed = true;
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "Not enough memory for content change anim buffer", e);
+ } finally {
+ if (!completed) {
+ mResizeBitmap = null;
+ }
+ }
+ }
mAttachInfo.mContentInsets.set(mPendingContentInsets);
host.fitSystemWindows(mAttachInfo.mContentInsets);
insetsChanged = true;
@@ -787,7 +845,6 @@
// Maybe we can just try the next size up, and see if that reduces
// the height?
if (host.getWidth() <= baseSize /*&& host.getHeight() <= maxHeight*/) {
- Log.v(TAG, "Good!");
goodMeasure = true;
} else {
// Didn't fit in that size... try expanding a bit.
@@ -972,6 +1029,7 @@
if (mScroller != null) {
mScroller.abortAnimation();
}
+ disposeResizeBitmap();
}
} catch (RemoteException e) {
}
@@ -1310,6 +1368,22 @@
return measureSpec;
}
+ int mHardwareYOffset;
+ int mResizeAlpha;
+ final Paint mResizePaint = new Paint();
+
+ public void onHardwarePreDraw(Canvas canvas) {
+ canvas.translate(0, -mHardwareYOffset);
+ }
+
+ public void onHardwarePostDraw(Canvas canvas) {
+ if (mResizeBitmap != null) {
+ canvas.translate(0, mHardwareYOffset);
+ mResizePaint.setAlpha(mResizeAlpha);
+ canvas.drawBitmap(mResizeBitmap, 0, 0, mResizePaint);
+ }
+ }
+
private void draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;
if (surface == null || !surface.isValid()) {
@@ -1334,8 +1408,8 @@
}
int yoff;
- final boolean scrolling = mScroller != null && mScroller.computeScrollOffset();
- if (scrolling) {
+ boolean animating = mScroller != null && mScroller.computeScrollOffset();
+ if (animating) {
yoff = mScroller.getCurrY();
} else {
yoff = mScrollY;
@@ -1347,10 +1421,29 @@
float appScale = mAttachInfo.mApplicationScale;
boolean scalingRequired = mAttachInfo.mScalingRequired;
+ int resizeAlpha = 0;
+ if (mResizeBitmap != null) {
+ long deltaTime = SystemClock.uptimeMillis() - mResizeBitmapStartTime;
+ if (deltaTime < mResizeBitmapDuration) {
+ float amt = deltaTime/(float)mResizeBitmapDuration;
+ amt = mResizeInterpolator.getInterpolation(amt);
+ animating = true;
+ resizeAlpha = 255 - (int)(amt*255);
+ } else {
+ disposeResizeBitmap();
+ }
+ }
+
Rect dirty = mDirty;
if (mSurfaceHolder != null) {
// The app owns the surface, we won't draw.
dirty.setEmpty();
+ if (animating) {
+ if (mScroller != null) {
+ mScroller.abortAnimation();
+ }
+ disposeResizeBitmap();
+ }
return;
}
@@ -1363,10 +1456,12 @@
if (!dirty.isEmpty() || mIsAnimating) {
mIsAnimating = false;
dirty.setEmpty();
- mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, yoff);
+ mHardwareYOffset = yoff;
+ mResizeAlpha = resizeAlpha;
+ mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
}
- if (scrolling) {
+ if (animating) {
mFullRedrawNeeded = true;
scheduleTraversals();
}
@@ -1486,7 +1581,7 @@
Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
}
- if (scrolling) {
+ if (animating) {
mFullRedrawNeeded = true;
scheduleTraversals();
}
@@ -1600,7 +1695,7 @@
if (scrollY != mScrollY) {
if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
+ mScrollY + " , new=" + scrollY);
- if (!immediate) {
+ if (!immediate && mResizeBitmap == null) {
if (mScroller == null) {
mScroller = new Scroller(mView.getContext());
}
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 0e9d9b7..1647540 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -621,6 +621,20 @@
}
/**
+ * Tell the cookie store that this is a good time to flush cookies to flash.
+ *
+ * This should be called when the app is paused. Note that this method only
+ * acts as a hint, and may not have any effect. Flushing is asynchronous.
+ *
+ * @hide pending API council approval.
+ */
+ public void flushCookieStore() {
+ if (useChromiumHttpStack()) {
+ nativeFlushCookieStore();
+ }
+ }
+
+ /**
* Package level api, called from CookieSyncManager
*
* Get a list of cookies which are updated since a given time.
@@ -1078,4 +1092,5 @@
private static native void nativeRemoveSessionCookie();
private static native void nativeSetAcceptCookie(boolean accept);
private static native void nativeSetCookie(String url, String value);
+ private static native void nativeFlushCookieStore();
}
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 6769563..85bff4f 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -138,6 +138,10 @@
mCurrentProxy.dispatchOnEnded();
else
mCurrentProxy.dispatchOnPaused();
+
+ // Re enable plugin views.
+ mCurrentProxy.getWebView().getViewManager().showAll();
+
isVideoSelfEnded = false;
mCurrentProxy = null;
mLayout.removeView(mVideoView);
@@ -199,6 +203,9 @@
mTimer = new Timer();
mVideoView.start();
client.onShowCustomView(mLayout, mCallback);
+ // Plugins like Flash will draw over the video so hide
+ // them while we're playing.
+ mCurrentProxy.getWebView().getViewManager().hideAll();
}
public static boolean isPlaying(HTML5VideoViewProxy proxy) {
@@ -599,6 +606,10 @@
return new HTML5VideoViewProxy(webViewCore.getWebView(), nativePtr);
}
+ /* package */ WebView getWebView() {
+ return mWebView;
+ }
+
private native void nativeOnPrepared(int duration, int width, int height, int nativePointer);
private native void nativeOnEnded(int nativePointer);
private native void nativeOnPaused(int nativePointer);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6e27b7a..b8ccf45 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2183,14 +2183,13 @@
// look at the cursor node, and not the focus node. Also, what is
// getFocusNodePath?
public void requestFocusNodeHref(Message hrefMsg) {
- if (hrefMsg == null || mNativeClass == 0) {
+ if (hrefMsg == null) {
return;
}
- if (nativeCursorIsAnchor()) {
- mWebViewCore.sendMessage(EventHub.REQUEST_CURSOR_HREF,
- nativeCursorFramePointer(), nativeCursorNodePointer(),
- hrefMsg);
- }
+ int contentX = viewToContentX((int) mLastTouchX + mScrollX);
+ int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+ mWebViewCore.sendMessage(EventHub.REQUEST_CURSOR_HREF,
+ contentX, contentY, hrefMsg);
}
/**
@@ -3739,6 +3738,8 @@
if (mNativeClass != 0 && nativeWordSelection(x, y)) {
nativeSetExtendSelection();
mDrawSelectionPointer = false;
+ mSelectionStarted = true;
+ mTouchMode = TOUCH_DRAG_MODE;
return true;
}
selectionDone();
@@ -4989,10 +4990,10 @@
startTouch(detector.getFocusX(), detector.getFocusY(), mLastTouchTime);
}
- private void startScrollingLayer(float gestureX, float gestureY) {
+ private void startScrollingLayer(float x, float y) {
if (mTouchMode != TOUCH_DRAG_LAYER_MODE) {
- int contentX = viewToContentX((int) gestureX + mScrollX);
- int contentY = viewToContentY((int) gestureY + mScrollY);
+ int contentX = viewToContentX((int) x + mScrollX);
+ int contentY = viewToContentY((int) y + mScrollY);
mScrollingLayer = nativeScrollableLayer(contentX, contentY);
if (mScrollingLayer != 0) {
mTouchMode = TOUCH_DRAG_LAYER_MODE;
@@ -5025,52 +5026,12 @@
float y = ev.getY();
long eventTime = ev.getEventTime();
- final ScaleGestureDetector detector =
- mZoomManager.getMultiTouchGestureDetector();
- boolean isScrollGesture = false;
- // Set to the mid-point of a two-finger gesture used to detect if the
- // user has touched a layer.
- float gestureX = x;
- float gestureY = y;
- if (detector == null || !detector.isInProgress()) {
- // The gesture for scrolling a layer is two fingers close together.
- // FIXME: we may consider giving WebKit an option to handle
- // multi-touch events later.
- if (ev.getPointerCount() > 1) {
- float dx = ev.getX(1) - ev.getX(0);
- float dy = ev.getY(1) - ev.getY(0);
- float dist = (dx * dx + dy * dy) *
- DRAG_LAYER_INVERSE_DENSITY_SQUARED;
- // Use the approximate center to determine if the gesture is in
- // a layer.
- gestureX = ev.getX(0) + (dx * .5f);
- gestureY = ev.getY(0) + (dy * .5f);
- // Now use a consistent point for tracking movement.
- if (ev.getX(0) < ev.getX(1)) {
- x = ev.getX(0);
- y = ev.getY(0);
- } else {
- x = ev.getX(1);
- y = ev.getY(1);
- }
- action = ev.getActionMasked();
- if (dist < DRAG_LAYER_FINGER_DISTANCE) {
- isScrollGesture = true;
- } else if (mTouchMode == TOUCH_DRAG_LAYER_MODE) {
- // Fingers moved too far apart while dragging, the user
- // might be trying to zoom.
- mTouchMode = TOUCH_INIT_MODE;
- }
- }
- }
-
- // If the page disallows zoom, pass multi-touch events to webkit.
// mDeferMultitouch is a hack for layout tests, where it is used to
// force passing multi-touch events to webkit.
// FIXME: always pass multi-touch events to webkit and remove everything
// related to mDeferMultitouch.
if (ev.getPointerCount() > 1 &&
- (mDeferMultitouch || (!isScrollGesture && mZoomManager.isZoomScaleFixed()))) {
+ (mDeferMultitouch || mZoomManager.isZoomScaleFixed())) {
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "passing " + ev.getPointerCount() + " points to webkit");
}
@@ -5078,8 +5039,11 @@
return true;
}
+ final ScaleGestureDetector detector =
+ mZoomManager.getMultiTouchGestureDetector();
+
if (mZoomManager.supportsMultiTouchZoom() && ev.getPointerCount() > 1 &&
- mTouchMode != TOUCH_DRAG_LAYER_MODE && !isScrollGesture) {
+ mTouchMode != TOUCH_DRAG_LAYER_MODE) {
if (!detector.isInProgress() &&
ev.getActionMasked() != MotionEvent.ACTION_POINTER_DOWN) {
// Insert a fake pointer down event in order to start
@@ -5369,9 +5333,7 @@
deltaX = 0;
deltaY = 0;
- if (isScrollGesture) {
- startScrollingLayer(gestureX, gestureY);
- }
+ startScrollingLayer(x, y);
startDrag();
}
@@ -5667,8 +5629,10 @@
deltaY = viewToContentDimension(deltaY);
if (nativeScrollLayer(mScrollingLayer, deltaX, deltaY)) {
invalidate();
+ return;
}
- return;
+ // Switch to drag mode and fall through.
+ mTouchMode = TOUCH_DRAG_MODE;
}
final int oldX = mScrollX;
@@ -7706,6 +7670,10 @@
mWebViewCore.sendMessage(EventHub.AUTOFILL_FORM, autoFillQueryId, /* unused */0);
}
+ /* package */ ViewManager getViewManager() {
+ return mViewManager;
+ }
+
private native int nativeCacheHitFramePointer();
private native Rect nativeCacheHitNodeBounds();
private native int nativeCacheHitNodePointer();
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index b7d20b4..99a0386 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -553,8 +553,8 @@
private native void nativeMoveMouseIfLatest(int moveGeneration,
int framePtr, int x, int y);
- private native String nativeRetrieveHref(int framePtr, int nodePtr);
- private native String nativeRetrieveAnchorText(int framePtr, int nodePtr);
+ private native String nativeRetrieveHref(int x, int y);
+ private native String nativeRetrieveAnchorText(int x, int y);
private native void nativeTouchUp(int touchGeneration,
int framePtr, int nodePtr, int x, int y);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 57af643..cfdcd32 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -220,8 +220,8 @@
private boolean mTemporaryDetach;
private boolean mDispatchTemporaryDetach;
- private boolean mEatTouchRelease = false;
- private boolean mScrolled = false;
+ private boolean mDiscardNextActionUp = false;
+ private boolean mIgnoreActionUpEvent = false;
private Editable.Factory mEditableFactory = Editable.Factory.getInstance();
private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance();
@@ -7002,26 +7002,6 @@
}
}
- private void onTapUpEvent(int prevStart, int prevEnd) {
- final int start = getSelectionStart();
- final int end = getSelectionEnd();
-
- if (start == end) {
- if (start >= prevStart && start < prevEnd) {
- // Restore previous selection
- Selection.setSelection((Spannable)mText, prevStart, prevEnd);
- return;
- } else {
- // Tapping outside stops selection mode, if any
- stopSelectionActionMode();
-
- if (hasInsertionController()) {
- getInsertionController().show();
- }
- }
- }
- }
-
class CommitSelectionReceiver extends ResultReceiver {
private final int mPrevStart, mPrevEnd;
@@ -7066,7 +7046,7 @@
// Reset this state; it will be re-set if super.onTouchEvent
// causes focus to move to the view.
mTouchFocusSelected = false;
- mScrolled = false;
+ mIgnoreActionUpEvent = false;
}
final boolean superResult = super.onTouchEvent(event);
@@ -7076,8 +7056,8 @@
* move the selection away from whatever the menu action was
* trying to affect.
*/
- if (mEatTouchRelease && action == MotionEvent.ACTION_UP) {
- mEatTouchRelease = false;
+ if (mDiscardNextActionUp && action == MotionEvent.ACTION_UP) {
+ mDiscardNextActionUp = false;
return superResult;
}
@@ -7106,7 +7086,7 @@
mSelectionModifierCursorController.updatePosition();
}
}
- if (action == MotionEvent.ACTION_UP && !mScrolled && isFocused()) {
+ if (action == MotionEvent.ACTION_UP && !mIgnoreActionUpEvent && isFocused()) {
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -7117,13 +7097,14 @@
}
if (!mTextIsSelectable) {
- // Selection in read-only text should not bring up the IME.
+ // Show the IME, except when selecting in read-only text.
handled |= imm.showSoftInput(this, 0, csr) && (csr != null);
}
- // Cannot be done by CommitSelectionReceiver, which might not always be called,
- // for instance when dealing with an ExtractEditText.
- onTapUpEvent(oldSelStart, oldSelEnd);
+ stopSelectionActionMode();
+ if (hasInsertionController()) {
+ getInsertionController().show();
+ }
}
}
@@ -7181,7 +7162,7 @@
@Override
public void cancelLongPress() {
super.cancelLongPress();
- mScrolled = true;
+ mIgnoreActionUpEvent = true;
}
@Override
@@ -7815,7 +7796,7 @@
@Override
public boolean performLongClick() {
if (super.performLongClick()) {
- mEatTouchRelease = true;
+ mDiscardNextActionUp = true;
return true;
}
@@ -7826,7 +7807,7 @@
stopSelectionActionMode();
Selection.setSelection((Spannable)mText, offset);
getInsertionController().show(0);
- mEatTouchRelease = true;
+ mDiscardNextActionUp = true;
return true;
}
@@ -7845,13 +7826,13 @@
getSelectionController().show();
}
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- mEatTouchRelease = true;
+ mDiscardNextActionUp = true;
return true;
}
if (startSelectionActionMode()) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- mEatTouchRelease = true;
+ mDiscardNextActionUp = true;
return true;
}
@@ -8772,6 +8753,7 @@
final int slopSquared = doubleTapSlop * doubleTapSlop;
if (distanceSquared < slopSquared) {
startSelectionActionMode();
+ mDiscardNextActionUp = true;
}
}
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index cc6dc2a..a911e8d 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3418,21 +3418,18 @@
greater than 0 or infinite. The default value is restart. -->
<attr name="repeatMode"/>
<!-- Value the animation starts from. -->
- <attr name="valueFrom" format="float|integer"/>
+ <attr name="valueFrom" format="float|integer|color|dimension"/>
<!-- Value the animation animates to. -->
- <attr name="valueTo" format="float|integer"/>
+ <attr name="valueTo" format="float|integer|color|dimension"/>
<!-- The type of valueFrom and valueTo. -->
<attr name="valueType">
- <!-- valueFrom and valueTo are floats. -->
+ <!-- valueFrom and valueTo are floats. This is the default value is valueType is
+ unspecified. Note that if either valueFrom or valueTo represent colors
+ (beginning with "#"), then this attribute is ignored and the color values are
+ interpreted as integers. -->
<enum name="floatType" value="0" />
<!-- valueFrom and valueTo are integers. -->
<enum name="intType" value="1" />
- <!-- valueFrom and valueTo are doubles. -->
- <enum name="doubleType" value="2" />
- <!-- valueFrom and valueTo are colors. -->
- <enum name="colorType" value="3" />
- <!-- valueFrom and valueTo are a custom type. -->
- <enum name="customType" value="4" />
</attr>
</declare-styleable>
diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd
index 6c02031..623ee22 100644
--- a/docs/html/guide/topics/data/backup.jd
+++ b/docs/html/guide/topics/data/backup.jd
@@ -7,7 +7,9 @@
<h2>Quickview</h2>
<ul>
- <li>Back up your data to the cloud in case the user looses it</li>
+ <li>Back up the user's data to the cloud in case the user loses it</li>
+ <li>If the user upgrades to a new Android-powered device, your app can restore the user's
+data onto the new device</li>
<li>Easily back up SharedPreferences and private files with BackupAgentHelper</li>
<li>Requires API Level 8</li>
</ul>
@@ -389,7 +391,7 @@
<p>To add an entity to your backup data set, you must:</p>
<ol>
<li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int)
-writeEntityheader()}, passing a unique string key for the data you're about to write and the data
+writeEntityHeader()}, passing a unique string key for the data you're about to write and the data
size.</li>
<li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int)
writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write
@@ -403,8 +405,8 @@
ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
DataOutputStream outWriter = new DataOutputStream(bufStream);
// Write structured data
-outWriter.writeString(playerName);
-outWriter.writeInt(playerScore);
+outWriter.writeUTF(mPlayerName);
+outWriter.writeInt(mPlayerScore);
// Send the data to the Backup Manager via the BackupDataOutput
byte[] buffer = bufStream.toByteArray();
int len = buffer.length;
@@ -422,10 +424,10 @@
onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you
do not write the current data state to this file, then
{@code oldState} will be empty during the next callback.
- <p>Again, the following example saves a representation of the data using the file's
-last-modified timestamp:</p>
+ <p>The following example saves a representation of the current data into {@code newState} using
+the file's last-modified timestamp:</p>
<pre>
-FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
+FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
DataOutputStream out = new DataOutputStream(outstream);
long modified = mDataFile.lastModified();
@@ -493,7 +495,8 @@
<p>In your implementation of {@link
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} to iterate
+onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} on the
+{@code data} to iterate
through all entities in the data set. For each entity found, do the following:</p>
<ol>
@@ -517,6 +520,54 @@
onBackup()}.
</ol>
+<p>For example, here's how you can restore the data backed up by the example in the previous
+section:</p>
+
+<pre>
+@Override
+public void onRestore(BackupDataInput data, int appVersionCode,
+ ParcelFileDescriptor newState) throws IOException {
+ // There should be only one entity, but the safest
+ // way to consume it is using a while loop
+ while (data.readNextHeader()) {
+ String key = data.getKey();
+ int dataSize = data.getDataSize();
+
+ // If the key is ours (for saving top score). Note this key was used when
+ // we wrote the backup entity header
+ if (TOPSCORE_BACKUP_KEY.equals(key)) {
+ // Create an input stream for the BackupDataInput
+ byte[] dataBuf = new byte[dataSize];
+ data.readEntityData(dataBuf, 0, dataSize);
+ ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
+ DataInputStream in = new DataInputStream(baStream);
+
+ // Read the player name and score from the backup data
+ mPlayerName = in.readUTF();
+ mPlayerScore = in.readInt();
+
+ // Record the score on the device (to a file or something)
+ recordScore(mPlayerName, mPlayerScore);
+ } else {
+ // We don't know this entity key. Skip it. (Shouldn't happen.)
+ data.skipEntityData();
+ }
+ }
+
+ // Finally, write to the state blob (newState) that describes the restored data
+ FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
+ DataOutputStream out = new DataOutputStream(outstream);
+ out.writeUTF(mPlayerName);
+ out.writeInt(mPlayerScore);
+}
+</pre>
+
+<p>In this example, the {@code appVersionCode} parameter passed to {@link
+android.app.backup.BackupAgent#onRestore onRestore()} is not used. However, you might want to use
+it if you've chosen to perform backup when the user's version of the application has actually moved
+backward (for example, the user went from version 1.5 of your app to 1.0). For more information, see
+the section about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</p>
+
<div class="special">
<p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a
href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code
@@ -592,7 +643,8 @@
static final String PREFS_BACKUP_KEY = "prefs";
// Allocate a helper and add it to the backup agent
- void onCreate() {
+ @Override
+ public void onCreate() {
SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS);
addHelper(PREFS_BACKUP_KEY, helper);
}
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index 0f36345..2c8e4c2 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -67,73 +67,71 @@
width="9px" /> Android NDK, Revision 5</a> <em>(November 2010)</em>
<div class="toggleme">
- <dl>
- <dt>NDK r5 notes:</dt>
-
- <dd>
- <p>The r5 release of the NDK includes many new APIs, many of which are introduced to
- support native game development and applications that require similar requirements. Most
- notably, native activities are now supported, which allow you to write an application
- entirely with native code. For detailed information describing the changes in this
- release, read the CHANGES.HTML document included in the downloaded NDK package.</p>
- </dd>
- </dl>
-
+ <p>This release of the NDK includes many new APIs, most of which are introduced to
+ support the development of games and similar applications that make extensive use
+ of native code. Using the APIs, developers have direct native access to events, audio,
+ graphics and window management, assets, and storage. Developers can also implement the
+ Android application lifecycle in native code with help from the new
+ {@link android.app.NativeActivity} class. For detailed information describing the changes in this
+ release, read the CHANGES.HTML document included in the downloaded NDK package.
+ </p>
<dl>
<dt>General notes:</dt>
-
<dd>
<ul>
-
- <li>A new toolchain (based on GCC 4.4.3), which generates better code, and can also now
-be used as a standalone cross-compiler, for people who want to build their stuff with
-<code>./configure && make</code>. See
-docs/STANDALONE-TOOLCHAIN.html for the details. The binaries for GCC 4.4.0 are still provided,
-but the 4.2.1 binaries were removed.</li>
-
- <li>Support for prebuilt static and shared libraries (docs/PREBUILTS.html), module
-exports and imports to make sharing and reuse of third-party modules much easier
-(docs/IMPORT-MODULE.html explains why).</li>
-
- <li>A C++ STL implementation (based on STLport) is now provided as a helper module. It
-can be used either as a static or shared library (details and usage exemple under
-sources/android/stlport/README). <strong>Note:</strong> For now, C++ Exceptions and RTTI are still
-not supported.</li>
-
- <li>Improvements to the <code>cpufeatures</code> helper library to deal with buggy
-kernel that incorrectly report they run on an ARMv7 CPU (while the device really is an ARMv6). We
-recommend developers that use it to simply rebuild their applications to benefit from it, then
-upload to Market.</li>
-
- <li>Adds support for native activities, which allows you to write completely native
- applications.</li>
-
- <li>Adds an EGL library that lets you create and manage OpenGL ES textures and
- services.</li>
+ <li>Adds support for native activities, which allows you to implement the
+ Android application lifecycle in native code.</li>
<li>Adds native support for the following:
<ul>
+
<li>Input subsystem (such as the keyboard and touch screen)</li>
+ <li>Access to sensor data (accelerometer, compass, gyroscope, etc).</li>
+
+ <li>Event loop APIs to wait for things such as input and sensor events.</li>
+
<li>Window and surface subsystem</li>
<li>Audio APIs based on the OpenSL ES standard that support playback and recording
as well as control over platform audio effects</li>
- <li>Event loop APIs to wait for things such as input and sensor events</li>
-
- <li>Access to assets packaged in the <code>.apk</code></li>
-
- <li>Access to sensor data (accelerometer, compass, gyroscope, etc.)</li>
+ <li>Access to assets packaged in an <code>.apk</code> file.</li>
+
</ul>
</li>
- <li>New sample applications, <code>native-plasma</code> and
- <code>native-activity</code>, to demonstrate how to write a native activity.</li>
-
- <li>Plus many bugfixes and other small improvements; see docs/CHANGES.html for a more
-detailed list of changes.</li>
+ <li>Includes a new toolchain (based on GCC 4.4.3), which generates better code, and can also now
+ be used as a standalone cross-compiler, for people who want to build their stuff with
+ <code>./configure && make</code>. See
+ docs/STANDALONE-TOOLCHAIN.html for the details. The binaries for GCC 4.4.0 are still provided,
+ but the 4.2.1 binaries were removed.</li>
+
+ <li>Adds support for prebuilt static and shared libraries (docs/PREBUILTS.html) and module
+ exports and imports to make sharing and reuse of third-party modules much easier
+ (docs/IMPORT-MODULE.html explains why).</li>
+
+ <li>Provides a default C++ STL implementation (based on STLport) as a helper module. It can be used either
+ as a static or shared library (details and usage examples are in sources/android/stlport/README). Prebuilt
+ binaries for STLport (static or shared) and GNU libstdc++ (static only) are also provided if you choose to
+ compile against those libraries instead of the default C++ STL implementation.
+ C++ Exceptions and RTTI are not supported in the default STL implementation. For more information, see
+ docs/CPLUSPLUS-SUPPORT.HTML.</li>
+
+ <li>Includes improvements to the <code>cpufeatures</code> helper library that improves reporting
+ of the CPU type (some devices previously reported ARMv7 CPU when the device really was an ARMv6). We
+ recommend developers that use this library to rebuild their applications then
+ upload to Market to benefit from the improvements.</li>
+
+ <li>Adds an EGL library that lets you create and manage OpenGL ES textures and
+ services.</li>
+
+ <li>Adds new sample applications, <code>native-plasma</code> and <code>native-activity</code>,
+ to demonstrate how to write a native activity.</li>
+
+ <li>Includes many bugfixes and other small improvements; see docs/CHANGES.html for a more
+ detailed list of changes.</li>
</ul>
</dd>
</dl>
@@ -296,14 +294,13 @@
<h2 id="installing">Installing the NDK</h2>
<p>Installing the NDK on your development computer is straightforward and involves extracting the
- NDK from its download package. Unlike previous releases, there is no need to run a host-setup
- script.</p>
+ NDK from its download package.</p>
<p>Before you get started make sure that you have downloaded the latest <a href=
"{@docRoot}sdk/index.html">Android SDK</a> and upgraded your applications and environment as
- needed. The NDK will not work with older versions of the Android SDK. Also, take a moment to
- review the <a href="{@docRoot}sdk/ndk/reqs.html">System and Software Requirements</a> for the
- NDK, if you haven't already.</p>
+ needed. The NDK is compatible with older platform versions but not older versions of the SDK tools.
+ Also, take a moment to review the <a href="{@docRoot}sdk/ndk/reqs.html">System and Software Requirements</a>
+ for the NDK, if you haven't already.</p>
<p>To install the NDK, follow these steps:</p>
@@ -318,7 +315,7 @@
<code><ndk></code>.</li>
</ol>
- <p>You are now ready start working with the NDK.</p>
+ <p>You are now ready to start working with the NDK.</p>
<h2 id="gettingstarted">Getting Started with the NDK</h2>
@@ -342,8 +339,7 @@
<li>Build your native code by running the 'ndk-build' script from your project's directory. It
is located in the top-level NDK directory:
- <pre class="no-pretty-print">
-cd <project>
+ <pre class="no-pretty-print">cd <project>
<ndk>/ndk-build
</pre>
@@ -360,220 +356,10 @@
<h2 id="samples">Sample Applications</h2>
- <p>The NDK includes sample applications that illustrate how to use native code in your Android
- applications:</p>
+ <p>The NDK includes sample Android applications that illustrate how to use native code in your
+ Android applications. For more information, see <a href=
+ "{@docRoot}sdk/ndk/overview.html#samples">Sample Applications</a>.</p>
- <ul>
- <li><code>hello-jni</code> — a simple application that loads a string from a native
- method implemented in a shared library and then displays it in the application UI.</li>
-
- <li><code>two-libs</code> — a simple application that loads a shared library dynamically
- and calls a native method provided by the library. In this case, the method is implemented in a
- static library imported by the shared library.</li>
-
- <li><code>san-angeles</code> — a simple application that renders 3D graphics through the
- native OpenGL ES APIs, while managing activity lifecycle with a {@link
- android.opengl.GLSurfaceView} object.</li>
-
- <li><code>hello-gl2</code> — a simple application that renders a triangle using OpenGL ES
- 2.0 vertex and fragment shaders.</li>
-
- <li><code>hello-neon</code> — a simple application that shows how to use the
- <code>cpufeatures</code> library to check CPU capabilities at runtime, then use NEON intrinsics
- if supported by the CPU. Specifically, the application implements two versions of a tiny
- benchmark for a FIR filter loop, a C version and a NEON-optimized version for devices that
- support it.</li>
-
- <li><code>bitmap-plasma</code> — a simple application that demonstrates how to access the
- pixel buffers of Android {@link android.graphics.Bitmap} objects from native code, and uses
- this to generate an old-school "plasma" effect.</li>
-
- <li><code>native-activity</code> — a simple application that demonstrates how to use the
- native-app-glue static library to create a native activity</li>
-
- <li><code>native-plasma</code> — a version of bitmap-plasma implemented with a native
- activity.</li>
- </ul>
-
- <p>For each sample, the NDK includes the corresponding C source code and the necessary Android.mk
- and Application.mk files. There are located under <code><ndk>/samples/<name>/</code>
- and their source code can be found under <code><ndk>/samples/<name>/jni/</code>.</p>
-
- <p>You can build the shared libraries for the sample apps by going into
- <code><ndk>/samples/<name>/</code> then calling the <code>ndk-build</code> command.
- The generated shared libraries will be located under
- <code><ndk>/samples/<name>/libs/armeabi/</code> for (ARMv5TE machine code) and/or
- <code><ndk>/samples/<name>/libs/armeabi-v7a/</code> for (ARMv7 machine code).</p>
-
- <p>Next, build the sample Android applications that use the shared libraries:</p>
-
- <ul>
- <li>If you are developing in Eclipse with ADT, use the New Project Wizard to create a new
- Android project for each sample, using the "Import from Existing Source" option and importing
- the source from <code><ndk>/apps/<app_name>/project/</code>. Then, set up an AVD,
- if necessary, and build/run the application in the emulator. For more information about
- creating a new Android project in Eclipse, see <a href=
- "{@docRoot}guide/developing/eclipse-adt.html">Developing in Eclipse</a>.</li>
-
- <li>If you are developing with Ant, use the <code>android</code> tool to create the build file
- for each of the sample projects at <code><ndk>/apps/<app_name>/project/</code>.
- Then set up an AVD, if necessary, build your project in the usual way, and run it in the
- emulator. For more information, see <a href=
- "{@docRoot}guide/developing/other-ide.html">Developing in Other IDEs</a>.</li>
- </ul>
-
- <h3 id="hello-jni">Exploring the hello-jni Sample</h3>
-
- <p>The hello-jni sample is a simple demonstration on how to use JNI from an Android application.
- The HelloJni activity receives a string from a simple C function and displays it in a
- TextView.</p>
-
- <p>The main components of the sample include:</p>
-
- <ul>
- <li>The familiar basic structure of an Android application (an <code>AndroidManifest.xml</code>
- file, a <code>src/</code> and <code>res</code> directories, and a main activity)</li>
-
- <li>A <code>jni/</code> directory that includes the implemented source file for the native code
- as well as the Android.mk file</li>
-
- <li>A <code>tests/</code> directory that contains unit test code.</li>
- </ul>
-
- <ol>
- <li>Create a new project in Eclipse from the existing sample source or use the
- <code>android</code> tool to update the project so it generates a build.xml file that you can
- use to build the sample.
-
- <ul>
- <li>In Eclipse:
-
- <ol type="a">
- <li>Click <strong>File > New Android Project...</strong></li>
-
- <li>Select the <strong>Create project from existing source</strong> radio button.</li>
-
- <li>Select any API level above Android 1.5.</li>
-
- <li>In the <strong>Location</strong> field, click <strong>Browse...</strong> and select
- the <code><ndk-root>/samples/hello-jni</code> directory.</li>
-
- <li>Click <strong>Finish</strong>.</li>
- </ol>
- </li>
-
- <li>On the command line:
-
- <ol type="a">
- <li>Change to the <code><ndk-root>/samples/hello-jni</code> directory.</li>
-
- <li>Run the following command to generate a build.xml file:
- <pre class="no-pretty-print">
-android update project -p . -s
-</pre>
- </li>
- </ol>
- </li>
- </ul>
- </li>
-
- <li>Compile the native code using the <code>ndk-build</code> command.
- <pre class="no-pretty-print">
-cd <ndk-root>/samples/hello-jni
-<ndk_root>/ndk-build
-</pre>
- </li>
-
- <li>Build and install the application as you would a normal Android application. If you are
- using Eclipse, run the application to build and install it on a device. If you are using Ant,
- run the following commands from the project directory:
- <pre class="no-pretty-print">
-ant debug
-adb install bin/HelloJni-debug.apk
-</pre>
- </li>
- </ol>
-
- <p>When you run the application on the device, the string <code>Hello JNI</code> should appear on
- your device. You can explore the rest of the samples that are located in the
- <code><ndk-root>/samples</code> directory for more examples on how to use the JNI.</p>
-
- <h3 id="native-activity">Exploring the native-activity Sample Application</h3>
-
- <p>The native-activity sample provided with the Android NDK demonstrates how to use the
- android_native_app_glue static library. This static library makes creating a native activity
- easier by providing you with an implementation that handles your callbacks in another thread, so
- you do not have to worry about them blocking your main UI thread. The main parts of the sample
- are described below:</p>
-
- <ul>
- <li>The familiar basic structure of an Android application (an <code>AndroidManifest.xml</code>
- file, a <code>src/</code> and <code>res</code> directories). The AndroidManifest.xml declares
- that the application is native and specifies the .so file of the native activity. See {@link
- android.app.NativeActivity} for the source or see the
- <code><ndk_root>/platforms/samples/native-activity/AndroidManifest.xml</code> file.</li>
-
- <li>A <code>jni/</code> directory contains the native activity, main.c, which uses the
- <code>android_native_app_glue.h</code> interface to implement the activity. The Android.mk that
- describes the native module to the build system also exists here.</li>
- </ul>
-
- <p>To build this sample application:</p>
-
- <ol>
- <li>Create a new project in Eclipse from the existing sample source or use the
- <code>android</code> tool to update the project so it generates a build.xml file that you can
- use to build the sample.
-
- <ul>
- <li>In Eclipse:
-
- <ol type="a">
- <li>Click <strong>File > New Android Project...</strong></li>
-
- <li>Select the <strong>Create project from existing source</strong> radio button.</li>
-
- <li>Select any API level above Android 2.3.</li>
-
- <li>In the <strong>Location</strong> field, click <strong>Browse...</strong> and select
- the <code><ndk-root>/samples/native-activity</code> directory.</li>
-
- <li>Click <strong>Finish</strong>.</li>
- </ol>
- </li>
-
- <li>On the command line:
-
- <ol type="a">
- <li>Change to the <code><ndk-root>/samples/native-activity</code> directory.</li>
-
- <li>Run the following command to generate a build.xml file:
- <pre class="no-pretty-print">
-android update project -p . -s
-</pre>
- </li>
- </ol>
- </li>
- </ul>
- </li>
-
- <li>Compile the native code using the <code>ndk-build</code> command.
- <pre class="no-pretty-print">
-cd <ndk-root>/platforms/samples/android-9/samples/native-activity
-<ndk_root>/ndk-build
-</pre>
- </li>
-
- <li>Build and install the application as you would a normal Android application. If you are
- using Eclipse, run the application to build and install it on a device. If you are using Ant,
- run the following commands in the project directory, then run the application on the device:
- <pre class="no-pretty-print">
-ant debug
-adb install bin/NativeActivity-debug.apk
-</pre>
- </li>
- </ol>
-
<h2 id="forum">Discussion Forum and Mailing List</h2>
<p>If you have questions about the NDK or would like to read or contribute to discussions about
diff --git a/docs/html/sdk/ndk/overview.jd b/docs/html/sdk/ndk/overview.jd
index a7ec5d4..f6d148a 100644
--- a/docs/html/sdk/ndk/overview.jd
+++ b/docs/html/sdk/ndk/overview.jd
@@ -7,10 +7,8 @@
<ol>
<li><a href="#choosing">When to Develop in Native Code</a></li>
-
<li>
<a href="#contents">Contents of the NDK</a>
-
<ol>
<li><a href="#tools">Development tools</a></li>
@@ -19,9 +17,7 @@
<li><a href="#samples">Sample applications</a></li>
</ol>
</li>
-
<li><a href="#reqs">System and Software Requirements</a></li>
-
</ol>
</div>
</div>
@@ -102,9 +98,8 @@
later.</li>
<li>
- <p>Write a native activity, which allows you to potentially create an application completely in native
- code, because you can implement the lifecycle callbacks natively. The Android SDK provides
- the {@link android.app.NativeActivity} class, which is a convenience class that notifies your
+ <p>Write a native activity, which allows you to implement the lifecycle callbacks in native
+ code. The Android SDK provides the {@link android.app.NativeActivity} class, which is a convenience class that notifies your
native code of any activity lifecycle callbacks (<code>onCreate()</code>, <code>onPause()</code>,
<code>onResume()</code>, etc). You can implement the callbacks in your native code to handle
these events when they occur. Applications that use native activities must be run on Android
@@ -142,6 +137,10 @@
<li>libjnigraphics (Pixel buffer access) header (for Android 2.2 and above).</li>
<li>A Minimal set of headers for C++ support</li>
+
+ <li>OpenSL ES native audio libraries</li>
+
+ <li>Android native application APIS</li>
</ul>
<p>The NDK also provides a build system that lets you work efficiently with your sources, without
@@ -163,25 +162,18 @@
the <code><ndk>/docs/</code> directory. Included are these files:</p>
<ul>
- <li>INSTALL.HTML — describes how to install the NDK and configure it for your host
+ <li>
+ INSTALL.HTML — describes how to install the NDK and configure it for your host
system</li>
<li>OVERVIEW.HTML — provides an overview of the NDK capabilities and usage</li>
-
+
<li>ANDROID-MK.HTML — describes the use of the Android.mk file, which defines the native
sources you want to compile</li>
-
+
<li>APPLICATION-MK.HTML — describes the use of the Application.mk file, which describes
- the native sources required by your Android application</li>
-
- <li>HOWTO.HTML — information about common tasks associated with NDK development.</li>
-
- <li>SYSTEM-ISSUES.HTML — known issues in the Android system images that you should be
- aware of, if you are developing using the NDK.</li>
-
- <li>STABLE-APIS.HTML — a complete list of the stable APIs exposed by headers in the
- NDK.</li>
-
+ the native sources required by your Android application</li>
+ <li>CPLUSPLUS-SUPPORT.HTML — describes the C++ support provided in the Android NDK</li>
<li>CPU-ARCH-ABIS.HTML — a description of supported CPU architectures and how to target
them.</li>
@@ -193,6 +185,32 @@
instructions.</li>
<li>CHANGES.HTML — a complete list of changes to the NDK across all releases.</li>
+
+ <li>DEVELOPMENT.HTML — describes how to modify the NDK and generate release packages for it</li>
+
+ <li>HOWTO.HTML — information about common tasks associated with NDK development</li>
+
+ <li>IMPORT-MODULE.HTML — describes how to share and reuse modules</li>
+
+ <li>LICENSES.HTML — information about the various open source licenses that govern the Android NDK</li>
+
+ <li>NATIVE-ACTIVITY.HTML — describes how to implement native activities</li>
+
+ <li>NDK-BUILD.HTML — describes the usage of the ndk-build script</li>
+
+ <li>NDK-GDB.HTML — describes how to use the native code debugger</li>
+
+ <li>PREBUILTS.HTML — information about how shared and static prebuilt libraries work </li>
+
+ <li>STANDALONE-TOOLCHAIN.HTML — describes how to use Android NDK toolchain as a standalone
+ compiler (still in beta).</li>
+
+ <li>SYSTEM-ISSUES.HTML — known issues in the Android system images that you should be
+ aware of, if you are developing using the NDK.</li>
+
+ <li>STABLE-APIS.HTML — a complete list of the stable APIs exposed by headers in the
+ NDK.</li>
+
</ul>
<p>Additionally, the package includes detailed information about the "bionic" C library provided
@@ -206,9 +224,218 @@
<h3 id="samples">Sample applications</h3>
- <p>The NDK includes sample Android applications that illustrate how to use native code in your
- Android applications. For more information, see <a href=
- "{@docRoot}sdk/ndk/installing.html#samples">Sample Applications</a>.</p>
+<p>The NDK includes sample applications that illustrate how to use native code in your Android
+ applications:</p>
+
+ <ul>
+ <li><code>hello-jni</code> — a simple application that loads a string from a native
+ method implemented in a shared library and then displays it in the application UI.</li>
+
+ <li><code>two-libs</code> — a simple application that loads a shared library dynamically
+ and calls a native method provided by the library. In this case, the method is implemented in a
+ static library imported by the shared library.</li>
+
+ <li><code>san-angeles</code> — a simple application that renders 3D graphics through the
+ native OpenGL ES APIs, while managing activity lifecycle with a {@link
+ android.opengl.GLSurfaceView} object.</li>
+
+ <li><code>hello-gl2</code> — a simple application that renders a triangle using OpenGL ES
+ 2.0 vertex and fragment shaders.</li>
+
+ <li><code>hello-neon</code> — a simple application that shows how to use the
+ <code>cpufeatures</code> library to check CPU capabilities at runtime, then use NEON intrinsics
+ if supported by the CPU. Specifically, the application implements two versions of a tiny
+ benchmark for a FIR filter loop, a C version and a NEON-optimized version for devices that
+ support it.</li>
+
+ <li><code>bitmap-plasma</code> — a simple application that demonstrates how to access the
+ pixel buffers of Android {@link android.graphics.Bitmap} objects from native code, and uses
+ this to generate an old-school "plasma" effect.</li>
+
+ <li><code>native-activity</code> — a simple application that demonstrates how to use the
+ native-app-glue static library to create a native activity</li>
+
+ <li><code>native-plasma</code> — a version of bitmap-plasma implemented with a native
+ activity.</li>
+ </ul>
+
+ <p>For each sample, the NDK includes the corresponding C source code and the necessary Android.mk
+ and Application.mk files. There are located under <code><ndk>/samples/<name>/</code>
+ and their source code can be found under <code><ndk>/samples/<name>/jni/</code>.</p>
+
+ <p>You can build the shared libraries for the sample apps by going into
+ <code><ndk>/samples/<name>/</code> then calling the <code>ndk-build</code> command.
+ The generated shared libraries will be located under
+ <code><ndk>/samples/<name>/libs/armeabi/</code> for (ARMv5TE machine code) and/or
+ <code><ndk>/samples/<name>/libs/armeabi-v7a/</code> for (ARMv7 machine code).</p>
+
+ <p>Next, build the sample Android applications that use the shared libraries:</p>
+
+ <ul>
+ <li>If you are developing in Eclipse with ADT, use the New Project Wizard to create a new
+ Android project for each sample, using the "Import from Existing Source" option and importing
+ the source from <code><ndk>/apps/<app_name>/project/</code>. Then, set up an AVD,
+ if necessary, and build/run the application in the emulator. For more information about
+ creating a new Android project in Eclipse, see <a href=
+ "{@docRoot}guide/developing/eclipse-adt.html">Developing in Eclipse</a>.</li>
+
+ <li>If you are developing with Ant, use the <code>android</code> tool to create the build file
+ for each of the sample projects at <code><ndk>/apps/<app_name>/project/</code>.
+ Then set up an AVD, if necessary, build your project in the usual way, and run it in the
+ emulator. For more information, see <a href=
+ "{@docRoot}guide/developing/other-ide.html">Developing in Other IDEs</a>.</li>
+ </ul>
+
+ <h4 id="hello-jni">Exploring the hello-jni Sample</h4>
+
+ <p>The hello-jni sample is a simple demonstration on how to use JNI from an Android application.
+ The HelloJni activity receives a string from a simple C function and displays it in a
+ TextView.</p>
+
+ <p>The main components of the sample include:</p>
+
+ <ul>
+ <li>The familiar basic structure of an Android application (an <code>AndroidManifest.xml</code>
+ file, a <code>src/</code> and <code>res</code> directories, and a main activity)</li>
+
+ <li>A <code>jni/</code> directory that includes the implemented source file for the native code
+ as well as the Android.mk file</li>
+
+ <li>A <code>tests/</code> directory that contains unit test code.</li>
+ </ul>
+
+ <ol>
+ <li>Create a new project in Eclipse from the existing sample source or use the
+ <code>android</code> tool to update the project so it generates a build.xml file that you can
+ use to build the sample.
+
+ <ul>
+ <li>In Eclipse:
+
+ <ol type="a">
+ <li>Click <strong>File > New Android Project...</strong></li>
+
+ <li>Select the <strong>Create project from existing source</strong> radio button.</li>
+
+ <li>Select any API level above Android 1.5.</li>
+
+ <li>In the <strong>Location</strong> field, click <strong>Browse...</strong> and select
+ the <code><ndk-root>/samples/hello-jni</code> directory.</li>
+
+ <li>Click <strong>Finish</strong>.</li>
+ </ol>
+ </li>
+
+ <li>On the command line:
+
+ <ol type="a">
+ <li>Change to the <code><ndk-root>/samples/hello-jni</code> directory.</li>
+
+ <li>Run the following command to generate a build.xml file:
+ <pre class="no-pretty-print">android update project -p . -s</pre>
+ </li>
+ </ol>
+ </li>
+ </ul>
+ </li>
+
+ <li>Compile the native code using the <code>ndk-build</code> command.
+ <pre class="no-pretty-print">
+cd <ndk-root>/samples/hello-jni
+<ndk_root>/ndk-build
+</pre>
+ </li>
+
+ <li>Build and install the application as you would a normal Android application. If you are
+ using Eclipse, run the application to build and install it on a device. If you are using Ant,
+ run the following commands from the project directory:
+ <pre class="no-pretty-print">
+ant debug
+adb install bin/HelloJni-debug.apk
+</pre>
+ </li>
+ </ol>
+
+ <p>When you run the application on the device, the string <code>Hello JNI</code> should appear on
+ your device. You can explore the rest of the samples that are located in the
+ <code><ndk-root>/samples</code> directory for more examples on how to use the JNI.</p>
+
+ <h4 id="native-activity">Exploring the native-activity Sample Application</h4>
+
+ <p>The native-activity sample provided with the Android NDK demonstrates how to use the
+ android_native_app_glue static library. This static library makes creating a native activity
+ easier by providing you with an implementation that handles your callbacks in another thread, so
+ you do not have to worry about them blocking your main UI thread. The main parts of the sample
+ are described below:</p>
+
+ <ul>
+ <li>The familiar basic structure of an Android application (an <code>AndroidManifest.xml</code>
+ file, a <code>src/</code> and <code>res</code> directories). The AndroidManifest.xml declares
+ that the application is native and specifies the .so file of the native activity. See {@link
+ android.app.NativeActivity} for the source or see the
+ <code><ndk_root>/platforms/samples/native-activity/AndroidManifest.xml</code> file.</li>
+
+ <li>A <code>jni/</code> directory contains the native activity, main.c, which uses the
+ <code>android_native_app_glue.h</code> interface to implement the activity. The Android.mk that
+ describes the native module to the build system also exists here.</li>
+ </ul>
+
+ <p>To build this sample application:</p>
+
+ <ol>
+ <li>Create a new project in Eclipse from the existing sample source or use the
+ <code>android</code> tool to update the project so it generates a build.xml file that you can
+ use to build the sample.
+
+ <ul>
+ <li>In Eclipse:
+
+ <ol type="a">
+ <li>Click <strong>File > New Android Project...</strong></li>
+
+ <li>Select the <strong>Create project from existing source</strong> radio button.</li>
+
+ <li>Select any API level above Android 2.3.</li>
+
+ <li>In the <strong>Location</strong> field, click <strong>Browse...</strong> and select
+ the <code><ndk-root>/samples/native-activity</code> directory.</li>
+
+ <li>Click <strong>Finish</strong>.</li>
+ </ol>
+ </li>
+
+ <li>On the command line:
+
+ <ol type="a">
+ <li>Change to the <code><ndk-root>/samples/native-activity</code> directory.</li>
+
+ <li>Run the following command to generate a build.xml file:
+ <pre class="no-pretty-print">
+android update project -p . -s
+</pre>
+ </li>
+ </ol>
+ </li>
+ </ul>
+ </li>
+
+ <li>Compile the native code using the <code>ndk-build</code> command.
+ <pre class="no-pretty-print">
+cd <ndk-root>/platforms/samples/android-9/samples/native-activity
+<ndk_root>/ndk-build
+</pre>
+ </li>
+
+ <li>Build and install the application as you would a normal Android application. If you are
+ using Eclipse, run the application to build and install it on a device. If you are using Ant,
+ run the following commands in the project directory, then run the application on the device:
+ <pre class="no-pretty-print">
+ant debug
+adb install bin/NativeActivity-debug.apk
+</pre>
+ </li>
+ </ol>
+
<h2 id="reqs">System and Software Requirements</h2>
@@ -313,7 +540,7 @@
to users whose devices are capable of supporting your application. For example:
<pre style="margin:1em;">
<manifest>
- ...
+ ...
<!-- Declare that the application uses the OpenGL ES 2.0 API and is designed
to run only on devices that support OpenGL ES 2.0 or higher. -->
<uses-feature android:glEsVersion="0x00020000" />
@@ -331,4 +558,4 @@
containing the library can be deployed only to devices running Android 2.2 (API level 8) or
higher. To ensure compatibility, make sure that your application declares <code><uses-sdk
android:minSdkVersion="8" /></code> attribute value in its manifest.</li>
- </ul>
\ No newline at end of file
+ </ul>
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 6364d58..431aaa47 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -79,6 +79,14 @@
// the camera only has a single output, and does not have
// separate output for video frames and preview frame.
void getSupportedVideoSizes(Vector<Size> &sizes) const;
+ // Retrieve the preferred preview size (width and height) in pixels
+ // for video recording. The given width and height must be one of
+ // supported preview sizes returned from getSupportedPreviewSizes().
+ // Must not be called if getSupportedVideoSizes() returns an empty
+ // Vector of Size. If getSupportedVideoSizes() returns an empty
+ // Vector of Size, the width and height returned from this method
+ // is invalid, and is "-1x-1".
+ void getPreferredPreviewSizeForVideo(int *width, int *height) const;
void setPreviewFrameRate(int fps);
int getPreviewFrameRate() const;
@@ -319,6 +327,21 @@
// frameworks/base/include/camera/Camera.h.
// Example: "176x144,1280x720". Read only.
static const char KEY_SUPPORTED_VIDEO_SIZES[];
+
+ // Preferred preview frame size in pixels for video recording.
+ // The width and height must be one of the supported sizes retrieved
+ // via KEY_SUPPORTED_PREVIEW_SIZES. This key can be used only when
+ // getSupportedVideoSizes() does not return an empty Vector of Size.
+ // Camcorder applications are recommended to set the preview size
+ // to a value that is not larger than the preferred preview size.
+ // In other words, the product of the width and height of the
+ // preview size should not be larger than that of the preferred
+ // preview size. In addition, we recommend to choos a preview size
+ // that has the same aspect ratio as the resolution of video to be
+ // recorded.
+ // Example value: "800x600". Read only.
+ static const char KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[];
+
// The image format for video frames. See CAMERA_MSG_VIDEO_FRAME in
// frameworks/base/include/camera/Camera.h.
// Example value: "yuv420sp" or PIXEL_FORMAT_XXX constants. Read only.
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 45b1b9a..e9a5f8c 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -75,6 +75,7 @@
const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format";
const char CameraParameters::KEY_VIDEO_SIZE[] = "video-size";
const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values";
+const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video";
const char CameraParameters::TRUE[] = "true";
const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity";
@@ -333,6 +334,14 @@
parse_pair(p, width, height, 'x');
}
+void CameraParameters::getPreferredPreviewSizeForVideo(int *width, int *height) const
+{
+ *width = *height = -1;
+ const char *p = get(KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
void CameraParameters::getSupportedPreviewSizes(Vector<Size> &sizes) const
{
const char *previewSizesStr = get(KEY_SUPPORTED_PREVIEW_SIZES);
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index 0c48556..41309dc 100755
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -43,10 +43,8 @@
* <li>Frequency data: 8-bit magnitude FFT by using the {@link #getFft(byte[])} method</li>
* </ul>
* <p>The length of the capture can be retrieved or specified by calling respectively
- * {@link #getCaptureSize()} and {@link #setCaptureSize(int)} methods. Note that the size of the FFT
- * is half of the specified capture size but both sides of the spectrum are returned yielding in a
- * number of bytes equal to the capture size. The capture size must be a power of 2 in the range
- * returned by {@link #getCaptureSizeRange()}.
+ * {@link #getCaptureSize()} and {@link #setCaptureSize(int)} methods. The capture size must be a
+ * power of 2 in the range returned by {@link #getCaptureSizeRange()}.
* <p>In addition to the polling capture mode described above with {@link #getWaveForm(byte[])} and
* {@link #getFft(byte[])} methods, a callback mode is also available by installing a listener by
* use of the {@link #setDataCaptureListener(OnDataCaptureListener, int, boolean, boolean)} method.
@@ -333,11 +331,43 @@
}
}
/**
- * Returns a frequency capture of currently playing audio content. The capture is a 8-bit
- * magnitude FFT. Note that the size of the FFT is half of the specified capture size but both
- * sides of the spectrum are returned yielding in a number of bytes equal to the capture size.
- * {@see #getCaptureSize()}.
+ * Returns a frequency capture of currently playing audio content.
* <p>This method must be called when the Visualizer is enabled.
+ * <p>The capture is an 8-bit magnitude FFT, the frequency range covered being 0 (DC) to half of
+ * the sampling rate returned by {@link #getSamplingRate()}. The capture returns the real and
+ * imaginary parts of a number of frequency points equal to half of the capture size plus one.
+ * <p>Note: only the real part is returned for the first point (DC) and the last point
+ * (sampling frequency / 2).
+ * <p>The layout in the returned byte array is as follows:
+ * <ul>
+ * <li> n is the capture size returned by getCaptureSize()</li>
+ * <li> Rfk, Ifk are respectively the real and imaginary parts of the kth frequency
+ * component</li>
+ * <li> If Fs is the sampling frequency retuned by getSamplingRate() the kth frequency is:
+ * (k*Fs)/(n/2) </li>
+ * </ul>
+ * <table border="0" cellspacing="0" cellpadding="0">
+ * <tr><td>Index </p></td>
+ * <td>0 </p></td>
+ * <td>1 </p></td>
+ * <td>2 </p></td>
+ * <td>3 </p></td>
+ * <td>4 </p></td>
+ * <td>5 </p></td>
+ * <td>... </p></td>
+ * <td>n - 2 </p></td>
+ * <td>n - 1 </p></td></tr>
+ * <tr><td>Data </p></td>
+ * <td>Rf0 </p></td>
+ * <td>Rf(n/2) </p></td>
+ * <td>Rf1 </p></td>
+ * <td>If1 </p></td>
+ * <td>Rf2 </p></td>
+ * <td>If2 </p></td>
+ * <td>... </p></td>
+ * <td>Rf(n-1)/2 </p></td>
+ * <td>If(n-1)/2 </p></td></tr>
+ * </table>
* @param fft array of bytes where the FFT should be returned
* @return {@link #SUCCESS} in case of success,
* {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
diff --git a/services/java/com/android/server/ScreenRotationAnimation.java b/services/java/com/android/server/ScreenRotationAnimation.java
index 1cc6a2a..a95a6c7 100644
--- a/services/java/com/android/server/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/ScreenRotationAnimation.java
@@ -122,7 +122,9 @@
mSurface.unlockCanvasAndPost(c);
Surface.closeTransaction();
- screenshot.recycle();
+ if (screenshot != null) {
+ screenshot.recycle();
+ }
}
static int deltaRotation(int oldRotation, int newRotation) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 5e49404..27ec1af 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -6848,6 +6848,8 @@
}
if (!mParentFrame.equals(pf)) {
+ //Slog.i(TAG, "Window " + this + " content frame from " + mParentFrame
+ // + " to " + pf);
mParentFrame.set(pf);
mContentChanged = true;
}
@@ -7734,12 +7736,10 @@
* sense to call from performLayoutAndPlaceSurfacesLockedInner().)
*/
boolean shouldAnimateMove() {
- return mContentChanged && !mAnimating && !mLastHidden && !mDisplayFrozen
+ return mContentChanged && !mExiting && !mLastHidden && !mDisplayFrozen
&& (mFrame.top != mLastFrame.top
|| mFrame.left != mLastFrame.left)
- && (mAttachedWindow == null
- || (mAttachedWindow.mAnimation == null
- && !mAttachedWindow.shouldAnimateMove()))
+ && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove())
&& mPolicy.isScreenOn();
}
@@ -9223,6 +9223,7 @@
if (!gone || !win.mHaveFrame) {
if (!win.mLayoutAttached) {
if (initial) {
+ //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
win.mContentChanged = false;
}
mPolicy.layoutWindowLw(win, win.mAttrs, null);
@@ -9257,6 +9258,7 @@
if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
|| !win.mHaveFrame) {
if (initial) {
+ //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
win.mContentChanged = false;
}
mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
@@ -9455,7 +9457,6 @@
w.setAnimation(a);
animDw = w.mLastFrame.left - w.mFrame.left;
animDh = w.mLastFrame.top - w.mFrame.top;
- w.mContentChanged = false;
}
// Execute animation.
@@ -10242,6 +10243,11 @@
w.mOrientationChanging = false;
}
+ if (w.mContentChanged) {
+ //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
+ w.mContentChanged = false;
+ }
+
final boolean canBeSeen = w.isDisplayedLw();
if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) {
diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp
index 18bd359..5c6aa99 100644
--- a/services/sensorservice/GravitySensor.cpp
+++ b/services/sensorservice/GravitySensor.cpp
@@ -29,8 +29,8 @@
GravitySensor::GravitySensor(sensor_t const* list, size_t count)
: mSensorDevice(SensorDevice::getInstance()),
- mEnabled(false), mAccTime(0),
- mLowPass(M_SQRT1_2, 1),
+ mAccTime(0),
+ mLowPass(M_SQRT1_2, 1.5f),
mX(mLowPass), mY(mLowPass), mZ(mLowPass)
{
@@ -71,15 +71,9 @@
}
return false;
}
-
-bool GravitySensor::isEnabled() const {
- return mEnabled;
-}
-
status_t GravitySensor::activate(void* ident, bool enabled) {
status_t err = mSensorDevice.activate(this, mAccelerometer.getHandle(), enabled);
if (err == NO_ERROR) {
- mEnabled = enabled;
if (enabled) {
mAccTime = 0;
}
diff --git a/services/sensorservice/GravitySensor.h b/services/sensorservice/GravitySensor.h
index f9850b7..decfbb8 100644
--- a/services/sensorservice/GravitySensor.h
+++ b/services/sensorservice/GravitySensor.h
@@ -33,17 +33,15 @@
class GravitySensor : public SensorInterface {
SensorDevice& mSensorDevice;
Sensor mAccelerometer;
- bool mEnabled;
double mAccTime;
SecondOrderLowPassFilter mLowPass;
- BiquadFilter mX, mY, mZ;
+ CascadedBiquadFilter mX, mY, mZ;
public:
GravitySensor(sensor_t const* list, size_t count);
virtual bool process(sensors_event_t* outEvent,
const sensors_event_t& event);
- virtual bool isEnabled() const;
virtual status_t activate(void* ident, bool enabled);
virtual status_t setDelay(void* ident, int handle, int64_t ns);
virtual Sensor getSensor() const;
diff --git a/services/sensorservice/LinearAccelerationSensor.cpp b/services/sensorservice/LinearAccelerationSensor.cpp
index 2dc12dc..9425a92 100644
--- a/services/sensorservice/LinearAccelerationSensor.cpp
+++ b/services/sensorservice/LinearAccelerationSensor.cpp
@@ -53,10 +53,6 @@
return result;
}
-bool LinearAccelerationSensor::isEnabled() const {
- return mGravitySensor.isEnabled();
-}
-
status_t LinearAccelerationSensor::activate(void* ident, bool enabled) {
return mGravitySensor.activate(ident, enabled);
}
diff --git a/services/sensorservice/LinearAccelerationSensor.h b/services/sensorservice/LinearAccelerationSensor.h
index ee918ce..c577086a 100644
--- a/services/sensorservice/LinearAccelerationSensor.h
+++ b/services/sensorservice/LinearAccelerationSensor.h
@@ -40,7 +40,6 @@
const sensors_event_t& event);
public:
LinearAccelerationSensor(sensor_t const* list, size_t count);
- virtual bool isEnabled() const;
virtual status_t activate(void* ident, bool enabled);
virtual status_t setDelay(void* ident, int handle, int64_t ns);
virtual Sensor getSensor() const;
diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp
index 6f4b8be..418e7f8 100644
--- a/services/sensorservice/RotationVectorSensor.cpp
+++ b/services/sensorservice/RotationVectorSensor.cpp
@@ -34,7 +34,6 @@
RotationVectorSensor::RotationVectorSensor(sensor_t const* list, size_t count)
: mSensorDevice(SensorDevice::getInstance()),
- mEnabled(false),
mALowPass(M_SQRT1_2, 5.0f),
mAX(mALowPass), mAY(mALowPass), mAZ(mALowPass),
mMLowPass(M_SQRT1_2, 2.5f),
@@ -114,15 +113,18 @@
float qx = sqrtf( clamp( Hx - My - Az + 1) * 0.25f );
float qy = sqrtf( clamp(-Hx + My - Az + 1) * 0.25f );
float qz = sqrtf( clamp(-Hx - My + Az + 1) * 0.25f );
- const float n = 1.0f / (qw*qw + qx*qx + qy*qy + qz*qz);
- qx = copysignf(qx, Ay - Mz) * n;
- qy = copysignf(qy, Hz - Ax) * n;
- qz = copysignf(qz, Mx - Hy) * n;
+ qx = copysignf(qx, Ay - Mz);
+ qy = copysignf(qy, Hz - Ax);
+ qz = copysignf(qz, Mx - Hy);
+
+ // this quaternion is guaranteed to be normalized, by construction
+ // of the rotation matrix.
*outEvent = event;
outEvent->data[0] = qx;
outEvent->data[1] = qy;
outEvent->data[2] = qz;
+ outEvent->data[3] = qw;
outEvent->sensor = '_rov';
outEvent->type = SENSOR_TYPE_ROTATION_VECTOR;
return true;
@@ -130,19 +132,12 @@
return false;
}
-bool RotationVectorSensor::isEnabled() const {
- return mEnabled;
-}
-
status_t RotationVectorSensor::activate(void* ident, bool enabled) {
- if (mEnabled != enabled) {
- mSensorDevice.activate(this, mAcc.getHandle(), enabled);
- mSensorDevice.activate(this, mMag.getHandle(), enabled);
- mEnabled = enabled;
- if (enabled) {
- mMagTime = 0;
- mAccTime = 0;
- }
+ mSensorDevice.activate(this, mAcc.getHandle(), enabled);
+ mSensorDevice.activate(this, mMag.getHandle(), enabled);
+ if (enabled) {
+ mMagTime = 0;
+ mAccTime = 0;
}
return NO_ERROR;
}
diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h
index e7f28c9..b7c9512 100644
--- a/services/sensorservice/RotationVectorSensor.h
+++ b/services/sensorservice/RotationVectorSensor.h
@@ -34,7 +34,6 @@
SensorDevice& mSensorDevice;
Sensor mAcc;
Sensor mMag;
- bool mEnabled;
float mMagData[3];
double mAccTime;
double mMagTime;
@@ -47,7 +46,6 @@
RotationVectorSensor(sensor_t const* list, size_t count);
virtual bool process(sensors_event_t* outEvent,
const sensors_event_t& event);
- virtual bool isEnabled() const;
virtual status_t activate(void* ident, bool enabled);
virtual status_t setDelay(void* ident, int handle, int64_t ns);
virtual Sensor getSensor() const;
diff --git a/services/sensorservice/SecondOrderLowPassFilter.cpp b/services/sensorservice/SecondOrderLowPassFilter.cpp
index e13e1362..eeb6d1e 100644
--- a/services/sensorservice/SecondOrderLowPassFilter.cpp
+++ b/services/sensorservice/SecondOrderLowPassFilter.cpp
@@ -67,4 +67,23 @@
}
// ---------------------------------------------------------------------------
+
+CascadedBiquadFilter::CascadedBiquadFilter(const SecondOrderLowPassFilter& s)
+ : mA(s), mB(s)
+{
+}
+
+float CascadedBiquadFilter::init(float x)
+{
+ mA.init(x);
+ mB.init(x);
+ return x;
+}
+
+float CascadedBiquadFilter::operator()(float x)
+{
+ return mB(mA(x));
+}
+
+// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SecondOrderLowPassFilter.h b/services/sensorservice/SecondOrderLowPassFilter.h
index 998ca35b9..85698ca 100644
--- a/services/sensorservice/SecondOrderLowPassFilter.h
+++ b/services/sensorservice/SecondOrderLowPassFilter.h
@@ -54,6 +54,18 @@
float operator()(float in);
};
+/*
+ * Two cascaded biquad IIR filters
+ * (4-poles IIR)
+ */
+class CascadedBiquadFilter {
+ BiquadFilter mA;
+ BiquadFilter mB;
+public:
+ CascadedBiquadFilter(const SecondOrderLowPassFilter& s);
+ float init(float in);
+ float operator()(float in);
+};
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 73f85ba..f192913 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -137,9 +137,8 @@
Mutex::Autolock _l(mLock);
for (size_t i=0 ; i<size_t(count) ; i++) {
- snprintf(buffer, SIZE, "handle=0x%08x, active-count=%d / %d\n",
+ snprintf(buffer, SIZE, "handle=0x%08x, active-count=%d\n",
list[i].handle,
- mActivationCount.valueFor(list[i].handle).count,
mActivationCount.valueFor(list[i].handle).rates.size());
result.append(buffer);
}
@@ -167,22 +166,25 @@
bool actuateHardware = false;
Info& info( mActivationCount.editValueFor(handle) );
- int32_t& count(info.count);
if (enabled) {
- if (android_atomic_inc(&count) == 0) {
- actuateHardware = true;
- }
Mutex::Autolock _l(mLock);
if (info.rates.indexOfKey(ident) < 0) {
info.rates.add(ident, DEFAULT_EVENTS_PERIOD);
+ actuateHardware = true;
+ } else {
+ // sensor was already activated for this ident
}
} else {
- if (android_atomic_dec(&count) == 1) {
- actuateHardware = true;
- }
Mutex::Autolock _l(mLock);
- info.rates.removeItem(ident);
+ if (info.rates.removeItem(ident) >= 0) {
+ if (info.rates.size() == 0) {
+ actuateHardware = true;
+ }
+ } else {
+ // sensor wasn't enabled for this ident
+ }
}
+
if (actuateHardware) {
err = mSensorDevice->activate(mSensorDevice, handle, enabled);
if (enabled) {
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 63ecbcd..c19b2ce 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -40,8 +40,7 @@
Mutex mLock; // protect mActivationCount[].rates
// fixed-size array after construction
struct Info {
- Info() : count(0) { }
- int32_t count;
+ Info() { }
KeyedVector<void*, nsecs_t> rates;
};
DefaultKeyedVector<int, Info> mActivationCount;
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
index 93d23d9..be8eaff 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -32,7 +32,7 @@
HardwareSensor::HardwareSensor(const sensor_t& sensor)
: mSensorDevice(SensorDevice::getInstance()),
- mSensor(&sensor), mEnabled(false)
+ mSensor(&sensor)
{
LOGI("%s", sensor.name);
}
@@ -46,15 +46,8 @@
return true;
}
-bool HardwareSensor::isEnabled() const {
- return mEnabled;
-}
-
-status_t HardwareSensor::activate(void* ident,bool enabled) {
- status_t err = mSensorDevice.activate(ident, mSensor.getHandle(), enabled);
- if (err == NO_ERROR)
- mEnabled = enabled;
- return err;
+status_t HardwareSensor::activate(void* ident, bool enabled) {
+ return mSensorDevice.activate(ident, mSensor.getHandle(), enabled);
}
status_t HardwareSensor::setDelay(void* ident, int handle, int64_t ns) {
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index eebd563..084f2f5 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -38,7 +38,6 @@
virtual bool process(sensors_event_t* outEvent,
const sensors_event_t& event) = 0;
- virtual bool isEnabled() const = 0;
virtual status_t activate(void* ident, bool enabled) = 0;
virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0;
virtual Sensor getSensor() const = 0;
@@ -51,7 +50,6 @@
{
SensorDevice& mSensorDevice;
Sensor mSensor;
- bool mEnabled;
public:
HardwareSensor(const sensor_t& sensor);
@@ -61,7 +59,6 @@
virtual bool process(sensors_event_t* outEvent,
const sensors_event_t& event);
- virtual bool isEnabled() const;
virtual status_t activate(void* ident, bool enabled);
virtual status_t setDelay(void* ident, int handle, int64_t ns);
virtual Sensor getSensor() const;
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 5b49305..719e5b4 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -700,6 +700,10 @@
Log.d(LOG_TAG, this.toString());
}
+ if (!canDial(phone)) {
+ throw new CallStateException("cannot dial in current state");
+ }
+
if ( hasActiveFgCall() ) {
Phone activePhone = getActiveFgCall().getPhone();
boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle());
@@ -753,6 +757,32 @@
}
/**
+ * Phone can make a call only if ALL of the following are true:
+ * - Phone is not powered off
+ * - There's no incoming or waiting call
+ * - There's available call slot in either foreground or background
+ * - The foreground call is ACTIVE or IDLE or DISCONNECTED.
+ * (We mainly need to make sure it *isn't* DIALING or ALERTING.)
+ * @param phone
+ * @return true if the phone can make a new call
+ */
+ private boolean canDial(Phone phone) {
+ int serviceState = phone.getServiceState().getState();
+ boolean hasRingingCall = hasActiveRingingCall();
+ boolean hasActiveCall = hasActiveFgCall();
+ boolean hasHoldingCall = hasActiveBgCall();
+ boolean allLinesTaken = hasActiveCall && hasHoldingCall;
+ Call.State fgCallState = getActiveFgCallState();
+
+ return (serviceState != ServiceState.STATE_POWER_OFF
+ && !hasRingingCall
+ && !allLinesTaken
+ && ((fgCallState == Call.State.ACTIVE)
+ || (fgCallState == Call.State.IDLE)
+ || (fgCallState == Call.State.DISCONNECTED)));
+ }
+
+ /**
* Whether or not the phone can do explicit call transfer in the current
* phone state--that is, one call holding and one call active.
* @return true if the phone can do explicit call transfer; false otherwise.
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index 82fcb6a..014901d 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -20,12 +20,13 @@
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.provider.ContactsContract.PhoneLookup;
import android.provider.ContactsContract.CommonDataKinds.Phone;
-import static android.provider.ContactsContract.RawContacts;
-import android.text.TextUtils;
-import android.telephony.TelephonyManager;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.PhoneLookup;
+import android.provider.ContactsContract.RawContacts;
import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.Log;
@@ -171,33 +172,17 @@
}
}
- // Look for the person ID.
-
- // TODO: This is pretty ugly now, see bug 2269240 for
- // more details. The column to use depends upon the type of URL,
- // for content://com.android.contacts/data/phones the "contact_id"
- // column is used. For content/com.andriod.contacts/phone_lookup"
- // the "_ID" column is used. If it is neither we leave columnIndex
- // at -1 and no person ID will be available.
-
- columnIndex = -1;
- String url = contactRef.toString();
- if (url.startsWith("content://com.android.contacts/data/phones")) {
- if (VDBG) Log.v(TAG,
- "URL path starts with 'data/phones' using RawContacts.CONTACT_ID");
- columnIndex = cursor.getColumnIndex(RawContacts.CONTACT_ID);
- } else if (url.startsWith("content://com.android.contacts/phone_lookup")) {
- if (VDBG) Log.v(TAG,
- "URL path starts with 'phone_lookup' using PhoneLookup._ID");
- columnIndex = cursor.getColumnIndex(PhoneLookup._ID);
- } else {
- Log.e(TAG, "Bad contact URL '" + url + "'");
- }
-
+ // Look for the person_id.
+ columnIndex = getColumnIndexForPersonId(contactRef, cursor);
if (columnIndex != -1) {
info.person_id = cursor.getLong(columnIndex);
+ if (VDBG) Log.v(TAG, "==> got info.person_id: " + info.person_id);
} else {
- Log.e(TAG, "person_id column missing for " + contactRef);
+ // No valid columnIndex, so we can't look up person_id.
+ Log.w(TAG, "Couldn't find person_id column for " + contactRef);
+ // Watch out: this means that anything that depends on
+ // person_id will be broken (like contact photo lookups in
+ // the in-call UI, for example.)
}
// look for the custom ringtone, create from the string stored
@@ -411,30 +396,120 @@
}
/**
+ * Returns the column index to use to find the "person_id" field in
+ * the specified cursor, based on the contact URI that was originally
+ * queried.
+ *
+ * This is a helper function for the getCallerInfo() method that takes
+ * a Cursor. Looking up the person_id is nontrivial (compared to all
+ * the other CallerInfo fields) since the column we need to use
+ * depends on what query we originally ran.
+ *
+ * Watch out: be sure to not do any database access in this method, since
+ * it's run from the UI thread (see comments below for more info.)
+ *
+ * @return the columnIndex to use (with cursor.getLong()) to get the
+ * person_id, or -1 if we couldn't figure out what colum to use.
+ *
+ * TODO: Add a unittest for this method. (This is a little tricky to
+ * test, since we'll need a live contacts database to test against,
+ * preloaded with at least some phone numbers and SIP addresses. And
+ * we'll probably have to hardcode the column indexes we expect, so
+ * the test might break whenever the contacts schema changes. But we
+ * can at least make sure we handle all the URI patterns we claim to,
+ * and that the mime types match what we expect...)
+ */
+ private static int getColumnIndexForPersonId(Uri contactRef, Cursor cursor) {
+ // TODO: This is pretty ugly now, see bug 2269240 for
+ // more details. The column to use depends upon the type of URL:
+ // - content://com.android.contacts/data/phones ==> use the "contact_id" column
+ // - content://com.android.contacts/phone_lookup ==> use the "_ID" column
+ // - content://com.android.contacts/data ==> use the "contact_id" column
+ // If it's none of the above, we leave columnIndex=-1 which means
+ // that the person_id field will be left unset.
+ //
+ // The logic here *used* to be based on the mime type of contactRef
+ // (for example Phone.CONTENT_ITEM_TYPE would tell us to use the
+ // RawContacts.CONTACT_ID column). But looking up the mime type requires
+ // a call to context.getContentResolver().getType(contactRef), which
+ // isn't safe to do from the UI thread since it can cause an ANR if
+ // the contacts provider is slow or blocked (like during a sync.)
+ //
+ // So instead, figure out the column to use for person_id by just
+ // looking at the URI itself.
+
+ if (VDBG) Log.v(TAG, "- getColumnIndexForPersonId: contactRef URI = '"
+ + contactRef + "'...");
+ // Warning: Do not enable the following logging (due to ANR risk.)
+ // if (VDBG) Log.v(TAG, "- MIME type: "
+ // + context.getContentResolver().getType(contactRef));
+
+ String url = contactRef.toString();
+ String columnName = null;
+ if (url.startsWith("content://com.android.contacts/data/phones")) {
+ // Direct lookup in the Phone table.
+ // MIME type: Phone.CONTENT_ITEM_TYPE (= "vnd.android.cursor.item/phone_v2")
+ if (VDBG) Log.v(TAG, "'data/phones' URI; using RawContacts.CONTACT_ID");
+ columnName = RawContacts.CONTACT_ID;
+ } else if (url.startsWith("content://com.android.contacts/data")) {
+ // Direct lookup in the Data table.
+ // MIME type: Data.CONTENT_TYPE (= "vnd.android.cursor.dir/data")
+ if (VDBG) Log.v(TAG, "'data' URI; using Data.CONTACT_ID");
+ // (Note Data.CONTACT_ID and RawContacts.CONTACT_ID are equivalent.)
+ columnName = Data.CONTACT_ID;
+ } else if (url.startsWith("content://com.android.contacts/phone_lookup")) {
+ // Lookup in the PhoneLookup table, which provides "fuzzy matching"
+ // for phone numbers.
+ // MIME type: PhoneLookup.CONTENT_TYPE (= "vnd.android.cursor.dir/phone_lookup")
+ if (VDBG) Log.v(TAG, "'phone_lookup' URI; using PhoneLookup._ID");
+ columnName = PhoneLookup._ID;
+ } else {
+ Log.w(TAG, "Unexpected prefix for contactRef '" + url + "'");
+ }
+ int columnIndex = (columnName != null) ? cursor.getColumnIndex(columnName) : -1;
+ if (VDBG) Log.v(TAG, "==> Using column '" + columnName
+ + "' (columnIndex = " + columnIndex + ") for person_id lookup...");
+ return columnIndex;
+ }
+
+ /**
* @return a string debug representation of this instance.
*/
public String toString() {
- return new StringBuilder(384)
- .append("\nname: " + /*name*/ "nnnnnn")
- .append("\nphoneNumber: " + /*phoneNumber*/ "xxxxxxx")
- .append("\ncnapName: " + cnapName)
- .append("\nnumberPresentation: " + numberPresentation)
- .append("\nnamePresentation: " + namePresentation)
- .append("\ncontactExits: " + contactExists)
- .append("\nphoneLabel: " + phoneLabel)
- .append("\nnumberType: " + numberType)
- .append("\nnumberLabel: " + numberLabel)
- .append("\nphotoResource: " + photoResource)
- .append("\nperson_id: " + person_id)
- .append("\nneedUpdate: " + needUpdate)
- .append("\ncontactRefUri: " + /*contactRefUri*/ "xxxxxxx")
- .append("\ncontactRingtoneUri: " + /*contactRefUri*/ "xxxxxxx")
- .append("\nshouldSendToVoicemail: " + shouldSendToVoicemail)
- .append("\ncachedPhoto: " + cachedPhoto)
- .append("\nisCachedPhotoCurrent: " + isCachedPhotoCurrent)
- .append("\nemergency: " + mIsEmergency)
- .append("\nvoicemail " + mIsVoiceMail)
- .append("\ncontactExists " + contactExists)
- .toString();
+ // Warning: never check in this file with VERBOSE_DEBUG = true
+ // because that will result in PII in the system log.
+ final boolean VERBOSE_DEBUG = false;
+
+ if (VERBOSE_DEBUG) {
+ return new StringBuilder(384)
+ .append("\nname: " + name)
+ .append("\nphoneNumber: " + phoneNumber)
+ .append("\ncnapName: " + cnapName)
+ .append("\nnumberPresentation: " + numberPresentation)
+ .append("\nnamePresentation: " + namePresentation)
+ .append("\ncontactExits: " + contactExists)
+ .append("\nphoneLabel: " + phoneLabel)
+ .append("\nnumberType: " + numberType)
+ .append("\nnumberLabel: " + numberLabel)
+ .append("\nphotoResource: " + photoResource)
+ .append("\nperson_id: " + person_id)
+ .append("\nneedUpdate: " + needUpdate)
+ .append("\ncontactRefUri: " + contactRefUri)
+ .append("\ncontactRingtoneUri: " + contactRefUri)
+ .append("\nshouldSendToVoicemail: " + shouldSendToVoicemail)
+ .append("\ncachedPhoto: " + cachedPhoto)
+ .append("\nisCachedPhotoCurrent: " + isCachedPhotoCurrent)
+ .append("\nemergency: " + mIsEmergency)
+ .append("\nvoicemail " + mIsVoiceMail)
+ .append("\ncontactExists " + contactExists)
+ .toString();
+ } else {
+ return new StringBuilder(128)
+ .append("CallerInfo { ")
+ .append("name " + ((name == null) ? "null" : "non-null"))
+ .append(", phoneNumber " + ((phoneNumber == null) ? "null" : "non-null"))
+ .append(" }")
+ .toString();
+ }
}
}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index 1f1338c..58a4cba 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -659,12 +659,6 @@
@Override
protected void onError(DisconnectCause cause) {
if (DEBUG) Log.d(LOG_TAG, "SIP error: " + cause);
- if (mSipAudioCall.isInCall()
- && (cause != DisconnectCause.LOST_SIGNAL)) {
- // Don't end the call when in a call.
- return;
- }
-
onCallEnded(cause);
}
};
diff --git a/tests/DumpRenderTree/AndroidManifest.xml b/tests/DumpRenderTree/AndroidManifest.xml
index c151251..dc44b25 100644
--- a/tests/DumpRenderTree/AndroidManifest.xml
+++ b/tests/DumpRenderTree/AndroidManifest.xml
@@ -25,7 +25,9 @@
<category android:name="android.intent.category.TEST" />
</intent-filter>
</activity>
- <activity android:name="TestShellActivity" android:launchMode="singleTop"
+ <activity android:name="TestShellActivity"
+ android:launchMode="singleTop"
+ android:hardwareAccelerated="true"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Light"/>
<activity android:name="ReliabilityTestActivity" android:screenOrientation="portrait"
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
index 0859976..8a07767 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
@@ -440,8 +440,13 @@
// draw the views
// create the BufferedImage into which the layout will be rendered.
- mImage = new BufferedImage(renderScreenWidth, renderScreenHeight - mScreenOffset,
- BufferedImage.TYPE_INT_ARGB);
+ if (mParams.getImageFactory() != null) {
+ mImage = mParams.getImageFactory().getImage(renderScreenWidth,
+ renderScreenHeight - mScreenOffset);
+ } else {
+ mImage = new BufferedImage(renderScreenWidth, renderScreenHeight - mScreenOffset,
+ BufferedImage.TYPE_INT_ARGB);
+ }
if (mParams.isCustomBackgroundEnabled()) {
Graphics2D gc = mImage.createGraphics();
@@ -482,7 +487,7 @@
// log it
mParams.getLogger().error(t);
- return new SceneResult("Unknown error during inflation.", t);
+ return new SceneResult("Unknown error during rendering.", t);
}
}
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index 2fbaee2..30ddfb5 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -527,11 +527,14 @@
}
public void answerCall(String sessionDescription, int timeout) {
- try {
- processCommand(new MakeCallCommand(mPeerProfile,
- sessionDescription, timeout));
- } catch (SipException e) {
- onError(e);
+ synchronized (SipSessionGroup.this) {
+ if (mPeerProfile == null) return;
+ try {
+ processCommand(new MakeCallCommand(mPeerProfile,
+ sessionDescription, timeout));
+ } catch (SipException e) {
+ onError(e);
+ }
}
}
@@ -540,14 +543,11 @@
}
public void changeCall(String sessionDescription, int timeout) {
- doCommandAsync(new MakeCallCommand(mPeerProfile, sessionDescription,
- timeout));
- }
-
- public void changeCallWithTimeout(
- String sessionDescription, int timeout) {
- doCommandAsync(new MakeCallCommand(mPeerProfile, sessionDescription,
- timeout));
+ synchronized (SipSessionGroup.this) {
+ if (mPeerProfile == null) return;
+ doCommandAsync(new MakeCallCommand(mPeerProfile,
+ sessionDescription, timeout));
+ }
}
public void register(int duration) {
@@ -1163,11 +1163,6 @@
mProxy.onCallEstablished(this, mPeerSessionDescription);
}
- private void fallbackToPreviousInCall(int errorCode, String message) {
- mState = SipSession.State.IN_CALL;
- mProxy.onCallChangeFailed(this, errorCode, message);
- }
-
private void endCallNormally() {
reset();
mProxy.onCallEnded(this);
@@ -1191,12 +1186,7 @@
onRegistrationFailed(errorCode, message);
break;
default:
- if ((errorCode != SipErrorCode.DATA_CONNECTION_LOST)
- && mInCall) {
- fallbackToPreviousInCall(errorCode, message);
- } else {
- endCallOnError(errorCode, message);
- }
+ endCallOnError(errorCode, message);
}
}