This adds an Android apk for running tests on  the Java layer of PeerConnection.

The only testcase is currently the same test we run on Java standalone.
To run the test adb shell am instrument -w org.webrtc.test/android.test.InstrumentationTestRunner

R=kjellander@webrtc.org, phoglund@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/26219004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@7732 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/app/webrtc/androidtests/AndroidManifest.xml b/talk/app/webrtc/androidtests/AndroidManifest.xml
new file mode 100644
index 0000000..3bcd99b
--- /dev/null
+++ b/talk/app/webrtc/androidtests/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.webrtc.test"
+    android:versionCode="1"
+    android:versionName="1.0" >
+    <uses-feature android:name="android.hardware.camera" />
+    <uses-feature android:name="android.hardware.camera.autofocus" />
+    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
+
+    <uses-sdk android:minSdkVersion="13" android:targetSdkVersion="21" />
+
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+    <instrumentation
+        android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="org.webrtc.test" />
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name" >
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+</manifest>
diff --git a/talk/app/webrtc/androidtests/ant.properties b/talk/app/webrtc/androidtests/ant.properties
new file mode 100644
index 0000000..bc05353
--- /dev/null
+++ b/talk/app/webrtc/androidtests/ant.properties
@@ -0,0 +1,18 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked into Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+#  'source.dir' for the location of your java source folder and
+#  'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+#  'key.store' for the location of your keystore and
+#  'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
+source.dir=../java/testcommon/src;src
\ No newline at end of file
diff --git a/talk/app/webrtc/androidtests/build.xml b/talk/app/webrtc/androidtests/build.xml
new file mode 100644
index 0000000..cb4cb7a
--- /dev/null
+++ b/talk/app/webrtc/androidtests/build.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="libjingle_peerconnection_android_unittest" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties" />
+
+    <!-- if sdk.dir was not set from one of the property file, then
+         get it from the ANDROID_HOME env var.
+         This must be done before we load project.properties since
+         the proguard config can use sdk.dir -->
+    <property environment="env" />
+    <condition property="sdk.dir" value="${env.ANDROID_SDK_ROOT}">
+        <isset property="env.ANDROID_SDK_ROOT" />
+    </condition>
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties" />
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
+            unless="sdk.dir"
+    />
+
+    <!--
+        Import per project custom build rules if present at the root of the project.
+        This is the place to put custom intermediary targets such as:
+            -pre-build
+            -pre-compile
+            -post-compile (This is typically used for code obfuscation.
+                           Compiled code location: ${out.classes.absolute.dir}
+                           If this is not done in place, override ${out.dex.input.absolute.dir})
+            -post-package
+            -post-build
+            -pre-clean
+    -->
+    <import file="custom_rules.xml" optional="true" />
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: 1 -->
+    <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>
diff --git a/talk/app/webrtc/androidtests/jni/Android.mk b/talk/app/webrtc/androidtests/jni/Android.mk
new file mode 100644
index 0000000..8e80160
--- /dev/null
+++ b/talk/app/webrtc/androidtests/jni/Android.mk
@@ -0,0 +1,2 @@
+# This space intentionally left blank (required for Android build system).
+
diff --git a/talk/app/webrtc/androidtests/project.properties b/talk/app/webrtc/androidtests/project.properties
new file mode 100644
index 0000000..47b7078
--- /dev/null
+++ b/talk/app/webrtc/androidtests/project.properties
@@ -0,0 +1,16 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-21
+
+java.compilerargs=-Xlint:all -Werror
diff --git a/talk/app/webrtc/androidtests/res/drawable-hdpi/ic_launcher.png b/talk/app/webrtc/androidtests/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..96a442e
--- /dev/null
+++ b/talk/app/webrtc/androidtests/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/talk/app/webrtc/androidtests/res/drawable-ldpi/ic_launcher.png b/talk/app/webrtc/androidtests/res/drawable-ldpi/ic_launcher.png
new file mode 100644
index 0000000..9923872
--- /dev/null
+++ b/talk/app/webrtc/androidtests/res/drawable-ldpi/ic_launcher.png
Binary files differ
diff --git a/talk/app/webrtc/androidtests/res/drawable-mdpi/ic_launcher.png b/talk/app/webrtc/androidtests/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..359047d
--- /dev/null
+++ b/talk/app/webrtc/androidtests/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/talk/app/webrtc/androidtests/res/drawable-xhdpi/ic_launcher.png b/talk/app/webrtc/androidtests/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71c6d76
--- /dev/null
+++ b/talk/app/webrtc/androidtests/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/talk/app/webrtc/androidtests/res/values/strings.xml b/talk/app/webrtc/androidtests/res/values/strings.xml
new file mode 100644
index 0000000..dfe63f8
--- /dev/null
+++ b/talk/app/webrtc/androidtests/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="app_name">AndroidPeerConnectionTests</string>
+
+</resources>
diff --git a/talk/app/webrtc/androidtests/src/org/webrtc/PeerConnectionAndroidTest.java b/talk/app/webrtc/androidtests/src/org/webrtc/PeerConnectionAndroidTest.java
new file mode 100644
index 0000000..228d35c
--- /dev/null
+++ b/talk/app/webrtc/androidtests/src/org/webrtc/PeerConnectionAndroidTest.java
@@ -0,0 +1,49 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.webrtc;
+
+import android.test.ActivityTestCase;
+
+public class PeerConnectionAndroidTest extends ActivityTestCase {
+  private PeerConnectionTest test = new PeerConnectionTest();
+
+  @Override
+  protected void setUp() {
+    assertTrue(PeerConnectionFactory.initializeAndroidGlobals(
+        getInstrumentation().getContext(), true,
+        true, null));
+  }
+
+  public void testCompleteSession() throws Exception {
+    // TODO(perkj): Investigate if |test.initializeThreadCheck()| can be used
+    // on android as well. Currently this check fail.
+    test.doTest();
+  }
+
+
+}
diff --git a/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java b/talk/app/webrtc/java/testcommon/src/org/webrtc/PeerConnectionTest.java
similarity index 94%
rename from talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java
rename to talk/app/webrtc/java/testcommon/src/org/webrtc/PeerConnectionTest.java
index 048d92b..8d962cc 100644
--- a/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java
+++ b/talk/app/webrtc/java/testcommon/src/org/webrtc/PeerConnectionTest.java
@@ -27,9 +27,6 @@
 
 package org.webrtc;
 
