Add http related functionalities to sl4a.

Change-Id: Ie5f16087b9f44eec11501798eadc96ef69d9366b
diff --git a/Common/src/com/googlecode/android_scripting/facade/wifi/HttpFacade.java b/Common/src/com/googlecode/android_scripting/facade/wifi/HttpFacade.java
new file mode 100644
index 0000000..854a41b
--- /dev/null
+++ b/Common/src/com/googlecode/android_scripting/facade/wifi/HttpFacade.java
@@ -0,0 +1,200 @@
+
+package com.googlecode.android_scripting.facade.wifi;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+
+import android.app.Service;
+
+import com.googlecode.android_scripting.Log;
+import com.googlecode.android_scripting.facade.FacadeManager;
+import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
+import com.googlecode.android_scripting.rpc.Rpc;
+import com.googlecode.android_scripting.rpc.RpcParameter;
+
+/**
+ * Basic http operations.
+ */
+public class HttpFacade extends RpcReceiver {
+
+    private final Service mService;
+    private ServerSocket mServerSocket = null;
+    private int mSocketPort = 8081;
+    private int mServerTimeout = -1;
+    private HashMap<Integer, Socket> mSockets = null;
+    private int socketCnt = 0;
+
+    public HttpFacade(FacadeManager manager) throws IOException {
+        super(manager);
+        mService = manager.getService();
+        mSockets = new HashMap<Integer, Socket>();
+        mServerSocket = new ServerSocket(mSocketPort);
+    }
+
+    private void inputStreamToOutputStream(InputStream in, OutputStream out) throws IOException {
+        if (in == null) {
+            Log.e("InputStream is null.");
+            return;
+        }
+        if (out == null) {
+            Log.e("OutputStream is null.");
+            return;
+        }
+        try {
+            int read = 0;
+            byte[] bytes = new byte[1024];
+            while ((read = in.read(bytes)) != -1) {
+                out.write(bytes, 0, read);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            in.close();
+            out.close();
+        }
+
+    }
+
+    private String inputStreamToString(InputStream in) throws IOException {
+        BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
+        StringBuilder sb = new StringBuilder();
+        String str = null;
+        while ((str = r.readLine()) != null) {
+            sb.append(str);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Send an http request and get the response.
+     *
+     * @param url The url to send request to.
+     * @return The HttpURLConnection object.
+     * @throws IOException When request failed to go through with response code 200.
+     */
+    private HttpURLConnection httpRequest(String url) throws IOException {
+        URL targetURL = new URL(url);
+        HttpURLConnection urlConnection = null;
+        try {
+            urlConnection = (HttpURLConnection) targetURL.openConnection();
+        } catch (IOException e) {
+            Log.e("Failed to open a connection to " + url);
+            Log.e(e.toString());
+            throw e;
+        } finally {
+            if (urlConnection != null) {
+                urlConnection.disconnect();
+            }
+        }
+        int code = urlConnection.getResponseCode();
+        if (code != HttpURLConnection.HTTP_OK) {
+            Log.d("Http request did not return 200.");
+            Log.d("Response code: " + code);
+            String respMsg = urlConnection.getResponseMessage();
+            Log.d("Response message: " + respMsg);
+            throw new IOException("HTTP request did not return 200. " + respMsg);
+        }
+        return urlConnection;
+    }
+
+    @Rpc(description = "Start waiting for a connection request on a specified port.",
+            returns = "The index of the connection.")
+    public Integer httpAcceptConnection(int port) throws IOException {
+        mServerSocket = new ServerSocket(port);
+        if (mServerTimeout > 0) {
+            mServerSocket.setSoTimeout(mServerTimeout);
+        }
+        Socket sock = mServerSocket.accept();
+        socketCnt += 1;
+        mSockets.put(socketCnt, sock);
+        return socketCnt;
+    }
+
+    @Rpc(description = "Download a file from specified url.")
+    public void httpDownloadFile(String url) throws IOException {
+        HttpURLConnection urlConnection = httpRequest(url);
+
+        String filename = null;
+        String contentDisposition = urlConnection.getHeaderField("Content-Disposition");
+        // Try to figure out the name of the file being downloaded.
+        // If the server returned a filename, use it.
+        if (contentDisposition != null) {
+            int idx = contentDisposition.toLowerCase().indexOf("filename");
+            if (idx != -1) {
+                filename = contentDisposition.substring(idx + 9);
+                Log.d("Using name returned by server: " + filename);
+            }
+        }
+        // If the server did not provide a filename to us, use the last part of url.
+        if (filename == null) {
+            int lastIdx = url.lastIndexOf('/');
+            filename = url.substring(lastIdx + 1);
+            Log.d("Using name from url: " + filename);
+        }
+        InputStream in = new BufferedInputStream(urlConnection.getInputStream());
+        String outPath = "/sdcard/Download/" + filename;
+        OutputStream output = new FileOutputStream(new File(outPath));
+        inputStreamToOutputStream(in, output);
+        Log.d("Downloaded file at " + outPath);
+    }
+
+    @Rpc(description = "Make an http request and return the response message.")
+    public String httpPing(@RpcParameter(name = "url") String url) throws IOException {
+        HttpURLConnection urlConnection = null;
+        urlConnection = httpRequest(url);
+        String resp = urlConnection.getResponseMessage();
+        Log.d("Fetched " + resp);
+        return resp;
+    }
+
+    @Rpc(description = "Make an http request and only return the length of the response content.")
+    public Integer httpRequestLength(@RpcParameter(name = "url") String url) throws IOException {
+        HttpURLConnection urlConnection = httpRequest(url);
+        int respSize = urlConnection.getContentLength();
+        Log.d("Fetched: " + respSize);
+        return respSize;
+    }
+
+    @Rpc(description = "Make an http request and return the response content as a string.")
+    public String httpRequestString(@RpcParameter(name = "url") String url) throws IOException {
+        HttpURLConnection urlConnection = httpRequest(url);
+        InputStream in = new BufferedInputStream(urlConnection.getInputStream());
+        String result = inputStreamToString(in);
+        Log.d("Fetched: " + result);
+        return result;
+    }
+
+    @Rpc(description = "Set how many milliseconds to wait for an incoming connection.")
+    public void httpSetServerTimeout(@RpcParameter(name = "timeout") int timeout)
+            throws SocketException {
+        mServerSocket.setSoTimeout(timeout);
+        mServerTimeout = timeout;
+    }
+
+    @Override
+    public void shutdown() {
+        for (int key : mSockets.keySet()) {
+            Socket sock = mSockets.get(key);
+            try {
+                sock.close();
+            } catch (IOException e) {
+                Log.e("Failed to close socket " + key + " on port " + sock.getLocalPort());
+                e.printStackTrace();
+            }
+        }
+    }
+}
diff --git a/Common/src/com/googlecode/android_scripting/facade/wifi/WifiManagerFacade.java b/Common/src/com/googlecode/android_scripting/facade/wifi/WifiManagerFacade.java
index 91f7a38..6d537ef 100755
--- a/Common/src/com/googlecode/android_scripting/facade/wifi/WifiManagerFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/wifi/WifiManagerFacade.java
@@ -80,14 +80,13 @@
         }
     };
 
-    private WifiLock mLock;
-    private boolean mIsConnected;
+    private WifiLock mLock = null;
+    private boolean mIsConnected = false;
 
     public WifiManagerFacade(FacadeManager manager) {
         super(manager);
         mService = manager.getService();
         mWifi = (WifiManager) mService.getSystemService(Context.WIFI_SERVICE);
-        mLock = null;
         mEventFacade = manager.getReceiver(EventFacade.class);
 
         mScanFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
diff --git a/ScriptingLayer/src/com/googlecode/android_scripting/facade/FacadeConfiguration.java b/ScriptingLayer/src/com/googlecode/android_scripting/facade/FacadeConfiguration.java
index 29b3f14..d1d9350 100644
--- a/ScriptingLayer/src/com/googlecode/android_scripting/facade/FacadeConfiguration.java
+++ b/ScriptingLayer/src/com/googlecode/android_scripting/facade/FacadeConfiguration.java
@@ -16,6 +16,16 @@
 
 package com.googlecode.android_scripting.facade;
 
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
 import com.google.common.collect.Maps;
 import com.googlecode.android_scripting.Log;
 import com.googlecode.android_scripting.facade.bluetooth.BluetoothA2dpFacade;
@@ -37,6 +47,7 @@
 import com.googlecode.android_scripting.facade.tele.PhoneFacade;
 import com.googlecode.android_scripting.facade.tele.TelecomManagerFacade;
 import com.googlecode.android_scripting.facade.ui.UiFacade;
+import com.googlecode.android_scripting.facade.wifi.HttpFacade;
 import com.googlecode.android_scripting.facade.wifi.WifiManagerFacade;
 import com.googlecode.android_scripting.facade.wifi.WifiP2pManagerFacade;
 import com.googlecode.android_scripting.facade.wifi.WifiRttManagerFacade;
@@ -49,16 +60,6 @@
 import com.googlecode.android_scripting.rpc.RpcStopEvent;
 import com.googlecode.android_scripting.webcam.WebCamFacade;
 
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
 /**
  * Encapsulates the list of supported facades and their construction.
  */
@@ -95,6 +96,7 @@
         sFacadeClassList.add(SpeechRecognitionFacade.class);
         sFacadeClassList.add(ToneGeneratorFacade.class);
         sFacadeClassList.add(WakeLockFacade.class);
+        sFacadeClassList.add(HttpFacade.class);
         sFacadeClassList.add(WifiManagerFacade.class);
         sFacadeClassList.add(UiFacade.class);