summaryrefslogtreecommitdiff
path: root/console_test_server
diff options
context:
space:
mode:
authorJingjing Liu <jingjingliu@google.com>2016-11-08 10:55:03 -0800
committerJingjing Liu <jingjingliu@google.com>2016-11-08 11:25:08 -0800
commit0dd4be439821d5925358fbf3e4d456a318eb3df4 (patch)
tree8a3f277299cf372a0ea88091b2c7aa4c88c2132a /console_test_server
parent1d13eb735d77b17c84f69d86d637a8ec635310c4 (diff)
downloadadt-infra-0dd4be439821d5925358fbf3e4d456a318eb3df4.tar.gz
Refactor console test code
1) move the event testing data to utils/constants directory 2) move REST service for console tests out 3) update related python files duo to the above changes test tracker doc: go/adt-consoletest-tracker Test: run all console test cases by command "python emu_test/dotest.py -l DEBUG -n "Ubuntu 12.04 HD Graphics 4000" -c emu_test/config/console_cfg.csv -p "test_console.*" --skip-adb-perf -f '{"gpu":"yes"}'", passed Change-Id: I8a419a89ab46bc9456fedb981217ced5200dda02
Diffstat (limited to 'console_test_server')
-rw-r--r--console_test_server/Server.iml19
-rw-r--r--console_test_server/app/build.gradle35
-rw-r--r--console_test_server/app/proguard-rules.pro17
-rw-r--r--console_test_server/app/src/androidTest/java/com/android/devtools/server/Server.java86
-rw-r--r--console_test_server/app/src/main/AndroidManifest.xml15
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/Readme.md10
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/http/GetProcessor.java71
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/http/HttpMethodsProcessor.java23
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/http/HttpServer.java157
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/http/PostProcessor.java78
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/http/UiAutomatorServlet.java46
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/model/Action.java31
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/model/Clazz.java48
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/model/PackageModel.java31
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/model/Point.java40
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/model/RestServiceModel.java44
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/model/Result.java83
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/model/SmsManagerModel.java39
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/model/TelephonyManagerModel.java39
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/model/UiModel.java76
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/services/Service.java32
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/services/ServiceBase.java91
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/services/ServiceLocator.java46
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/services/SmsManagerService.java115
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/services/TelephonyManagerService.java75
-rw-r--r--console_test_server/app/src/main/java/com/android/devtools/server/utils/ErrorHandleUtils.java39
-rw-r--r--console_test_server/app/src/main/res/mipmap-hdpi/ic_launcher.pngbin0 -> 3418 bytes
-rw-r--r--console_test_server/app/src/main/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2206 bytes
-rw-r--r--console_test_server/app/src/main/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4842 bytes
-rw-r--r--console_test_server/app/src/main/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 7718 bytes
-rw-r--r--console_test_server/app/src/main/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 10486 bytes
-rw-r--r--console_test_server/app/src/main/res/values/colors.xml6
-rw-r--r--console_test_server/app/src/main/res/values/strings.xml3
-rw-r--r--console_test_server/app/src/main/res/values/styles.xml11
-rw-r--r--console_test_server/build.gradle23
-rw-r--r--console_test_server/gradle.properties18
-rw-r--r--console_test_server/gradle/wrapper/gradle-wrapper.jarbin0 -> 53636 bytes
-rw-r--r--console_test_server/gradle/wrapper/gradle-wrapper.properties6
-rwxr-xr-xconsole_test_server/gradlew160
-rw-r--r--console_test_server/gradlew.bat90
-rw-r--r--console_test_server/settings.gradle1
41 files changed, 1704 insertions, 0 deletions
diff --git a/console_test_server/Server.iml b/console_test_server/Server.iml
new file mode 100644
index 00000000..54de7e02
--- /dev/null
+++ b/console_test_server/Server.iml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id="Server" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
+ <component name="FacetManager">
+ <facet type="java-gradle" name="Java-Gradle">
+ <configuration>
+ <option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
+ <option name="BUILDABLE" value="false" />
+ </configuration>
+ </facet>
+ </component>
+ <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <excludeFolder url="file://$MODULE_DIR$/.gradle" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ </component>
+</module> \ No newline at end of file
diff --git a/console_test_server/app/build.gradle b/console_test_server/app/build.gradle
new file mode 100644
index 00000000..da72cacc
--- /dev/null
+++ b/console_test_server/app/build.gradle
@@ -0,0 +1,35 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 23
+ buildToolsVersion "23.0.3"
+
+ defaultConfig {
+ applicationId "com.android.devtools.server"
+ minSdkVersion 18
+ targetSdkVersion 22
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ compile 'com.android.support:appcompat-v7:23.+'
+ compile 'com.android.support:support-annotations:+'
+ compile 'com.android.support.test.uiautomator:uiautomator-v18:+'
+ compile 'com.android.support.test:runner:+'
+ compile 'com.android.support.test:rules:+'
+ compile 'com.google.guava:guava:+'
+ compile 'org.hamcrest:hamcrest-library:1.3'
+ compile group: 'org.mortbay.jetty', name: 'jetty', version: '6.1.22'
+ compile group: 'com.google.code.gson', name: 'gson', version: '2.3.1'
+
+}
diff --git a/console_test_server/app/proguard-rules.pro b/console_test_server/app/proguard-rules.pro
new file mode 100644
index 00000000..fdadc4b2
--- /dev/null
+++ b/console_test_server/app/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /usr/local/google/home/jesikmin/Android/Sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/console_test_server/app/src/androidTest/java/com/android/devtools/server/Server.java b/console_test_server/app/src/androidTest/java/com/android/devtools/server/Server.java
new file mode 100644
index 00000000..5dbe217c
--- /dev/null
+++ b/console_test_server/app/src/androidTest/java/com/android/devtools/server/Server.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016 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.devtools.server;
+
+import com.android.devtools.server.http.HttpServer;
+import com.android.devtools.server.http.UiAutomatorServlet;
+import com.android.devtools.server.services.ServiceLocator;
+import com.android.devtools.server.services.SmsManagerService;
+import com.android.devtools.server.services.TelephonyManagerService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.RemoteException;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.Until;
+import android.util.Log;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * InstrumentationTestCase for launching servlet on emulator and use Android SDK.
+ */
+@RunWith(AndroidJUnit4.class)
+public class Server {
+ private final Instrumentation mInstrumentation =
+ InstrumentationRegistry.getInstrumentation();
+ private final UiDevice mDevice = UiDevice.getInstance(mInstrumentation);
+ private final Context mContext = mInstrumentation.getTargetContext();
+
+ @Before
+ public void setUp() throws RemoteException {
+ if (!mDevice.isScreenOn()) {
+ mDevice.wakeUp();
+ mDevice.wait(Until.hasObject(By.res("android", "glow_pad_view")), 10000);
+ mDevice.swipe(560, 1500, 560, 1000, 40);
+ }
+ mDevice.pressHome();
+ }
+
+ @Test
+ public void testLaunchTestServer() {
+ Map<Class<?>, String> servletUrlMapping = new HashMap<>(1);
+ servletUrlMapping.put(UiAutomatorServlet.class, "/");
+ HttpServer server =
+ new HttpServer.HttpServerBuilder()
+ .withServer(new org.mortbay.jetty.Server())
+ .withAcceptors(10)
+ .withMaxIdleTime(1000)
+ .withPort(8081)
+ .withSoLingerTime(-1)
+ .withServletUrlPathMapping(servletUrlMapping)
+ .build();
+ registerService();
+ try {
+ server.start();
+ } catch (Exception e) {
+ Log.e(this.getClass().getName(), e.getMessage());
+ }
+ }
+
+ private void registerService() {
+ ServiceLocator.register(new TelephonyManagerService(mContext));
+ ServiceLocator.register(new SmsManagerService(mContext));
+ }
+}
diff --git a/console_test_server/app/src/main/AndroidManifest.xml b/console_test_server/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..2c61bd9d
--- /dev/null
+++ b/console_test_server/app/src/main/AndroidManifest.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.devtools.server">
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+ <uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+ <uses-permission android:name="android.permission.READ_SMS"/>
+
+</manifest>
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/Readme.md b/console_test_server/app/src/main/java/com/android/devtools/server/Readme.md
new file mode 100644
index 00000000..0599fc2e
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/Readme.md
@@ -0,0 +1,10 @@
+# Description:
+ Android instrumentation test application that launches servlet on Android emulator.
+ Set up console tests (e.g. GSM call test) via REST service.
+## HOWTO:
+ ./gradlew assemble ("gradle.bat assemble" for windows)
+ adb install -r app/build/outputs/apk/app-debug.apk
+ ./gradlew assembleAndroidTest ("gradle.bat" assembleAndroidTest for windows)
+ adb install -r app/build/outputs/apk/app-debug-androidTest-unaligned.apk
+ adb shell am instrument -w -e class com.android.devtools.server.Server com.android.devtools.server.test/android.support.test.runner.AndroidJUnitRunner
+ adb -s emulator-5554 -e forward tcp:8080 tcp:8081
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/http/GetProcessor.java b/console_test_server/app/src/main/java/com/android/devtools/server/http/GetProcessor.java
new file mode 100644
index 00000000..bbe8e6b0
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/http/GetProcessor.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.http;
+
+import com.android.devtools.server.services.ServiceLocator;
+import com.android.devtools.server.utils.ErrorHandleUtils;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Handle all HTTP GET request and response.
+ */
+public class GetProcessor implements HttpMethodsProcessor {
+
+ private final HttpServletRequest req;
+ private final HttpServletResponse resp;
+
+ public GetProcessor(HttpServletRequest req, HttpServletResponse resp) {
+ this.req = req;
+ this.resp = resp;
+ }
+
+ @Override
+ public void processRequest() {
+ assert req.getMethod().equals("GET");
+ String path = req.getRequestURI();
+ resp.setStatus(HttpServletResponse.SC_OK);
+ if (path.equals("/help") || path.equals("/")) {
+ resp.setContentType("text/html");
+ writeHelpInfoToResponse();
+ } else {
+ resp.setContentType("application/json");
+ renderServicesResponse(path);
+ }
+ }
+
+ private void renderServicesResponse(String path) {
+ if (null == path) {
+ return;
+ }
+ try {
+ resp.getWriter().print(ServiceLocator.getService(path.substring(1)).execute(""));
+ } catch (IOException e) {
+ ErrorHandleUtils.logStacktrace(ErrorHandleUtils.getStacktrace(e), "GET");
+ }
+ }
+
+ private void writeHelpInfoToResponse() {
+ try {
+ resp.getWriter().println(ServiceLocator.getServices());
+ } catch (IOException e) {
+ ErrorHandleUtils.logStacktrace(ErrorHandleUtils.getStacktrace(e), "GET");
+ }
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/http/HttpMethodsProcessor.java b/console_test_server/app/src/main/java/com/android/devtools/server/http/HttpMethodsProcessor.java
new file mode 100644
index 00000000..176f869f
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/http/HttpMethodsProcessor.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.http;
+
+/**
+ * Interface for handling Http Request and Http Response.
+ */
+public interface HttpMethodsProcessor {
+ void processRequest();
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/http/HttpServer.java b/console_test_server/app/src/main/java/com/android/devtools/server/http/HttpServer.java
new file mode 100644
index 00000000..fb4b9adf
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/http/HttpServer.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.http;
+
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.handler.ContextHandler;
+import org.mortbay.jetty.nio.SelectChannelConnector;
+import org.mortbay.jetty.servlet.HashSessionManager;
+import org.mortbay.jetty.servlet.ServletHandler;
+import org.mortbay.jetty.servlet.SessionHandler;
+
+import java.util.Map;
+
+/**
+ * <p>Http Server Implementation.</p> <p> It is the place to register servlet.</p>
+ */
+public class HttpServer {
+
+ private static final String SERVER_CONTEXT_PATH = "/";
+ private final int port;
+ private final int acceptors;
+ private final int maxIdleTime;
+ private final int soLingerTime;
+ private final Map<Class<?>, String> servletUrlPathMapping;
+ private Server server;
+
+ private HttpServer(final Server server, final int port, final int acceptors,
+ final int maxIdleTime,
+ final int soLingerTime, final Map<Class<?>, String> servletUrlPathMapping) {
+ this.server = server;
+ this.port = port;
+ this.acceptors = acceptors;
+ this.maxIdleTime = maxIdleTime;
+ this.soLingerTime = soLingerTime;
+ this.servletUrlPathMapping = servletUrlPathMapping;
+ }
+
+ public void start() throws Exception {
+ configureServer();
+ server.start();
+ server.join();
+ }
+
+ private void configureServer() {
+ ServletHandler servletHandler = setServletHandler();
+ setSelectChannelConnector();
+ SessionHandler sessionsHandler = setSessionHandler(servletHandler);
+ setSessionHandler(sessionsHandler);
+ }
+
+ private void setSessionHandler(SessionHandler sessionsHandler) {
+ ContextHandler contextHandler = new ContextHandler(SERVER_CONTEXT_PATH);
+ contextHandler.setHandler(sessionsHandler);
+ server.setHandler(contextHandler);
+ }
+
+ private SessionHandler setSessionHandler(ServletHandler servletHandler) {
+ HashSessionManager manager = new HashSessionManager();
+ SessionHandler sessionsHandler = new SessionHandler(manager);
+ sessionsHandler.setHandler(servletHandler);
+ return sessionsHandler;
+ }
+
+ private void setSelectChannelConnector() {
+ SelectChannelConnector connector = new SelectChannelConnector();
+ connector.setPort(port);
+ connector.setAcceptors(acceptors);
+ connector.setMaxIdleTime(maxIdleTime);
+ connector.setSoLingerTime(soLingerTime);
+ server.addConnector(connector);
+ }
+
+ private ServletHandler setServletHandler() {
+ ServletHandler servletHandler = new ServletHandler();
+ for (Class<?> servlet : servletUrlPathMapping.keySet()) {
+ servletHandler.addServletWithMapping(servlet, servletUrlPathMapping.get(servlet));
+ }
+ return servletHandler;
+ }
+
+ public void stop() throws Exception {
+ if (server != null) {
+ server.stop();
+ server = null;
+ }
+ }
+
+ /**
+ * A builder for creating HttpServer.
+ */
+ public static class HttpServerBuilder {
+
+ private int port;
+ private int acceptors;
+ private int maxIdleTime;
+ private int soLingerTime;
+ private Map<Class<?>, String> servletUrlPathMapping;
+ private Server server;
+
+ public HttpServer build() {
+ checkServletMappingNullOrEmpty(servletUrlPathMapping);
+ return new HttpServer(server, port, acceptors, maxIdleTime, soLingerTime,
+ servletUrlPathMapping);
+ }
+
+ public HttpServerBuilder withServer(final Server server) {
+ this.server = server;
+ return this;
+ }
+
+ public HttpServerBuilder withPort(final int port) {
+ this.port = port;
+ return this;
+ }
+
+ public HttpServerBuilder withAcceptors(final int acceptors) {
+ this.acceptors = acceptors;
+ return this;
+ }
+
+ public HttpServerBuilder withMaxIdleTime(final int maxIdleTime) {
+ this.maxIdleTime = maxIdleTime;
+ return this;
+ }
+
+ public HttpServerBuilder withSoLingerTime(final int soLingerTime) {
+ this.soLingerTime = soLingerTime;
+ return this;
+ }
+
+ public HttpServerBuilder withServletUrlPathMapping(
+ final Map<Class<?>, String> servletUrlPathMapping) {
+ checkServletMappingNullOrEmpty(servletUrlPathMapping);
+ this.servletUrlPathMapping = servletUrlPathMapping;
+ return this;
+ }
+
+ private void checkServletMappingNullOrEmpty(Map<Class<?>, String> servletUrlPathMapping) {
+ if (null == servletUrlPathMapping) {
+ throw new RuntimeException("servletUrlPathMapping should not be null");
+ }
+ }
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/http/PostProcessor.java b/console_test_server/app/src/main/java/com/android/devtools/server/http/PostProcessor.java
new file mode 100644
index 00000000..cc8d6c25
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/http/PostProcessor.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.http;
+
+import com.android.devtools.server.model.Result;
+import com.android.devtools.server.services.ServiceLocator;
+import com.android.devtools.server.utils.ErrorHandleUtils;
+import com.google.gson.Gson;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Handle all HTTP POST request and response.
+ */
+public class PostProcessor implements HttpMethodsProcessor {
+
+ private final HttpServletRequest req;
+ private final HttpServletResponse resp;
+
+ public PostProcessor(HttpServletRequest req, HttpServletResponse resp) {
+ this.req = req;
+ this.resp = resp;
+ }
+
+ @Override
+ public void processRequest() {
+ assert req.getMethod().equals("POST");
+ resp.setContentType("application/json");
+ StringBuilder reqBody = new StringBuilder();
+ try {
+ consumeRequestBody(reqBody);
+ } catch (IOException e) {
+ ErrorHandleUtils.logStacktrace(ErrorHandleUtils.getStacktrace(e), "POST");
+ }
+ String stacktrace = null;
+ try {
+ resp.getWriter().print(
+ ServiceLocator.getService(req.getRequestURI().substring(1)).execute(reqBody.toString()));
+ } catch (Exception e) {
+ stacktrace = ErrorHandleUtils.getStacktrace(e);
+ ErrorHandleUtils.logStacktrace(stacktrace, "POST");
+ } finally {
+ try {
+ if (null != stacktrace) {
+ resp.getWriter().print(new Gson()
+ .toJson(new Result().setIsFail(true).setDescription(stacktrace)));
+ }
+ resp.getWriter().flush();
+ resp.getWriter().close();
+ } catch (IOException e) {
+ ErrorHandleUtils.logStacktrace(ErrorHandleUtils.getStacktrace(e), "POST");
+ }
+ }
+ }
+
+ private void consumeRequestBody(StringBuilder reqBody) throws IOException {
+ String line;
+ while (null != (line = req.getReader().readLine())) {
+ reqBody.append(line);
+ }
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/http/UiAutomatorServlet.java b/console_test_server/app/src/main/java/com/android/devtools/server/http/UiAutomatorServlet.java
new file mode 100644
index 00000000..ffe970ff
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/http/UiAutomatorServlet.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.http;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Servlet for dispacthing HTTP Request by different HTTP method.
+ */
+public class UiAutomatorServlet extends HttpServlet {
+ public UiAutomatorServlet() {}
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ processRequest(new GetProcessor(req, resp));
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ processRequest(new PostProcessor(req, resp));
+ }
+
+ public void processRequest(final HttpMethodsProcessor processor) {
+ processor.processRequest();
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/model/Action.java b/console_test_server/app/src/main/java/com/android/devtools/server/model/Action.java
new file mode 100644
index 00000000..f22ba6f3
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/model/Action.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.model;
+
+/**
+ * Json model for POST
+ */
+public abstract class Action {
+ private UiModel ui;
+
+ public UiModel getUi() {
+ return ui;
+ }
+
+ public void setUi(UiModel ui) {
+ this.ui = ui;
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/model/Clazz.java b/console_test_server/app/src/main/java/com/android/devtools/server/model/Clazz.java
new file mode 100644
index 00000000..01088cd0
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/model/Clazz.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.model;
+
+/**
+ * Model for class selector.
+ */
+public class Clazz {
+
+ private String classNameWithoutPackage;
+ private String packageName;
+
+ public String getClassNameWithoutPackage() {
+ return classNameWithoutPackage;
+ }
+
+ public void setClassNameWithoutPackage(String classNameWithoutPackage) {
+ this.classNameWithoutPackage = classNameWithoutPackage;
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ public void setPackageName(String packageName) {
+ this.packageName = packageName;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder stringBuilder =
+ new StringBuilder(packageName).append(".").append(classNameWithoutPackage);
+ return stringBuilder.toString();
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/model/PackageModel.java b/console_test_server/app/src/main/java/com/android/devtools/server/model/PackageModel.java
new file mode 100644
index 00000000..3f1c6d32
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/model/PackageModel.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.model;
+
+/**
+ * Json model for By.pkg.
+ */
+public class PackageModel {
+ private final String packageName;
+
+ public PackageModel(String packageName) {
+ this.packageName = packageName;
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/model/Point.java b/console_test_server/app/src/main/java/com/android/devtools/server/model/Point.java
new file mode 100644
index 00000000..8000c507
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/model/Point.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.model;
+
+/**
+ * Json model for a location at android ui.
+ */
+public class Point {
+ private int x;
+ private int y;
+
+ public int getX() {
+ return x;
+ }
+
+ public void setX(int x) {
+ this.x = x;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ public void setY(int y) {
+ this.y = y;
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/model/RestServiceModel.java b/console_test_server/app/src/main/java/com/android/devtools/server/model/RestServiceModel.java
new file mode 100644
index 00000000..5468e0c2
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/model/RestServiceModel.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.model;
+
+/**
+ * Model for describe a rest service endpoint.
+ */
+public class RestServiceModel {
+
+ private final String method;
+ private final String path;
+ private final String body;
+
+ public RestServiceModel(String method, String path, String body) {
+ this.method = method;
+ this.path = path;
+ this.body = body;
+ }
+
+ public String getMethod() {
+ return method;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public String getBody() {
+ return body;
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/model/Result.java b/console_test_server/app/src/main/java/com/android/devtools/server/model/Result.java
new file mode 100644
index 00000000..96476ca4
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/model/Result.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.model;
+
+/**
+ * Json model for HTTP response.
+ */
+public class Result {
+ private boolean isFail;
+ private String description;
+ private String requestBody;
+ private String windowHierarchy;
+ private String smsAddress;
+ private String smsTextMessage;
+
+ public boolean isFail() {
+ return isFail;
+ }
+
+ public Result setIsFail(boolean isFail) {
+ this.isFail = isFail;
+ return this;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public Result setDescription(String description) {
+ this.description = description;
+ return this;
+ }
+
+ public String getRequestBody() {
+ return requestBody;
+ }
+
+ public Result setRequestBody(String requestBody) {
+ this.requestBody = requestBody;
+ return this;
+ }
+
+ public String getWindowHierarchy() {
+ return windowHierarchy;
+ }
+
+ public Result setWindowHierarchy(String windowHierarchy) {
+ this.windowHierarchy = windowHierarchy;
+ return this;
+ }
+
+ public String getSmsAddress() {
+ return smsAddress;
+ }
+
+ public Result setSmsAddress(String smsAddress) {
+ this.smsAddress = smsAddress;
+ return this;
+ }
+
+ public String getSmsTextMessage() {
+ return smsTextMessage;
+ }
+
+ public Result setSmsTextMessage(String smsTextMessage) {
+ this.smsTextMessage = smsTextMessage;
+ return this;
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/model/SmsManagerModel.java b/console_test_server/app/src/main/java/com/android/devtools/server/model/SmsManagerModel.java
new file mode 100644
index 00000000..4b99a585
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/model/SmsManagerModel.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.model;
+
+import com.google.gson.Gson;
+
+/**
+ * Representation model for SMS manager services.
+ */
+public class SmsManagerModel {
+ private final String action;
+
+ public SmsManagerModel(String action) {
+ this.action = action;
+ }
+
+ @Override
+ public String toString() {
+ return new Gson().toJson(this);
+ }
+
+ public String getAction() {
+ return action;
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/model/TelephonyManagerModel.java b/console_test_server/app/src/main/java/com/android/devtools/server/model/TelephonyManagerModel.java
new file mode 100644
index 00000000..2eb6e4e1
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/model/TelephonyManagerModel.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.model;
+
+import com.google.gson.Gson;
+
+/**
+ * Representation model for Wifi manager services.
+ */
+public class TelephonyManagerModel {
+
+ private final String action;
+
+ public TelephonyManagerModel(String action) {
+ this.action = action;
+ }
+
+ @Override
+ public String toString() {
+ return new Gson().toJson(this);
+ }
+
+ public String getAction() {
+ return action;
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/model/UiModel.java b/console_test_server/app/src/main/java/com/android/devtools/server/model/UiModel.java
new file mode 100644
index 00000000..288322af
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/model/UiModel.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.model;
+/**
+ * Json model for ui selector.
+ */
+public class UiModel {
+
+ private String res;
+ private Clazz uiElementClass;
+ private String description;
+ private String text;
+ private int index;
+ private int depth;
+
+ public int getDepth() {
+ return depth;
+ }
+
+ public void setDepth(int depth) {
+ this.depth = depth;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getRes() {
+ return res;
+ }
+
+ public void setRes(String res) {
+ this.res = res;
+ }
+
+ public Clazz getUiElementClass() {
+ return uiElementClass;
+ }
+
+ public void setUiElementClass(Clazz uiElementClass) {
+ this.uiElementClass = uiElementClass;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/services/Service.java b/console_test_server/app/src/main/java/com/android/devtools/server/services/Service.java
new file mode 100644
index 00000000..3ce72af5
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/services/Service.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.services;
+
+import java.io.IOException;
+
+/**
+ * Part of Service Locator design pattern, a interface for all services.
+ */
+public interface Service {
+
+ static final String GET = "GET";
+ static final String POST = "POST";
+ static final String EMPTY_BODY = "{}";
+
+ long MAX_WAIT_TIME = 8000;
+
+ String execute(String json) throws IOException;
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/services/ServiceBase.java b/console_test_server/app/src/main/java/com/android/devtools/server/services/ServiceBase.java
new file mode 100644
index 00000000..b1ab421e
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/services/ServiceBase.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.services;
+
+import com.android.devtools.server.model.Result;
+import com.android.devtools.server.model.UiModel;
+import com.google.gson.Gson;
+
+import android.support.test.uiautomator.UiDevice;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+
+/**
+ * A parent class for all services. The idea is to provide share function for all services.
+ */
+public abstract class ServiceBase implements Service {
+
+ protected final UiDevice mDevice;
+ protected final ByteArrayOutputStream outStream;
+
+ protected ServiceBase(UiDevice mDevice) {
+ assert null != mDevice;
+ this.mDevice = mDevice;
+ this.outStream = new ByteArrayOutputStream();
+ }
+
+ protected boolean isUseText(UiModel ui) {
+ return null != ui.getText() && !ui.getText().isEmpty();
+ }
+
+ protected boolean isUseClass(UiModel ui) {
+ return null != ui.getUiElementClass();
+ }
+
+ protected boolean isUseResourceId(UiModel ui) {
+ return null != ui.getRes() && !ui.getRes().isEmpty();
+ }
+
+ protected boolean isUsingDescription(UiModel ui) {
+ return null != ui.getDescription()
+ && !ui.getDescription().isEmpty();
+ }
+
+ protected String getWidnowsHierachy() {
+ try {
+ mDevice.dumpWindowHierarchy(outStream);
+ } catch (IOException e) {
+ writeErrorToOutStream(e);
+ }
+ try {
+ return outStream.toString(Charset.forName("UTF-8").displayName());
+ } catch (UnsupportedEncodingException e) {
+ logException(e);
+ }
+ return outStream.toString();
+ }
+
+ protected String foundInvalidRequestBody(Result result) {
+ result.setIsFail(true).setDescription("Unable deserialize request body");
+ return new Gson().toJson(result);
+ }
+
+ private void logException(Exception e) {
+ Log.e("Service Error", e.getCause().toString());
+ }
+
+ private void writeErrorToOutStream(IOException e) {
+ try {
+ outStream.write(e.getCause().toString().getBytes(Charset.defaultCharset()));
+ } catch (IOException e1) {
+ logException(e);
+ }
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/services/ServiceLocator.java b/console_test_server/app/src/main/java/com/android/devtools/server/services/ServiceLocator.java
new file mode 100644
index 00000000..a25e020c
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/services/ServiceLocator.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.services;
+
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Service Locator design pattern.
+ */
+public final class ServiceLocator {
+
+ private static final Map<String, Service> serviceProvider = new HashMap<>();
+
+ public static void register(Service service) {
+ serviceProvider.put(service.getClass().getSimpleName(), service);
+ }
+
+ public static Service getService(String name) {
+ return serviceProvider.get(name);
+ }
+
+ public static String getServices() {
+ StringBuilder sb = new StringBuilder();
+ for (Service service : serviceProvider.values()){
+ Log.d("hihi", service.toString());
+ sb.append("<p>").append(service.toString()).append("</p>");
+ }
+ return sb.toString();
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/services/SmsManagerService.java b/console_test_server/app/src/main/java/com/android/devtools/server/services/SmsManagerService.java
new file mode 100644
index 00000000..2f56c519
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/services/SmsManagerService.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.services;
+
+import com.android.devtools.server.model.Result;
+import com.android.devtools.server.model.RestServiceModel;
+import com.android.devtools.server.model.SmsManagerModel;
+import com.google.gson.Gson;
+
+import java.io.IOException;
+
+import android.content.Context;
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.util.Log;
+
+/**
+ * Service for reading sms.
+ */
+public class SmsManagerService implements Service {
+
+ private static final String TAG = SmsManagerService.class.getSimpleName();
+ private static final String SMS_INBOX_URI = "content://sms/inbox";
+ private static final String SMS_ADDRESS_COLUMN = "address";
+ private static final String SMS_BODY_COLUMN = "body";
+ private static final String SMS_SERVICE_PATH = "/SmsManagerService";
+ private static final String ACTION = "String";
+ private final Context mContext;
+
+ public SmsManagerService(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public String execute(String json) throws IOException {
+ boolean isSuccess = false;
+ Result result = new Result();
+
+ SmsManagerModel smsModel = new Gson().fromJson(json, SmsManagerModel.class);
+ if (smsModel == null) {
+ Log.e(TAG, "SmsManagerModel is null. Invalid POST Request body: " + json);
+ result.setIsFail(true);
+ result.setDescription("Invalid POST Request Body");
+ return new Gson().toJson(result);
+ }
+
+ Uri smsQueryUri = Uri.parse(SMS_INBOX_URI);
+ ContentResolver contentResolver = mContext.getContentResolver();
+ Cursor cursor = null;
+
+ try {
+ cursor = contentResolver.query(smsQueryUri, null, null, null, null);
+
+ if (cursor == null) {
+ final String CURSOR_IS_NULL = "cursor is null.";
+ Log.i(TAG, CURSOR_IS_NULL + " uri: " + smsQueryUri);
+ result.setIsFail(!isSuccess);
+ return new Gson().toJson(CURSOR_IS_NULL + " uri: " + smsQueryUri);
+ }
+
+ if(cursor.moveToFirst()) {
+ for(String s : cursor.getColumnNames()){
+ Log.d(TAG + "smsColumns", "Column: " + s);
+ }
+
+ final String address = cursor.getString(
+ cursor.getColumnIndexOrThrow(SMS_ADDRESS_COLUMN));
+ result.setSmsAddress(address);
+ final String body = cursor.getString(
+ cursor.getColumnIndexOrThrow(SMS_BODY_COLUMN));
+ result.setSmsTextMessage(body);
+
+ isSuccess = true;
+ }
+ } catch (NullPointerException npe) {
+ Log.e(TAG, npe.getMessage());
+ isSuccess = false;
+ result.setDescription(Log.getStackTraceString(npe));
+ } catch (Exception e) {
+ Log.e(TAG, e.getMessage());
+ isSuccess = false;
+ result.setDescription(Log.getStackTraceString(e));
+ } finally {
+ cursor.close();
+ }
+
+ result.setIsFail(!isSuccess);
+ return new Gson().toJson(result);
+ }
+
+ @Override
+ public String toString() {
+ return new Gson()
+ .toJson(
+ new RestServiceModel(
+ POST,
+ SMS_SERVICE_PATH,
+ new SmsManagerModel(ACTION).toString()));
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/services/TelephonyManagerService.java b/console_test_server/app/src/main/java/com/android/devtools/server/services/TelephonyManagerService.java
new file mode 100644
index 00000000..c38ec790
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/services/TelephonyManagerService.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.services;
+
+import android.content.Context;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import com.android.devtools.server.model.RestServiceModel;
+import com.android.devtools.server.model.Result;
+import com.android.devtools.server.model.TelephonyManagerModel;
+import com.google.gson.Gson;
+import java.io.IOException;
+
+/**
+ * Service for phone(calling status) of phone.
+ */
+public class TelephonyManagerService implements Service {
+
+ private static final String TAG = TelephonyManagerService.class.getSimpleName();
+ private TelephonyManager telephonyManager = null;
+ private Result result = new Result();
+
+ public TelephonyManagerService(Context c) {
+ telephonyManager = (TelephonyManager) c.getSystemService(Context.TELEPHONY_SERVICE);
+ }
+
+ @Override
+ public String execute(String json) throws IOException {
+ boolean isSuccess = false;
+
+ TelephonyManagerModel telephonyModel = new Gson().fromJson(json, TelephonyManagerModel.class);
+ if (telephonyModel == null) {
+ Log.e(TAG, "TelephonyManagerModel null. Invalid POST Request body: " + json);
+ result.setIsFail(true);
+ result.setDescription("Invalid POST Request Body");
+ return new Gson().toJson(result);
+ }
+ int callState = telephonyManager.getCallState();
+ switch (callState) {
+ case TelephonyManager.CALL_STATE_IDLE:
+ case TelephonyManager.CALL_STATE_OFFHOOK:
+ case TelephonyManager.CALL_STATE_RINGING:
+ isSuccess = true;
+ result.setDescription(Integer.toString(callState));
+ break;
+ default:
+ Log.e(TAG, "Invalid Action specified in POST Request");
+ isSuccess = false;
+ result.setDescription("Unknown Action specified in request.");
+ }
+ result.setIsFail(!isSuccess);
+ return new Gson().toJson(result);
+ }
+
+ @Override
+ public String toString() {
+ return new Gson()
+ .toJson(
+ new RestServiceModel(
+ POST, "/TelephonyManagerService", new TelephonyManagerModel("String").toString()));
+ }
+}
diff --git a/console_test_server/app/src/main/java/com/android/devtools/server/utils/ErrorHandleUtils.java b/console_test_server/app/src/main/java/com/android/devtools/server/utils/ErrorHandleUtils.java
new file mode 100644
index 00000000..7d120953
--- /dev/null
+++ b/console_test_server/app/src/main/java/com/android/devtools/server/utils/ErrorHandleUtils.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016 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.devtools.server.utils;
+
+import android.util.Log;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Utils for error handling
+ */
+public class ErrorHandleUtils {
+
+ public static void logStacktrace(String stacktrace, String httpMethod){
+ Log.e(httpMethod, stacktrace);
+ }
+
+ public static String getStacktrace(Throwable t){
+ StringWriter sWriter = new StringWriter();
+ PrintWriter pWriter = new PrintWriter(sWriter);
+ t.printStackTrace(pWriter);
+ return sWriter.toString();
+ }
+
+}
diff --git a/console_test_server/app/src/main/res/mipmap-hdpi/ic_launcher.png b/console_test_server/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..cde69bcc
--- /dev/null
+++ b/console_test_server/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/console_test_server/app/src/main/res/mipmap-mdpi/ic_launcher.png b/console_test_server/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..c133a0cb
--- /dev/null
+++ b/console_test_server/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/console_test_server/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/console_test_server/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..bfa42f0e
--- /dev/null
+++ b/console_test_server/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/console_test_server/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/console_test_server/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..324e72cd
--- /dev/null
+++ b/console_test_server/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/console_test_server/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/console_test_server/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..aee44e13
--- /dev/null
+++ b/console_test_server/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/console_test_server/app/src/main/res/values/colors.xml b/console_test_server/app/src/main/res/values/colors.xml
new file mode 100644
index 00000000..3ab3e9cb
--- /dev/null
+++ b/console_test_server/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="colorPrimary">#3F51B5</color>
+ <color name="colorPrimaryDark">#303F9F</color>
+ <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/console_test_server/app/src/main/res/values/strings.xml b/console_test_server/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..a381ffb7
--- /dev/null
+++ b/console_test_server/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">Server</string>
+</resources>
diff --git a/console_test_server/app/src/main/res/values/styles.xml b/console_test_server/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..5885930d
--- /dev/null
+++ b/console_test_server/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <!-- Customize your theme here. -->
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ </style>
+
+</resources>
diff --git a/console_test_server/build.gradle b/console_test_server/build.gradle
new file mode 100644
index 00000000..aff4f415
--- /dev/null
+++ b/console_test_server/build.gradle
@@ -0,0 +1,23 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.1.2'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/console_test_server/gradle.properties b/console_test_server/gradle.properties
new file mode 100644
index 00000000..1d3591c8
--- /dev/null
+++ b/console_test_server/gradle.properties
@@ -0,0 +1,18 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true \ No newline at end of file
diff --git a/console_test_server/gradle/wrapper/gradle-wrapper.jar b/console_test_server/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..13372aef
--- /dev/null
+++ b/console_test_server/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/console_test_server/gradle/wrapper/gradle-wrapper.properties b/console_test_server/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..122a0dca
--- /dev/null
+++ b/console_test_server/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Dec 28 10:00:20 PST 2015
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
diff --git a/console_test_server/gradlew b/console_test_server/gradlew
new file mode 100755
index 00000000..9d82f789
--- /dev/null
+++ b/console_test_server/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/console_test_server/gradlew.bat b/console_test_server/gradlew.bat
new file mode 100644
index 00000000..8a0b282a
--- /dev/null
+++ b/console_test_server/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/console_test_server/settings.gradle b/console_test_server/settings.gradle
new file mode 100644
index 00000000..e7b4def4
--- /dev/null
+++ b/console_test_server/settings.gradle
@@ -0,0 +1 @@
+include ':app'