-import junit.framework.TestCase;
-
-import org.junit.Test;
 import org.webrtc.PeerConnection.IceConnectionState;
 import org.webrtc.PeerConnection.IceGatheringState;
 import org.webrtc.PeerConnection.SignalingState;
@@ -39,7 +36,6 @@
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
 import java.util.Arrays;
-import java.util.EnumSet;
 import java.util.IdentityHashMap;
 import java.util.LinkedList;
 import java.util.Map;
@@ -47,15 +43,18 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import static junit.framework.Assert.*;
+
 /** End-to-end tests for PeerConnection.java. */
-public class PeerConnectionTest extends TestCase {
+public class PeerConnectionTest {
   // Set to true to render video.
   private static final boolean RENDER_TO_GUI = false;
+  private TreeSet<String> threadsBeforeTest = null;
 
   private static class ObserverExpectations implements PeerConnection.Observer,
-                                            VideoRenderer.Callbacks,
-                                            DataChannel.Observer,
-                                            StatsObserver {
+                                                       VideoRenderer.Callbacks,
+                                                       DataChannel.Observer,
+                                                       StatsObserver {
     private final String name;
     private int expectedIceCandidates = 0;
     private int expectedErrors = 0;
@@ -113,10 +112,6 @@
       gotIceCandidates.add(candidate);
     }
 
-    public synchronized void expectError() {
-      ++expectedErrors;
-    }
-
     public synchronized void expectSetSize() {
       if (RENDER_TO_GUI) {
         // When new frames are delivered to the GUI renderer we don't get
@@ -440,6 +435,7 @@
     public int height = -1;
     public int numFramesDelivered = 0;
 
+    @Override
     public void setSize(int width, int height) {
       assertEquals(this.width, -1);
       assertEquals(this.height, -1);
@@ -447,6 +443,7 @@
       this.height = height;
     }
 
+    @Override
     public void renderFrame(VideoRenderer.I420Frame frame) {
       ++numFramesDelivered;
     }
@@ -488,40 +485,21 @@
     return new WeakReference<MediaStream>(lMS);
   }
 
-  private static void assertEquals(
-      SessionDescription lhs, SessionDescription rhs) {
-    assertEquals(lhs.type, rhs.type);
-    assertEquals(lhs.description, rhs.description);
-  }
-
-  @Test
-  public void testCompleteSession() throws Exception {
-    doTest();
-  }
-
-  @Test
-  public void testCompleteSessionOnNonMainThread() throws Exception {
-    final Exception[] exceptionHolder = new Exception[1];
-    Thread nonMainThread = new Thread("PeerConnectionTest-nonMainThread") {
-        @Override public void run() {
-          try {
-            doTest();
-          } catch (Exception e) {
-            exceptionHolder[0] = e;
-          }
-        }
-      };
-    nonMainThread.start();
-    nonMainThread.join();
-    if (exceptionHolder[0] != null)
-      throw exceptionHolder[0];
-  }
-
-  private void doTest() throws Exception {
-    CountDownLatch testDone = new CountDownLatch(1);
+  // Used for making sure thread handles are not leaked.
+  // Call initializeThreadCheck before a test and finalizeThreadCheck after
+  // a test.
+  void initializeThreadCheck() {
     System.gc();  // Encourage any GC-related threads to start up.
-    TreeSet<String> threadsBeforeTest = allThreads();
+    threadsBeforeTest = allThreads();
+  }
 
+  void finalizeThreadCheck() throws Exception {
+    TreeSet<String> threadsAfterTest = allThreads();
+    assertEquals(threadsBeforeTest, threadsAfterTest);
+    Thread.sleep(100);
+  }
+
+  void doTest() throws Exception {
     PeerConnectionFactory factory = new PeerConnectionFactory();
     // Uncomment to get ALL WebRTC tracing and SENSITIVE libjingle logging.
     // NOTE: this _must_ happen while |factory| is alive!
@@ -736,10 +714,6 @@
     videoSource.dispose();
     factory.dispose();
     System.gc();
-
-    TreeSet<String> threadsAfterTest = allThreads();
-    assertEquals(threadsBeforeTest, threadsAfterTest);
-    Thread.sleep(100);
   }
 
   private static void shutdownPC(
@@ -782,16 +756,4 @@
     }
     return threads;
   }
-
-  // Return a String form of |strings| joined by |separator|.
-  private static String joinStrings(String separator, TreeSet<String> strings) {
-    StringBuilder builder = new StringBuilder();
-    for (String s : strings) {
-      if (builder.length() > 0) {
-        builder.append(separator);
-      }
-      builder.append(s);
-    }
-    return builder.toString();
-  }
 }
diff --git a/talk/app/webrtc/javatests/libjingle_peerconnection_java_unittest.sh b/talk/app/webrtc/javatests/libjingle_peerconnection_java_unittest.sh
index 0ecb730..4f8c74a 100644
--- a/talk/app/webrtc/javatests/libjingle_peerconnection_java_unittest.sh
+++ b/talk/app/webrtc/javatests/libjingle_peerconnection_java_unittest.sh
@@ -44,4 +44,4 @@
 export JAVA_HOME=GYP_JAVA_HOME
 
 ${JAVA_HOME}/bin/java -Xcheck:jni -classpath $CLASSPATH \
-    junit.textui.TestRunner org.webrtc.PeerConnectionTest
+    junit.textui.TestRunner org.webrtc.PeerConnectionTestJava
diff --git a/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTestJava.java b/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTestJava.java
new file mode 100644
index 0000000..2f0419c
--- /dev/null
+++ b/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTestJava.java
@@ -0,0 +1,62 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.webrtc;
+
+
+import junit.framework.TestCase;
+
+/** End-to-end tests for PeerConnection.java. */
+public class PeerConnectionTestJava extends TestCase {
+  private PeerConnectionTest test = new PeerConnectionTest();
+  @Test
+  public void testCompleteSession() throws Exception {
+    test.initializeThreadCheck();
+    test.doTest();
+    test.finalizeThreadCheck();
+  }
+
+  @Test
+  public void testCompleteSessionOnNonMainThread() throws Exception {
+    final Exception[] exceptionHolder = new Exception[1];
+    Thread nonMainThread = new Thread("PeerConnectionTest-nonMainThread") {
+        @Override public void run() {
+          try {
+            test.initializeThreadCheck();
+            test.doTest();
+            test.finalizeThreadCheck();
+          } catch (Exception e) {
+            exceptionHolder[0] = e;
+          }
+        }
+      };
+    nonMainThread.start();
+    nonMainThread.join();
+    if (exceptionHolder[0] != null)
+      throw exceptionHolder[0];
+  }
+}
\ No newline at end of file
diff --git a/talk/libjingle_tests.gyp b/talk/libjingle_tests.gyp
index 128203b..d853236 100755
--- a/talk/libjingle_tests.gyp
+++ b/talk/libjingle_tests.gyp
@@ -263,7 +263,8 @@
               'variables': {
                 'java_src_dir': 'app/webrtc/javatests/src',
                 'java_files': [
-                  'app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java',
+                  'app/webrtc/java/testcommon/src/org/webrtc/PeerConnectionTest.java',
+                  'app/webrtc/javatests/src/org/webrtc/PeerConnectionTestJava.java',
                 ],
               },
               'action_name': 'create_jar',
@@ -313,6 +314,61 @@
         },
       ],
     }],
