Merge "Test Aspect Ratio in Different Orientations" into ics-mr1
diff --git a/tests/tests/animation/src/android/animation/cts/AnimationActivity.java b/tests/tests/animation/src/android/animation/cts/AnimationActivity.java
index ee3202e..43679c8 100644
--- a/tests/tests/animation/src/android/animation/cts/AnimationActivity.java
+++ b/tests/tests/animation/src/android/animation/cts/AnimationActivity.java
@@ -58,7 +58,6 @@
float mDeltaY = 200f;
long mDuration = 1000;
public AnimationView view = null;
- private boolean isAnimationRunning = false;
@Override
public void onCreate(Bundle bundle){
@@ -92,12 +91,12 @@
}
public ValueAnimator createAnimatorWithRepeatMode(int repeatMode) {
- return createAnimator(view.newBall, "y", 1000,ValueAnimator.INFINITE, repeatMode,
+ return createAnimator(view.newBall, "y", 1000, ValueAnimator.INFINITE, repeatMode,
new AccelerateInterpolator(), mStartY, mStartY + mDeltaY);
}
public ValueAnimator createAnimatorWithRepeatCount(int repeatCount) {
- return createAnimator(view.newBall, "y", 1000,repeatCount, ValueAnimator.REVERSE,
+ return createAnimator(view.newBall, "y", 1000, repeatCount, ValueAnimator.REVERSE,
new AccelerateInterpolator(), mStartY, mStartY + mDeltaY);
}
@@ -106,46 +105,98 @@
ValueAnimator.REVERSE,new AccelerateInterpolator(), mStartY, mStartY + mDeltaY);
}
+ public ValueAnimator createAnimatorWithInterpolator(TimeInterpolator interpolator){
+ return createAnimator(view.newBall, "y", 1000, ValueAnimator.INFINITE, ValueAnimator.REVERSE,
+ interpolator, mStartY, mStartY + mDeltaY);
+ }
+
+ public ValueAnimator createObjectAnimatorForInt(Object object,String propertyName,
+ long duration, int repeatCount, int repeatMode, TimeInterpolator timeInterpolator,
+ int start, int end) {
+ ObjectAnimator objAnimator = ObjectAnimator.ofInt(object, propertyName, start,end);
+ objAnimator.setDuration(duration);
+
+ objAnimator.setRepeatCount(repeatCount);
+ objAnimator.setInterpolator(timeInterpolator);
+ objAnimator.setRepeatMode(repeatMode);
+ return objAnimator;
+ }
+
+ public ValueAnimator createObjectAnimatorForInt() {
+ ObjectAnimator objAnimator = ObjectAnimator.ofInt(view.newBall, "y", (int)mStartY,
+ (int)(mStartY + mDeltaY));
+ objAnimator.setDuration(mDuration);
+
+ objAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ objAnimator.setInterpolator(new AccelerateInterpolator());
+ objAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ return objAnimator;
+ }
+
public void startAnimation(long duration){
ValueAnimator bounceAnimator = ObjectAnimator.ofFloat(view.newBall, "y", mStartY,
- mStartY + mDeltaY);
+ mStartY + mDeltaY);
bounceAnimator.setDuration(duration);
bounceAnimator.setRepeatCount(ValueAnimator.INFINITE);
bounceAnimator.setInterpolator(new AccelerateInterpolator());
bounceAnimator.setRepeatMode(ValueAnimator.REVERSE);
view.bounceAnimator = bounceAnimator;
+ view.startColorAnimator();
view.animateBall();
}
public void startAnimation(ValueAnimator valueAnimator){
view.bounceAnimator = valueAnimator;
+ view.startColorAnimator();
view.animateBall();
- isAnimationRunning = true;
+ }
+
+ public void startAnimation(ObjectAnimator bounceAnimator) {
+ view.bounceAnimator = bounceAnimator;
+ view.startColorAnimator();
+ view.animateBall();
+ }
+
+ public void startAnimation(ObjectAnimator bounceAnimator, ObjectAnimator colorAnimator) {
+ view.bounceAnimator = bounceAnimator;
+ view.startColorAnimator(colorAnimator);
+ view.animateBall();
+ }
+
+ public void startColorAnimation(ValueAnimator colorAnimator){
+ view.startColorAnimator(colorAnimator);
}
public class AnimationView extends View {
- private static final int RED = 0xffFF8080;
- private static final int BLUE = 0xff8080FF;
+ public static final int RED = 0xffFF8080;
+ public static final int BLUE = 0xff8080FF;
public ShapeHolder newBall = null;
public final ArrayList<ShapeHolder> balls = new ArrayList<ShapeHolder>();
AnimatorSet animation = null;
public ValueAnimator bounceAnimator;
+ public ValueAnimator colorAnimator;
public AnimationView(Context context) {
super(context);
- ValueAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor", RED, BLUE);
- colorAnim.setDuration(1000);
- colorAnim.setEvaluator(new ArgbEvaluator());
- colorAnim.setRepeatCount(1);
- colorAnim.setRepeatMode(ValueAnimator.REVERSE);
- colorAnim.start();
newBall = addBall(mBallHeight, mBallWidth);
}
+ public void startColorAnimator() {
+ colorAnimator = ObjectAnimator.ofInt(this, "backgroundColor", RED, BLUE);
+ colorAnimator.setDuration(1000);
+ colorAnimator.setEvaluator(new ArgbEvaluator());
+ colorAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ colorAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ colorAnimator.start();
+ }
+
+ public void startColorAnimator(ValueAnimator animator) {
+ this.colorAnimator = animator;
+ colorAnimator.start();
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
-
-
return true;
}
@@ -203,4 +254,3 @@
}
}
}
-
diff --git a/tests/tests/animation/src/android/animation/cts/ArgbEvaluatorTest.java b/tests/tests/animation/src/android/animation/cts/ArgbEvaluatorTest.java
new file mode 100644
index 0000000..33c3716
--- /dev/null
+++ b/tests/tests/animation/src/android/animation/cts/ArgbEvaluatorTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.animation.cts;
+
+import android.animation.ArgbEvaluator;
+import android.graphics.Color;
+import android.test.InstrumentationTestCase;
+
+public class ArgbEvaluatorTest extends InstrumentationTestCase {
+ public void testEvaluate() throws Throwable {
+ final int RED = 0xffFF8080;
+ final int BLUE = 0xff8080FF;
+ int aRED = Color.alpha(RED);
+ int rRED = Color.red(RED);
+ int gRED = Color.green(RED);
+ int bRED = Color.blue(RED);
+ int aBLUE = Color.alpha(BLUE);
+ int rBLUE = Color.red(BLUE);
+ int gBLUE = Color.green(BLUE);
+ int bBLUE = Color.blue(BLUE);
+
+ final ArgbEvaluator evaluator = new ArgbEvaluator();
+ class AnimationRunnable implements Runnable{
+ int result;
+ public void run() {
+ result = (Integer) evaluator.evaluate(0.5f, RED, BLUE);
+ }
+ }
+ AnimationRunnable aRunnable = new AnimationRunnable();
+ this.runTestOnUiThread(aRunnable);
+ Thread.sleep(100);
+ int result = aRunnable.result;
+
+ int aResult = Color.alpha(result);
+ int rResult = Color.red(result);
+ int gResult = Color.green(result);
+ int bResult = Color.blue(result);
+ assertTrue(aResult >= aRED);
+ assertTrue(aResult <= aBLUE);
+ assertTrue(rResult <= rRED);
+ assertTrue(rResult >= rBLUE);
+ assertTrue(gResult >= gRED);
+ assertTrue(gResult <= gBLUE);
+ assertTrue(bResult >= bRED);
+ assertTrue(bResult <= bBLUE);
+ }
+}
+
diff --git a/tests/tests/animation/src/android/animation/cts/FloatEvaluatorTest.java b/tests/tests/animation/src/android/animation/cts/FloatEvaluatorTest.java
new file mode 100644
index 0000000..8cc1ffe
--- /dev/null
+++ b/tests/tests/animation/src/android/animation/cts/FloatEvaluatorTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.animation.cts;
+
+import android.animation.FloatEvaluator;
+import android.test.InstrumentationTestCase;
+
+public class FloatEvaluatorTest extends InstrumentationTestCase {
+ public void testEvaluate() {
+ float start = 0.0f;
+ float end = 1.0f;
+ float fraction = 0.5f;
+ FloatEvaluator floatEvaluator = new FloatEvaluator();
+ float result = floatEvaluator.evaluate(fraction, start, end);
+ assertTrue(result >= (fraction*start));
+ assertTrue(result <= (fraction*end));
+ }
+}
+
diff --git a/tests/tests/animation/src/android/animation/cts/IntEvaluatorTest.java b/tests/tests/animation/src/android/animation/cts/IntEvaluatorTest.java
new file mode 100644
index 0000000..11df20c
--- /dev/null
+++ b/tests/tests/animation/src/android/animation/cts/IntEvaluatorTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.animation.cts;
+
+import android.animation.IntEvaluator;
+import android.test.InstrumentationTestCase;
+
+public class IntEvaluatorTest extends InstrumentationTestCase {
+ public void testEvaluate() throws Throwable {
+ final int start = 0;
+ final int end = 100;
+ final float fraction = 0.5f;
+ final IntEvaluator intEvaluator = new IntEvaluator();
+ class AnimationRunnable implements Runnable{
+ int result;
+ public void run() {
+ result = intEvaluator.evaluate(fraction, start, end);
+ }
+ }
+ AnimationRunnable aRunnable = new AnimationRunnable();
+ this.runTestOnUiThread(aRunnable);
+ Thread.sleep(1);
+ int result = aRunnable.result;
+ assertTrue(result >= (fraction*start));
+ assertTrue(result <= (fraction*end));
+ }
+}
+
diff --git a/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java b/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java
new file mode 100644
index 0000000..be5c1d4
--- /dev/null
+++ b/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.animation.cts;
+
+import android.animation.ArgbEvaluator;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Property;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.Interpolator;
+
+public class ObjectAnimatorTest extends
+ ActivityInstrumentationTestCase2<AnimationActivity> {
+ private AnimationActivity mActivity;
+ private ObjectAnimator mObjectAnimator;
+ private long mDuration = 1000;
+
+ public ObjectAnimatorTest() {
+ super(AnimationActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ setActivityInitialTouchMode(false);
+ mActivity = getActivity();
+ mObjectAnimator = (ObjectAnimator) mActivity.createAnimatorWithDuration(mDuration);
+ }
+
+ public void testDuration() throws Throwable {
+ final long duration = 2000;
+ ObjectAnimator objectAnimatorLocal = (ObjectAnimator)mActivity.createAnimatorWithDuration(
+ duration);
+ startAnimation(objectAnimatorLocal);
+ assertEquals(duration, objectAnimatorLocal.getDuration());
+ }
+ public void testOfFloat() throws Throwable {
+ Object object = mActivity.view.newBall;
+ String property = "y";
+ float startY = mActivity.mStartY;
+ float endY = mActivity.mStartY + mActivity.mDeltaY;
+ ObjectAnimator objAnimator = ObjectAnimator.ofFloat(object, property, startY, endY);
+ assertTrue(objAnimator != null);
+ objAnimator.setDuration(mDuration);
+ objAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ objAnimator.setInterpolator(new AccelerateInterpolator());
+ objAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ startAnimation(objAnimator);
+ assertTrue(objAnimator != null);
+ Thread.sleep(100);
+ float x = mActivity.view.newBall.getX();
+ float y = mActivity.view.newBall.getY();
+ assertTrue( y >= startY);
+ assertTrue( y <= endY);
+ }
+
+ public void testOfFloatBase() throws Throwable {
+ Object object = mActivity.view.newBall;
+ String property = "y";
+ float startY = mActivity.mStartY;
+ float endY = mActivity.mStartY + mActivity.mDeltaY;
+ ObjectAnimator animator = ObjectAnimator.ofFloat(object, property, startY, endY);
+ ObjectAnimator objAnimator = new ObjectAnimator();
+ objAnimator.setTarget(object);
+ objAnimator.setPropertyName(property);
+ assertEquals(animator.getTarget(), objAnimator.getTarget());
+ assertEquals(animator.getPropertyName(), objAnimator.getPropertyName());
+ }
+
+ public void testOfInt() throws Throwable {
+ Object object = mActivity.view.newBall;
+ String property = "backgroundColor";
+ int startColor = mActivity.view.RED;
+ int endColor = mActivity.view.BLUE;
+
+ ObjectAnimator colorAnimator = ObjectAnimator.ofInt(object, property,
+ startColor, endColor);
+ colorAnimator.setDuration(1000);
+ colorAnimator.setEvaluator(new ArgbEvaluator());
+ colorAnimator.setRepeatCount(1);
+ colorAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ colorAnimator.start();
+ startAnimation(mObjectAnimator, colorAnimator);
+ Thread.sleep(100);
+ Integer i = (Integer) colorAnimator.getAnimatedValue();
+ //We are going from less negative value to a more negative value
+ assertTrue(i.intValue() <= startColor);
+ assertTrue(endColor <= i.intValue());
+ }
+
+ public void testOfObject() throws Throwable {
+ Object object = mActivity.view.newBall;
+ String property = "backgroundColor";
+ int startColor = mActivity.view.RED;
+ int endColor = mActivity.view.BLUE;
+ Object[] values = {new Integer(startColor), new Integer(endColor)};
+ ArgbEvaluator evaluator = new ArgbEvaluator();
+ ObjectAnimator colorAnimator = ObjectAnimator.ofObject(object, property,
+ evaluator, values);
+ colorAnimator.setDuration(1000);
+ colorAnimator.setRepeatCount(1);
+ colorAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ colorAnimator.start();
+ startAnimation(mObjectAnimator, colorAnimator);
+ Thread.sleep(100);
+ Integer i = (Integer) colorAnimator.getAnimatedValue();
+ //We are going from less negative value to a more negative value
+ assertTrue(i.intValue() <= startColor);
+ assertTrue(endColor <= i.intValue());
+ }
+
+ public void testOfPropertyValuesHolder() throws Throwable {
+ Object object = mActivity.view.newBall;
+ String propertyName = "backgroundColor";
+ int startColor = mActivity.view.RED;
+ int endColor = mActivity.view.BLUE;
+ int values[] = {startColor, endColor};
+ ArgbEvaluator evaluator = new ArgbEvaluator();
+ PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofInt(propertyName, values);
+ ObjectAnimator colorAnimator = ObjectAnimator.ofPropertyValuesHolder(object,
+ propertyValuesHolder);
+ colorAnimator.setDuration(1000);
+ colorAnimator.setRepeatCount(1);
+ colorAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ colorAnimator.start();
+ startAnimation(mObjectAnimator, colorAnimator);
+ Thread.sleep(100);
+ Integer i = (Integer) colorAnimator.getAnimatedValue();
+ //We are going from less negative value to a more negative value
+ assertTrue(i.intValue() <= startColor);
+ assertTrue(endColor <= i.intValue());
+ }
+
+ public void testGetPropertyName() throws Throwable {
+ Object object = mActivity.view.newBall;
+ String propertyName = "backgroundColor";
+ int startColor = mActivity.view.RED;
+ int endColor = mActivity.view.BLUE;
+ Object[] values = {new Integer(startColor), new Integer(endColor)};
+ ArgbEvaluator evaluator = new ArgbEvaluator();
+ ObjectAnimator colorAnimator = ObjectAnimator.ofObject(object, propertyName,
+ evaluator, values);
+ String actualPropertyName = colorAnimator.getPropertyName();
+ assertEquals(propertyName, actualPropertyName);
+ }
+
+ public void testSetCurrentPlayTime() throws Throwable {
+ Object object = mActivity.view.newBall;
+ String propertyName = "backgroundColor";
+ int startColor = mActivity.view.RED;
+ int endColor = mActivity.view.BLUE;
+ long playTime = 10000l;
+ Object[] values = {new Integer(startColor), new Integer(endColor)};
+ ArgbEvaluator evaluator = new ArgbEvaluator();
+ ObjectAnimator colorAnimator = ObjectAnimator.ofObject(object, propertyName,
+ evaluator, values);
+ colorAnimator.setCurrentPlayTime(playTime);
+ long actualPlayTime = colorAnimator.getCurrentPlayTime();
+ assertEquals(playTime, actualPlayTime);
+ }
+
+ public void testSetFloatValues() throws Throwable {
+ Object object = mActivity.view.newBall;
+ String property = "y";
+ float startY = mActivity.mStartY;
+ float endY = mActivity.mStartY + mActivity.mDeltaY;
+ float[] values = {startY, endY};
+ ObjectAnimator objAnimator = new ObjectAnimator();
+ objAnimator.setTarget(object);
+ objAnimator.setPropertyName(property);
+ objAnimator.setFloatValues(values);
+ objAnimator.setDuration(mDuration);
+ objAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ objAnimator.setInterpolator(new AccelerateInterpolator());
+ objAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ startAnimation(objAnimator);
+ Thread.sleep(100);
+ float y = mActivity.view.newBall.getY();
+ assertTrue( y >= startY);
+ assertTrue( y <= endY);
+ }
+
+ public void testGetTarget() throws Throwable {
+ Object object = mActivity.view.newBall;
+ String propertyName = "backgroundColor";
+ int startColor = mActivity.view.RED;
+ int endColor = mActivity.view.BLUE;
+ Object[] values = {new Integer(startColor), new Integer(endColor)};
+ ArgbEvaluator evaluator = new ArgbEvaluator();
+ ObjectAnimator colorAnimator = ObjectAnimator.ofObject(object, propertyName,
+ evaluator, values);
+ Object target = colorAnimator.getTarget();
+ assertEquals(object, target);
+ }
+
+ public void testClone() throws Throwable {
+ Object object = mActivity.view.newBall;
+ String property = "y";
+ float startY = mActivity.mStartY;
+ float endY = mActivity.mStartY + mActivity.mDeltaY;
+ Interpolator interpolator = new AccelerateInterpolator();
+ ObjectAnimator objAnimator = ObjectAnimator.ofFloat(object, property, startY, endY);
+ objAnimator.setDuration(mDuration);
+ objAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ objAnimator.setInterpolator(interpolator);
+ objAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ ObjectAnimator cloneAnimator = objAnimator.clone();
+
+ assertEquals(mDuration, cloneAnimator.getDuration());
+ assertEquals(ValueAnimator.INFINITE, cloneAnimator.getRepeatCount());
+ assertEquals(ValueAnimator.REVERSE, cloneAnimator.getRepeatMode());
+ assertEquals(object, cloneAnimator.getTarget());
+ assertEquals(property, cloneAnimator.getPropertyName());
+ assertEquals(interpolator, cloneAnimator.getInterpolator());
+ }
+
+ public void testIsStarted() throws Throwable {
+ Object object = mActivity.view.newBall;
+ String property = "y";
+ float startY = mActivity.mStartY;
+ float endY = mActivity.mStartY + mActivity.mDeltaY;
+ Interpolator interpolator = new AccelerateInterpolator();
+ ObjectAnimator objAnimator = ObjectAnimator.ofFloat(object, property, startY, endY);
+ objAnimator.setDuration(mDuration);
+ objAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ objAnimator.setInterpolator(interpolator);
+ objAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ startAnimation(objAnimator);
+ Thread.sleep(100);
+ assertTrue(objAnimator.isStarted());
+ Thread.sleep(100);
+ }
+
+ private void startAnimation(final ObjectAnimator mObjectAnimator) throws Throwable {
+ Thread mAnimationRunnable = new Thread() {
+ public void run() {
+ mActivity.startAnimation(mObjectAnimator);
+ }
+ };
+ this.runTestOnUiThread(mAnimationRunnable);
+ }
+ private void startAnimation(final ObjectAnimator mObjectAnimator, final
+ ObjectAnimator colorAnimator) throws Throwable {
+ Thread mAnimationRunnable = new Thread() {
+ public void run() {
+ mActivity.startAnimation(mObjectAnimator, colorAnimator);
+ }
+ };
+ this.runTestOnUiThread(mAnimationRunnable);
+ }
+}
+
+
diff --git a/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java b/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
index 314c06d..a7626bc 100644
--- a/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
@@ -15,24 +15,22 @@
*/
package android.animation.cts;
+import android.animation.ArgbEvaluator;
+import android.animation.FloatEvaluator;
+import android.animation.IntEvaluator;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
-import android.app.Instrumentation;
-import android.content.Intent;
import android.test.ActivityInstrumentationTestCase2;
+import android.view.animation.AccelerateInterpolator;
public class ValueAnimatorTest extends
ActivityInstrumentationTestCase2<AnimationActivity> {
private AnimationActivity mActivity;
- private Instrumentation mInstrumentation;
private ValueAnimator mValueAnimator;
- private long mDuration;
+ private long mDuration = 1000;
public ValueAnimatorTest() {
- super("com.android.cts.animation",AnimationActivity.class);
- }
-
- public ValueAnimatorTest(Class<AnimationActivity> activityClass) {
- super("com.android.cts.animation",AnimationActivity.class);
+ super(AnimationActivity.class);
}
@Override
@@ -57,6 +55,16 @@
assertTrue(valueAnimatorReturned.isRunning());
}
+ public void testIsStarted() throws Throwable {
+ assertFalse(mValueAnimator.isRunning());
+ assertFalse(mValueAnimator.isStarted());
+ long startDelay = 10000;
+ mValueAnimator.setStartDelay(startDelay);
+ startAnimation(mValueAnimator);
+ assertFalse(mValueAnimator.isRunning());
+ assertTrue(mValueAnimator.isStarted());
+ }
+
public void testRepeatMode() throws Throwable {
ValueAnimator mValueAnimator = mActivity.createAnimatorWithRepeatMode(ValueAnimator.RESTART);
startAnimation(mValueAnimator);
@@ -92,12 +100,164 @@
assertEquals(frameDelay, actualFrameDelay);
}
- private void startAnimation(final ValueAnimator mValueAnimator) throws Throwable {
+ public void testSetInterpolator() throws Throwable {
+ AccelerateInterpolator interpolator = new AccelerateInterpolator();
+ ValueAnimator mValueAnimator = mActivity.createAnimatorWithInterpolator(interpolator);
+ startAnimation(mValueAnimator);
+ assertTrue(interpolator.equals(mValueAnimator.getInterpolator()));
+ }
+
+ public void testCancel() throws Throwable {
+ startAnimation(mValueAnimator);
+ Thread.sleep(100);
+ mValueAnimator.cancel();
+ assertFalse(mValueAnimator.isRunning());
+ }
+
+ public void testEnd() throws Throwable {
+ Object object = mActivity.view.newBall;
+ String property = "y";
+ float startY = mActivity.mStartY;
+ float endY = mActivity.mStartY + mActivity.mDeltaY;
+ ObjectAnimator objAnimator = ObjectAnimator.ofFloat(object, property, startY, endY);
+ objAnimator.setDuration(mDuration);
+ objAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ objAnimator.setInterpolator(new AccelerateInterpolator());
+ objAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ startAnimation(objAnimator);
+ Thread.sleep(100);
+ endAnimation(objAnimator);
+ float y = mActivity.view.newBall.getY();
+ assertEquals(y, endY);
+ }
+
+ public void testGetAnimatedFraction() throws Throwable {
+ ValueAnimator objAnimator = getAnimator();
+ startAnimation(objAnimator);
+ assertNotNull(objAnimator);
+ float[] fractions = getValue(objAnimator, 10, "getAnimatedFraction()", 100l, null);
+ for(int j = 0; j < 9; j++){
+ assertTrue(fractions[j] >= 0.0);
+ assertTrue(fractions[j] <= 1.0);
+ assertTrue(fractions[j + 1] != fractions[j]);
+ }
+ }
+
+ public void testGetAnimatedValue() throws Throwable {
+ ValueAnimator objAnimator = getAnimator();
+ startAnimation(objAnimator);
+ assertNotNull(objAnimator);
+ float[] animatedValues = getValue(objAnimator, 10, "getAnimatedValue()", 100l, null);
+
+ for(int j = 0; j < 9; j++){
+ assertTrue(animatedValues[j + 1] != animatedValues[j]);
+ }
+ }
+ public void testGetAnimatedValue_PropertyName() throws Throwable {
+ String property = "y";
+
+ ValueAnimator objAnimator = getAnimator();
+ startAnimation(objAnimator);
+ assertNotNull(objAnimator);
+ float[] animatedValues = getValue(objAnimator, 10, "getAnimatedValue(property)", 100l,
+ property);
+ for(int j = 0; j < 9; j++){
+ assertTrue(animatedValues[j + 1] != animatedValues[j]);
+ }
+ }
+
+ public void testOfFloat() throws Throwable {
+ float start = 0.0f;
+ float end = 1.0f;
+ float[] values = {start, end};
+ final ValueAnimator valueAnimatorLocal = ValueAnimator.ofFloat(values);
+ valueAnimatorLocal.setDuration(mDuration);
+ valueAnimatorLocal.setRepeatCount(ValueAnimator.INFINITE);
+ valueAnimatorLocal.setInterpolator(new AccelerateInterpolator());
+ valueAnimatorLocal.setRepeatMode(ValueAnimator.RESTART);
+
this.runTestOnUiThread(new Runnable(){
- public void run(){
- mActivity.startAnimation(mValueAnimator);
+ public void run() {
+ valueAnimatorLocal.start();
}
});
+ Thread.sleep(100);
+ boolean isRunning = valueAnimatorLocal.isRunning();
+ assertTrue(isRunning);
+
+ Float animatedValue = (Float) valueAnimatorLocal.getAnimatedValue();
+ assertTrue(animatedValue >= start);
+ assertTrue(animatedValue <= end);
+ }
+
+ public void testOfInt() throws Throwable {
+ int start = 0;
+ int end = 10;
+ int[] values = {start, end};
+ final ValueAnimator valueAnimatorLocal = ValueAnimator.ofInt(values);
+ valueAnimatorLocal.setDuration(mDuration);
+ valueAnimatorLocal.setRepeatCount(ValueAnimator.INFINITE);
+ valueAnimatorLocal.setInterpolator(new AccelerateInterpolator());
+ valueAnimatorLocal.setRepeatMode(ValueAnimator.RESTART);
+
+ this.runTestOnUiThread(new Runnable(){
+ public void run() {
+ valueAnimatorLocal.start();
+ }
+ });
+ Thread.sleep(100);
+ boolean isRunning = valueAnimatorLocal.isRunning();
+ assertTrue(isRunning);
+
+ Integer animatedValue = (Integer) valueAnimatorLocal.getAnimatedValue();
+ assertTrue(animatedValue >= start);
+ assertTrue(animatedValue <= end);
+ }
+
+ private ValueAnimator getAnimator() {
+ Object object = mActivity.view.newBall;
+ String property = "y";
+ float startY = mActivity.mStartY;
+ float endY = mActivity.mStartY + mActivity.mDeltaY;
+ ValueAnimator objAnimator = ObjectAnimator.ofFloat(object, property, startY, endY);
+ objAnimator.setDuration(mDuration);
+ objAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ objAnimator.setInterpolator(new AccelerateInterpolator());
+ objAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ return objAnimator;
+ }
+
+ private float[] getValue(ValueAnimator animator, int n, String methodName,
+ long sleepTime, String property) throws InterruptedException {
+ float[] values = new float[n];
+ for(int i = 0; i < (n-1); i++){
+ Thread.sleep(sleepTime);
+ float value = 0.0f;
+ if(methodName.equals("getAnimatedFraction()")) {
+ value = animator.getAnimatedFraction();
+ }else if(methodName.equals("getAnimatedValue()")) {
+ value = ((Float)animator.getAnimatedValue()).floatValue();
+ }else if(methodName.equals("getAnimatedValue(property)")) {
+ value = ((Float)animator.getAnimatedValue(property)).floatValue();
+ }
+ values[i] = value;
+ }
+ return values;
+ }
+ private void startAnimation(final ValueAnimator mValueAnimator) throws Throwable {
+ this.runTestOnUiThread(new Runnable(){
+ public void run() {
+ mActivity.startAnimation(mValueAnimator);
+ }
+ });
+ }
+ private void endAnimation(final ValueAnimator mValueAnimator) throws Throwable {
+ Thread animationRunnable = new Thread() {
+ public void run() {
+ mValueAnimator.end();
+ }
+ };
+ this.runTestOnUiThread(animationRunnable);
}
}
diff --git a/tests/tests/os/src/android/os/cts/EnvironmentTest.java b/tests/tests/os/src/android/os/cts/EnvironmentTest.java
index 2081cba..711306e 100644
--- a/tests/tests/os/src/android/os/cts/EnvironmentTest.java
+++ b/tests/tests/os/src/android/os/cts/EnvironmentTest.java
@@ -70,4 +70,15 @@
assertTrue(Environment.getDownloadCacheDirectory().isDirectory());
assertTrue(Environment.getDataDirectory().isDirectory());
}
+
+ /**
+ * TMPDIR being set prevents apps from asking to have temporary files
+ * placed in their own storage, instead forcing their location to
+ * something OS-defined. If TMPDIR points to a global shared directory,
+ * this could compromise the security of the files.
+ */
+ public void testNoTmpDir() {
+ assertNull("environment variable TMPDIR should not be set",
+ System.getenv("TMPDIR"));
+ }
}
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index 2e3bbdb..c1defb3 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -212,12 +212,14 @@
"/data/data/com.htc.loggers/tmp",
"/data/data/com.htc.loggers/htcghost",
"/data/data/com.android.providers.drm/rights",
+ "/data/data/recovery",
"/data/dontpanic",
"/data/drm",
"/data/drm/rights",
"/data/dump",
"/data/htcfs",
"/data/local",
+ "/data/local/tmp",
"/data/local/tmp/com.nuance.android.vsuite.vsuiteapp",
"/data/log",
"/data/lost+found",
@@ -228,6 +230,7 @@
"/data/misc/wifi/sockets",
"/data/property",
"/data/secure",
+ "/data/sensors",
"/data/shared",
"/data/system",
"/data/wifi",
diff --git a/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java b/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
index b2bdfc8..a31e0c0 100644
--- a/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
+++ b/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
@@ -56,6 +56,12 @@
public static final String EXT_WEB_URL1 = "http://www.example.com/";
+ public static final String LOCAL_FILESYSTEM_URL = "file:///etc/hosts";
+
+ // Must match the title of the page at
+ // android/frameworks/base/core/res/res/raw/loaderror.html
+ public static final String WEBPAGE_NOT_AVAILABLE_TITLE = "Webpage not available";
+
public static final String getFileUrl(String assetName) {
if (assetName.contains(":") || assetName.startsWith("/")) {
throw new IllegalArgumentException();
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index 639f795..05e668b 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -214,7 +214,6 @@
args = {boolean.class}
)
})
- @ToBeFixed(explanation = "Cannot block file access using setAllowFileAccess(false)")
public void testAccessAllowFileAccess() {
assertTrue(mSettings.getAllowFileAccess());
@@ -225,11 +224,15 @@
fileUrl = TestHtmlConstants.getFileUrl(TestHtmlConstants.BR_TAG_URL);
mSettings.setAllowFileAccess(false);
assertFalse(mSettings.getAllowFileAccess());
+
loadUrl(fileUrl);
- // direct file:// access still works with access disabled
+ // android_asset URLs should still be loaded when even with file access
+ // disabled.
assertEquals(TestHtmlConstants.BR_TAG_TITLE, mWebView.getTitle());
- // ToBeFixed: How does this API prevent file access?
+ // Files on the file system should not be loaded.
+ loadUrl(TestHtmlConstants.LOCAL_FILESYSTEM_URL);
+ assertEquals(TestHtmlConstants.WEBPAGE_NOT_AVAILABLE_TITLE, mWebView.getTitle());
}
@TestTargets({
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
index 855c209..686c90a 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
@@ -84,6 +84,9 @@
@Option(name = "quiet-output", description = "Mute display of test results.")
private boolean mQuietOutput = false;
+ @Option(name = "result-server", description = "Server to publish test results.")
+ private String mResultServer;
+
protected IBuildInfo mBuildInfo;
private String mStartTime;
private String mDeviceSerial;
@@ -254,9 +257,18 @@
CLog.w("Unable to create XML report");
return;
}
- createXmlResult(mReportDir, mStartTime, elapsedTime);
+
+ File reportFile = getResultFile(mReportDir);
+ createXmlResult(reportFile, mStartTime, elapsedTime);
copyFormattingFiles(mReportDir);
zipResults(mReportDir);
+
+ try {
+ ResultReporter reporter = new ResultReporter(mResultServer, reportFile);
+ reporter.reportResult();
+ } catch (IOException e) {
+ CLog.e(e);
+ }
}
private void logResult(String format, Object... args) {
@@ -281,12 +293,11 @@
/**
* Creates a report file and populates it with the report data from the completed tests.
*/
- private void createXmlResult(File reportDir, String startTimestamp, long elapsedTime) {
+ private void createXmlResult(File reportFile, String startTimestamp, long elapsedTime) {
String endTime = getTimestamp();
-
OutputStream stream = null;
try {
- stream = createOutputResultStream(reportDir);
+ stream = createOutputResultStream(reportFile);
KXmlSerializer serializer = new KXmlSerializer();
serializer.setOutput(stream, "UTF-8");
serializer.startDocument("UTF-8", false);
@@ -331,11 +342,14 @@
//serializer.endTag(ns, RESULT_TAG);
}
+ private File getResultFile(File reportDir) {
+ return new File(reportDir, TEST_RESULT_FILE_NAME);
+ }
+
/**
* Creates the output stream to use for test results. Exposed for mocking.
*/
- OutputStream createOutputResultStream(File reportDir) throws IOException {
- File reportFile = new File(reportDir, TEST_RESULT_FILE_NAME);
+ OutputStream createOutputResultStream(File reportFile) throws IOException {
logResult("Created xml report file at file://%s", reportFile.getAbsolutePath());
return new FileOutputStream(reportFile);
}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/IssueReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/IssueReporter.java
index 8ee9c0f..9d903dd 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/IssueReporter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/IssueReporter.java
@@ -28,11 +28,6 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.net.HttpURLConnection;
-import java.net.URL;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
@@ -46,7 +41,6 @@
*/
public class IssueReporter implements ITestInvocationListener {
- private static final String FORM_DATA_BOUNDARY = "C75I55u3R3p0r73r";
private static final int BUGREPORT_SIZE = 500 * 1024;
private static final String PRODUCT_NAME_KEY = "buildName";
@@ -87,22 +81,42 @@
*/
private void setBugReport(InputStreamSource dataStream) throws IOException {
if (mCurrentIssue != null) {
- InputStream input = dataStream.createInputStream();
- ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(BUGREPORT_SIZE);
- GZIPOutputStream gzipOutput = new GZIPOutputStream(byteOutput);
- for (byte[] buffer = new byte[1024]; input.read(buffer) >= 0; ) {
- gzipOutput.write(buffer);
- }
- gzipOutput.close();
-
// Only one bug report can be stored at a time and they are gzipped to
// about 0.5 MB so there shoudn't be any memory leak bringing down CTS.
- mCurrentIssue.mBugReport = byteOutput.toByteArray();
+ InputStream input = null;
+ try {
+ input = dataStream.createInputStream();
+ mCurrentIssue.mBugReport = getBytes(input, BUGREPORT_SIZE);
+ } finally {
+ if (input != null) {
+ input.close();
+ }
+ }
} else {
CLog.e("setBugReport is getting called on an empty issue...");
}
}
+ /**
+ * @param input that will be gzipped and returne as a byte array
+ * @param size of the output expected
+ * @return the byte array with the input's data
+ * @throws IOException
+ */
+ static byte[] getBytes(InputStream input, int size) throws IOException {
+ ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(size);
+ GZIPOutputStream gzipOutput = new GZIPOutputStream(byteOutput);
+ for (byte[] buffer = new byte[1024]; ; ) {
+ int numRead = input.read(buffer);
+ if (numRead < 0) {
+ break;
+ }
+ gzipOutput.write(buffer, 0, numRead);
+ }
+ gzipOutput.close();
+ return byteOutput.toByteArray();
+ }
+
@Override
public void testEnded(TestIdentifier test, Map<String, String> testMetrics) {
if (mCurrentIssue != null) {
@@ -158,32 +172,14 @@
return null;
}
- HttpURLConnection connection = null;
-
- try {
- URL url = new URL(mServerUrl);
- connection = (HttpURLConnection) url.openConnection();
- connection.setRequestMethod("POST");
- connection.setDoOutput(true);
- connection.setRequestProperty("Content-Type",
- "multipart/form-data; boundary=" + FORM_DATA_BOUNDARY);
-
- byte[] body = getContentBody();
- connection.setRequestProperty("Content-Length", Integer.toString(body.length));
-
- OutputStream output = connection.getOutputStream();
- output.write(body);
- output.close();
-
- // Open the stream to get a response. Otherwise request will be cancelled.
- InputStream input = connection.getInputStream();
- input.close();
-
- } finally {
- if (connection != null) {
- connection.disconnect();
- }
- }
+ new MultipartForm(mServerUrl)
+ .addFormValue("productName", mProductName)
+ .addFormValue("buildType", mBuildType)
+ .addFormValue("buildId", mBuildId)
+ .addFormValue("testName", mTestName)
+ .addFormValue("stackTrace", mStackTrace)
+ .addFormFile("bugReport", "bugreport.txt.gz", mBugReport)
+ .submit();
return null;
}
@@ -191,43 +187,6 @@
private boolean isEmpty(String value) {
return value == null || value.trim().isEmpty();
}
-
- private byte[] getContentBody() throws IOException {
- ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
- PrintWriter writer = new PrintWriter(new OutputStreamWriter(byteOutput));
- writer.println();
- writeFormField(writer, "productName", mProductName);
- writeFormField(writer, "buildType", mBuildType);
- writeFormField(writer, "buildId", mBuildId);
- writeFormField(writer, "testName", mTestName);
- writeFormField(writer, "stackTrace", mStackTrace);
- if (mBugReport != null) {
- writeFormFileHeader(writer, "bugReport", "bugReport.txt.gz");
- writer.flush(); // Must flush here before writing to the byte stream!
- byteOutput.write(mBugReport);
- writer.println();
- }
- writer.append("--").append(FORM_DATA_BOUNDARY).println("--");
- writer.flush();
- writer.close();
- return byteOutput.toByteArray();
- }
-
- private void writeFormField(PrintWriter writer, String name, String value) {
- writer.append("--").println(FORM_DATA_BOUNDARY);
- writer.append("Content-Disposition: form-data; name=\"").append(name).println("\"");
- writer.println();
- writer.println(value);
- }
-
- private void writeFormFileHeader(PrintWriter writer, String name, String fileName) {
- writer.append("--").println(FORM_DATA_BOUNDARY);
- writer.append("Content-Disposition: form-data; name=\"").append(name);
- writer.append("\"; filename=\"").append(fileName).println("\"");
- writer.println("Content-Type: application/x-gzip");
- writer.println("Content-Transfer-Encoding: binary");
- writer.println();
- }
}
@Override
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/MultipartForm.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/MultipartForm.java
new file mode 100644
index 0000000..f3ef0bb
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/MultipartForm.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.tradefed.result;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+/** MultipartForm builds a multipart form and submits it. */
+class MultipartForm {
+
+ private static final String FORM_DATA_BOUNDARY = "C75I55u3R3p0r73r";
+
+ private final String mServerUrl;
+
+ private final Map<String, String> mFormValues = new HashMap<String, String>();
+
+ private String mName;
+ private String mFileName;
+ private byte[] mData;
+
+ public MultipartForm(String serverUrl) {
+ mServerUrl = serverUrl;
+ }
+
+ public MultipartForm addFormValue(String name, String value) {
+ mFormValues.put(name, value);
+ return this;
+ }
+
+ public MultipartForm addFormFile(String name, String fileName, byte[] data) {
+ mName = name;
+ mFileName = fileName;
+ mData = data;
+ return this;
+ }
+
+ public void submit() throws IOException {
+ String redirectUrl = submitForm(mServerUrl);
+ if (redirectUrl != null) {
+ submitForm(redirectUrl);
+ }
+ }
+
+ /**
+ * @param serverUrl to post the data to
+ * @return a url if the server redirected to another url
+ * @throws IOException
+ */
+ private String submitForm(String serverUrl) throws IOException {
+ HttpURLConnection connection = null;
+ try {
+ URL url = new URL(serverUrl);
+ connection = (HttpURLConnection) url.openConnection();
+ connection.setInstanceFollowRedirects(false);
+ connection.setRequestMethod("POST");
+ connection.setDoOutput(true);
+ connection.setRequestProperty("Content-Type",
+ "multipart/form-data; boundary=" + FORM_DATA_BOUNDARY);
+
+ byte[] body = getContentBody();
+ connection.setRequestProperty("Content-Length", Integer.toString(body.length));
+
+ OutputStream output = connection.getOutputStream();
+ try {
+ output.write(body);
+ } finally {
+ output.close();
+ }
+
+ // Open the stream to get a response. Otherwise request will be cancelled.
+ InputStream input = connection.getInputStream();
+ input.close();
+
+ if (connection.getResponseCode() == 302) {
+ return connection.getHeaderField("Location");
+ }
+ } finally {
+ if (connection != null) {
+ connection.disconnect();
+ }
+ }
+
+ return null;
+ }
+
+ private byte[] getContentBody() throws IOException {
+ ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
+ PrintWriter writer = new PrintWriter(new OutputStreamWriter(byteOutput));
+ writer.println();
+
+ for (Map.Entry<String, String> formValue : mFormValues.entrySet()) {
+ writeFormField(writer, formValue.getKey(), formValue.getValue());
+ }
+
+ if (mData != null) {
+ writeFormFileHeader(writer, mName, mFileName);
+ writer.flush(); // Must flush here before writing to the byte stream!
+ byteOutput.write(mData);
+ writer.println();
+ }
+ writer.append("--").append(FORM_DATA_BOUNDARY).println("--");
+ writer.flush();
+ writer.close();
+ return byteOutput.toByteArray();
+ }
+
+ private void writeFormField(PrintWriter writer, String name, String value) {
+ writer.append("--").println(FORM_DATA_BOUNDARY);
+ writer.append("Content-Disposition: form-data; name=\"").append(name).println("\"");
+ writer.println();
+ writer.println(value);
+ }
+
+ private void writeFormFileHeader(PrintWriter writer, String name, String fileName) {
+ writer.append("--").println(FORM_DATA_BOUNDARY);
+ writer.append("Content-Disposition: form-data; name=\"").append(name);
+ writer.append("\"; filename=\"").append(fileName).println("\"");
+ writer.println("Content-Type: application/x-gzip");
+ writer.println("Content-Transfer-Encoding: binary");
+ writer.println();
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/ResultReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/ResultReporter.java
new file mode 100644
index 0000000..05192c9
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/ResultReporter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.tradefed.result;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Class that sends a HTTP POST multipart/form-data request containing
+ * the test result XML.
+ */
+class ResultReporter {
+
+ private static final int RESULT_XML_BYTES = 500 * 1024;
+
+ private final String mServerUrl;
+
+ private final File mReportFile;
+
+ ResultReporter(String serverUrl, File reportFile) {
+ mServerUrl = serverUrl;
+ mReportFile = reportFile;
+ }
+
+ public void reportResult() throws IOException {
+ if (isEmpty(mServerUrl)) {
+ return;
+ }
+
+ InputStream input = new FileInputStream(mReportFile);
+ try {
+ byte[] data = IssueReporter.getBytes(input, RESULT_XML_BYTES);
+ new MultipartForm(mServerUrl)
+ .addFormFile("resultXml", "testResult.xml.gz", data)
+ .submit();
+ } finally {
+ input.close();
+ }
+ }
+
+ private boolean isEmpty(String value) {
+ return value == null || value.trim().isEmpty();
+ }
+}