+    ['OS=="android"', {
+      'targets': [
+        {
+          'target_name': 'libjingle_peerconnection_android_unittest',
+          'type': 'none',
+          'dependencies': [
+            'libjingle.gyp:libjingle_peerconnection_jar',
+          ],
+          'actions': [
+            {
+              # TODO(perkj): convert from a custom script to a standard gyp
+              # apk build once chromium's apk-building gyp machinery can be used
+              # (http://crbug.com/225101)
+              'action_name': 'build_peerconnection_unittests_apk',
+              'inputs' : [
+                '<(PRODUCT_DIR)/libjingle_peerconnection.jar',
+                '<(PRODUCT_DIR)/libjingle_peerconnection_so.so',
+                'app/webrtc/androidtests/AndroidManifest.xml',
+                'app/webrtc/androidtests/ant.properties',
+                'app/webrtc/androidtests/build.xml',
+                'app/webrtc/androidtests/jni/Android.mk',
+                'app/webrtc/androidtests/project.properties',
+                'app/webrtc/androidtests/res/drawable-hdpi/ic_launcher.png',
+                'app/webrtc/androidtests/res/drawable-ldpi/ic_launcher.png',
+                'app/webrtc/androidtests/res/drawable-mdpi/ic_launcher.png',
+                'app/webrtc/androidtests/res/drawable-xhdpi/ic_launcher.png',
+                'app/webrtc/androidtests/res/values/strings.xml',
+                'app/webrtc/androidtests/src/org/webrtc/PeerConnectionAndroidTest.java',
+                'app/webrtc/java/testcommon/src/org/webrtc/PeerConnectionTest.java',
+              ],
+              'outputs': [
+                '<(PRODUCT_DIR)/libjingle_peerconnection_android_unittest.apk',
+              ],
+              'variables': {
+                'ant_log': '../../../<(INTERMEDIATE_DIR)/ant.log', # ../.. to compensate for the cd app/webrtc/androidtests below.
+              },
+              'action': [
+                'bash', '-ec',
+                'rm -fr <(_outputs) app/webrtc/androidtests/{bin,libs} && '
+                'mkdir -p <(INTERMEDIATE_DIR) && ' # Must happen _before_ the cd below
+                'mkdir -p app/webrtc/androidtests/libs/<(android_app_abi) && '
+                'cp <(PRODUCT_DIR)/libjingle_peerconnection.jar app/webrtc/androidtests/libs/ &&'
+                '<(android_strip) -o app/webrtc/androidtests/libs/<(android_app_abi)/libjingle_peerconnection_so.so  <(PRODUCT_DIR)/libjingle_peerconnection_so.so &&'
+                'cd app/webrtc/androidtests && '
+                '{ ANDROID_SDK_ROOT=<(android_sdk_root) '
+                'ant debug > <(ant_log) 2>&1 || '
+                '  { cat <(ant_log) ; exit 1; } } && '
+                'cd - > /dev/null && '
+                'cp app/webrtc/androidtests/bin/libjingle_peerconnection_android_unittest-debug.apk <(_outputs)'
+              ],
+            },
+          ],
+        },  # target AppRTCDemo
+      ],  # targets
+    }],  # OS=="android"
     ['OS=="ios" or (OS=="mac" and target_arch!="ia32" and mac_sdk>="10.7")', {
       # The >=10.7 above is required to make ARC link cleanly (e.g. as
       # opposed to _compile_ cleanly, which the library under test