commit a5b8c8910d2c99b0d5946dcd0cd220fb276086dd
parent a4da5eb73301e685f53d94a9454cd57a60fa4dc0
Author: Jan Dankert <devnull@localhost>
Date: Fri, 25 Nov 2011 00:05:54 +0100
Vervollständigung der Eingabe-Maske, incl. Kamera-Aufruf und Starten von IntentService. Vervollständiung der Einstellungen.
Diffstat:
9 files changed, 1057 insertions(+), 27 deletions(-)
diff --git a/res/layout/main.xml b/res/layout/main.xml
@@ -1,16 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical" android:layout_width="fill_parent"
- android:layout_height="fill_parent">
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent" android:layout_height="fill_parent">
+ <LinearLayout android:orientation="vertical"
+ android:layout_width="fill_parent" android:layout_height="fill_parent">
- <TextView android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="@string/hello" />
-
+ <TextView android:layout_width="fill_parent"
+ android:layout_height="wrap_content" android:text="@string/param_title" />
<EditText android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:id="@+id/text" />
-
- <Button android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="@string/hello"
- android:id="@+id/save" />
-
-</LinearLayout>
+ android:layout_height="wrap_content" android:id="@+id/title" />
+
+ <TextView android:layout_width="fill_parent"
+ android:layout_height="wrap_content" android:text="@string/param_text" />
+ <EditText android:layout_width="fill_parent"
+ android:layout_height="wrap_content" android:id="@+id/text" />
+
+ <TextView android:layout_width="fill_parent"
+ android:layout_height="wrap_content" android:text="@string/param_image" />
+ <ImageButton android:layout_width="fill_parent"
+ android:layout_height="wrap_content" android:id="@+id/image" />
+
+ <CheckBox android:layout_width="fill_parent"
+ android:layout_height="wrap_content" android:id="@+id/ispublic" android:text="@string/param_privacy" />
+
+ <Button android:layout_width="fill_parent"
+ android:layout_height="wrap_content" android:text="@string/hello"
+ android:id="@+id/save" />
+
+ </LinearLayout>
+</ScrollView>
diff --git a/res/values/strings.xml b/res/values/strings.xml
@@ -3,13 +3,22 @@
<string name="hello">Hello World, Blog!</string>
<string name="app_name">Blog</string>
<string name="save">Blog</string>
- <string name="settings">Einstellunen</string>
+ <string name="settings">Einstellungen</string>
<string name="mail">E-Mail</string>
<string name="upload">Hochladen</string>
+ <string name="upload_long">Hochladen der Daten</string>
+ <string name="upload_ok">Hochladen beendet</string>
+ <string name="upload_ok_long">Hochladen erfolgreich beendet</string>
+ <string name="upload_fail">Hochladen nicht erfolgreich</string>
+ <string name="upload_fail_long">Hochladen fehlgeschlagen</string>
<string name="url">URL</string>
<string name="param_image">Parameter Bild</string>
- <string name="param_text">Text</string>
+ <string name="param_title">Parameter Titel</string>
+ <string name="param_text">Parameter Text</string>
+ <string name="param_privacy">Parameter Privacy</string>
<string name="user">Benutzer</string>
<string name="password">Kennwort</string>
<string name="take_photo">Kamera</string>
+ <string name="use_email">Per E-Mail versenden</string>
+ <string name="use_upload">Hochladen</string>
</resources>
diff --git a/res/xml/settings.xml b/res/xml/settings.xml
@@ -1,11 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/hello">
- <PreferenceCategory android:title="@string/settings">
- <EditTextPreference android:key="param_image"
- android:title="@string/param_image"></EditTextPreference>
- <EditTextPreference android:key="url"
- android:title="@string/url"></EditTextPreference>
- </PreferenceCategory>
+ <CheckBoxPreference android:key="use_email" android:title="@string/use_email" />
+
+ <PreferenceScreen android:dependency="use_email" android:title="@string/use_email">
+ <PreferenceCategory android:title="@string/settings">
+ <EditTextPreference android:key="url"
+ android:title="@string/url"></EditTextPreference>
+ <EditTextPreference android:key="http_user"
+ android:title="@string/user"></EditTextPreference>
+ <EditTextPreference android:key="http_password"
+ android:password="true" android:title="@string/password"></EditTextPreference>
+ <EditTextPreference android:key="param_title"
+ android:title="@string/param_title"></EditTextPreference>
+ <EditTextPreference android:key="param_text"
+ android:title="@string/param_text"></EditTextPreference>
+ <EditTextPreference android:key="param_image"
+ android:title="@string/param_image"></EditTextPreference>
+ <EditTextPreference android:key="param_privacy"
+ android:title="@string/param_privacy"></EditTextPreference>
+ </PreferenceCategory>
+ </PreferenceScreen>
+
+ <CheckBoxPreference android:key="use_upload" android:title="@string/use_upload" />
+
+ <PreferenceScreen android:dependency="use_upload" android:title="@string/use_upload">
+ <PreferenceCategory android:title="@string/settings">
+ <EditTextPreference android:key="recipient_address"
+ android:title="@string/param_image"></EditTextPreference>
+ <EditTextPreference android:key="smtp_host"
+ android:title="@string/url"></EditTextPreference>
+ <EditTextPreference android:key="smtp_user"
+ android:title="@string/user"></EditTextPreference>
+ <EditTextPreference android:key="smtp_password"
+ android:password="true" android:title="@string/password"></EditTextPreference>
+ </PreferenceCategory>
+ </PreferenceScreen>
</PreferenceScreen>
diff --git a/src/de/openrat/android/blog/Blog.java b/src/de/openrat/android/blog/Blog.java
@@ -7,19 +7,29 @@ import java.io.IOException;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.graphics.Bitmap;
-import android.hardware.Camera;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
+import android.preference.PreferenceManager;
import android.provider.MediaStore;
-import android.provider.MediaStore.Audio.Media;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageView;
public class Blog extends Activity
{
+ private static final int TAKE_PHOTO_CODE = 1;
+ private String imageFilename;
+ private ImageView image;
+ private EditText title;
+ private EditText text;
@Override
public void onCreate(Bundle savedInstanceState)
@@ -27,6 +37,59 @@ public class Blog extends Activity
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
+
+ title = (EditText) findViewById(R.id.title);
+ text = (EditText) findViewById(R.id.text);
+ image = (ImageView) findViewById(R.id.image);
+ image.setOnClickListener(new OnClickListener()
+ {
+
+ @Override
+ public void onClick(View v)
+ {
+ takePhoto();
+ }
+ });
+ Button button = (Button) findViewById(R.id.save);
+ button.setOnClickListener(new OnClickListener()
+ {
+
+ @Override
+ public void onClick(View v)
+ {
+ SharedPreferences prefs = PreferenceManager
+ .getDefaultSharedPreferences(Blog.this);
+
+ if (prefs.getBoolean("use_upload", false))
+ {
+ final Intent uploadIntent = new Intent(Blog.this,
+ UploadIntentService.class);
+
+ uploadIntent.putExtra(UploadIntentService.EXTRA_TITLE,
+ title.getText());
+ uploadIntent.putExtra(UploadIntentService.EXTRA_TEXT, text
+ .getText());
+ uploadIntent.putExtra(UploadIntentService.EXTRA_IMAGE,
+ imageFilename);
+ startService(uploadIntent);
+
+ }
+ if (prefs.getBoolean("use_mail", false))
+ {
+ final Intent mailIntent = new Intent(Blog.this,
+ MailIntentService.class);
+ mailIntent.putExtra(UploadIntentService.EXTRA_TITLE, title
+ .getText());
+ mailIntent.putExtra(UploadIntentService.EXTRA_TEXT, text
+ .getText());
+ mailIntent.putExtra(UploadIntentService.EXTRA_IMAGE,
+ imageFilename);
+
+ startService(mailIntent);
+ }
+
+ }
+ });
}
@Override
@@ -71,8 +134,6 @@ public class Blog extends Activity
* } } };
*/
- private static final int TAKE_PHOTO_CODE = 1;
-
private void takePhoto()
{
final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
@@ -102,13 +163,14 @@ public class Blog extends Activity
{
case TAKE_PHOTO_CODE:
final File file = getTempFile(this);
+ this.imageFilename = file.getAbsoluteFile().getName();
try
{
Bitmap captureBmp = android.provider.MediaStore.Images.Media
.getBitmap(getContentResolver(), Uri
.fromFile(file));
- // do whatever you want with the bitmap (Resize, Rename,
- // Add To Gallery, etc)
+
+ image.setImageBitmap(captureBmp);
}
catch (FileNotFoundException e)
{
diff --git a/src/de/openrat/android/blog/FileUtils.java b/src/de/openrat/android/blog/FileUtils.java
@@ -0,0 +1,55 @@
+/**
+ *
+ */
+package de.openrat.android.blog;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author dankert
+ *
+ */
+public class FileUtils
+{
+
+ /**
+ *
+ * @param file
+ * @return
+ * @throws IOException
+ */
+ public static byte[] getBytesFromFile(File file) throws IOException {
+ InputStream is = new FileInputStream(file);
+
+ // Get the size of the file
+ long length = file.length();
+
+ if (length > Integer.MAX_VALUE) {
+ // File is too large
+ throw new IOException("File is too large");
+ }
+
+ // Create the byte array to hold the data
+ byte[] bytes = new byte[(int)length];
+
+ // Read in the bytes
+ int offset = 0;
+ int numRead = 0;
+ while (offset < bytes.length
+ && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
+ offset += numRead;
+ }
+
+ // Ensure all the bytes have been read in
+ if (offset < bytes.length) {
+ throw new IOException("Could not completely read file "+file.getName());
+ }
+
+ // Close the input stream and return bytes
+ is.close();
+ return bytes;
+ }
+}
diff --git a/src/de/openrat/android/blog/HTTPRequest.java b/src/de/openrat/android/blog/HTTPRequest.java
@@ -0,0 +1,624 @@
+/*
+OpenRat Java-Client
+Copyright (C) 2009 Jan Dankert
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the
+Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+Boston, MA 02110-1301, USA.
+
+ */
+package de.openrat.android.blog;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * API-Request to the OpenRat Content Management System. <br>
+ * <br>
+ * The call to the CMS server is done via a (non-SSL) HTTP connection.<br>
+ * <br>
+ * Before a call you are able to set some key/value-pairs as parameters. After
+ * calling the CMS a DOM-document is returned, which contains the server
+ * response.<br>
+ * Example <br>
+ *
+ * <pre>
+ * CMSRequest request = new CMSRequest("your.openrat.example.com");
+ * //prints tracing information to stdout.
+ * request.trace = true;
+ * try
+ * {
+ * request.parameter.put("action", "index");
+ * request.parameter.put("subaction", "showlogin"); // login page
+ * request.parameter.put("...", "...");
+ * Document response = request.call();
+ * // now traverse through the dom tree and get your information.
+ * } catch (IOException e)
+ * {
+ * // your error handling.
+ * }
+ * </pre>
+ *
+ * @author Jan Dankert
+ */
+public class HTTPRequest implements Serializable
+{
+
+ private static final String CRLF = "\r\n";
+
+ private Multipart multipart = new Multipart();
+
+ // some constants...
+ private static final String CHARSET_UTF8 = "UTF-8";
+ private static final String HTTP_GET = "GET";
+ private static final String HTTP_POST = "POST";
+
+ /**
+ * if <code>true</code>, Tracing-Output will be logged to stdout. Default:
+ * <code>false</code>.
+ */
+ // this is public, for easier use.
+ public boolean trace = false;
+
+ /**
+ * HTTP-method, must be "GET" or "POST", default: "GET".
+ */
+ private String method = HTTP_GET;
+
+ /**
+ * Parameter map.
+ */
+ private Map<String, String> parameter = new HashMap<String, String>();
+ private Map<String, String> requestHeader = new HashMap<String, String>();
+
+ private String serverPath;
+ private String serverHost;
+ private int serverPort;
+
+ private String proxyHostname;
+ private int proxyPort;
+ private SocketAddress socketAddress;
+
+ private String cookieName;
+ private String cookieValue;
+ private String language;
+ private int timeout = 30000;
+
+ /**
+ *
+ */
+ public HTTPRequest()
+ {
+ super();
+ this.language = Locale.getDefault().getLanguage();
+ }
+
+ public String getAcceptLanguage()
+ {
+ return language;
+ }
+
+ public void setAcceptLanguage(String language)
+ {
+ this.language = language;
+ }
+
+ /**
+ * Setting a HTTP-Cookie.
+ *
+ * @param name
+ * name
+ * @param value
+ * value
+ */
+ public void setCookie(String name, String value)
+ {
+
+ this.cookieName = this.urlEncode(name);
+ this.cookieValue = this.urlEncode(value);
+ }
+
+ /**
+ * URL-Encoder.
+ *
+ * @param value
+ * @return url-encoded value
+ */
+ private String urlEncode(String value)
+ {
+
+ try
+ {
+ return URLEncoder.encode(value, CHARSET_UTF8);
+ } catch (UnsupportedEncodingException e)
+ {
+ // maybe... this would be strange
+ throw new IllegalStateException(CHARSET_UTF8
+ + " ist not supported by this VM");
+ }
+ }
+
+ /**
+ * Setting a HTTP-Proxy.
+ *
+ * @param host
+ * hostname
+ * @param port
+ * port
+ */
+ public void setProxy(String host, int port)
+ {
+
+ this.proxyHostname = host;
+ this.proxyPort = port;
+ }
+
+
+ /**
+ * Timeout for Socket.
+ * @param timeout Timeout in milliseconds.
+ * @return old timeout
+ */
+ public int setTimeout(int timeout)
+ {
+ int oldTimeout = this.timeout;
+ this.timeout = timeout;
+
+ return oldTimeout;
+ }
+
+ /**
+ * Set the HTTP Method. Default is "GET".
+ *
+ * @param method
+ * HTTP-method
+ */
+ public void setMethod(String method)
+ {
+
+ if (!HTTP_GET.equalsIgnoreCase(method)
+ && !HTTP_POST.equalsIgnoreCase(method))
+ throw new IllegalArgumentException("Method must be '" + HTTP_POST
+ + "' or '" + HTTP_GET + "'.");
+
+ this.method = method.toUpperCase();
+ }
+
+ /**
+ * Clear parameter values.
+ */
+ public void clearParameters()
+ {
+
+ parameter.clear();
+ requestHeader.clear();
+ multipart.parts.clear();
+ }
+
+ /**
+ * Setting a parameter value. <strong>DO NOT url-encode your values</strong>
+ * as this is done automatically inside this method!
+ *
+ * @param paramName
+ * name
+ * @param paramValue
+ * value
+ */
+ public void setParameter(String paramName, String paramValue)
+ {
+
+ if (paramName == null || paramValue == null || "" == paramName)
+ throw new IllegalArgumentException(
+ "parameter name and value must have values");
+
+ parameter.put(paramName, paramValue);
+ }
+
+ /**
+ *
+ * Setting a parameter value. <strong>DO NOT url-encode your values</strong>
+ * as this is done automatically inside this method!
+ *
+ * @param paramName
+ * name
+ * @param paramValue
+ * value
+ */
+ public void setHeader(String paramName, String paramValue)
+ {
+
+ if (paramName == null || paramValue == null || "" == paramName)
+ throw new IllegalArgumentException(
+ "parameter name and value must have values");
+
+ requestHeader.put(paramName, paramValue);
+ }
+
+ /**
+ * Constructs a CMS-Request to the specified server.<br>
+ * Server-Path is "/", Server-Port is 80.
+ *
+ * @param host
+ * hostname
+ */
+ public HTTPRequest(String host)
+ {
+
+ super();
+ this.serverHost = host;
+ this.serverPath = "/";
+ this.serverPort = 80;
+ }
+
+ /**
+ * Constructs a CMS-Request to the specified server/path.<br>
+ * Server-Port is 80.
+ *
+ * @param host
+ * hostname
+ * @param path
+ * path
+ */
+ public HTTPRequest(String host, String path)
+ {
+
+ super();
+ this.serverHost = host;
+ this.serverPath = path;
+ this.serverPort = 80;
+ }
+
+ /**
+ * Constructs a CMS-Request to the specified server/path/port.
+ *
+ * @param host
+ * hostname
+ * @param path
+ * path
+ * @param port
+ * port-number
+ */
+ public HTTPRequest(String host, String path, int port)
+ {
+
+ super();
+ this.serverHost = host;
+ this.serverPath = path;
+ this.serverPort = port;
+ }
+
+ /**
+ * Sends a request to the openrat-server and parses the response into a DOM
+ * tree document.
+ *
+ * @return server response as a DOM tree
+ * @throws IOException
+ * if server is unrechable or responds non-wellformed XML
+ */
+ public byte[] performRequest() throws IOException
+ {
+ return performRequest(null);
+ }
+
+ /**
+ * Sends a request to the openrat-server and parses the response into a DOM
+ * tree document.
+ *
+ * @return server response as a DOM tree
+ * @throws IOException
+ * if server is unrechable or responds non-wellformed XML
+ */
+ public byte[] performRequest(String body) throws IOException
+ {
+
+ final Socket socket = new Socket();
+
+ try
+ {
+
+ final boolean useProxy = this.proxyHostname != null;
+ final boolean useCookie = this.cookieName != null;
+
+ if (serverPath == null)
+ this.serverPath = "/";
+ if (!serverPath.startsWith("/"))
+ this.serverPath = "/" + this.serverPath;
+
+ // When a client uses a proxy, it typically sends all requests to
+ // that proxy, instead
+ // of to the servers in the URLs. Requests to a proxy differ from
+ // normal requests in one
+ // way: in the first line, they use the complete URL of the resource
+ // being requested,
+ // instead of just the path.
+ if (useProxy)
+ {
+ socketAddress = new InetSocketAddress(this.proxyHostname,
+ this.proxyPort);
+ } else
+ {
+ socketAddress = new InetSocketAddress(this.serverHost,
+ serverPort);
+ }
+
+ socket.setKeepAlive(false);
+ socket.setReuseAddress(false);
+ socket.setSoTimeout(timeout);
+ socket.connect(socketAddress, timeout);
+
+ final StringBuffer header = new StringBuffer();
+
+ final StringBuffer parameterList = new StringBuffer();
+
+ for (Entry<String, String> entry : this.parameter.entrySet())
+ {
+ if (parameterList.length() > 0)
+ parameterList.append("&");
+ parameterList.append(this.urlEncode(entry.getKey()));
+ parameterList.append("=");
+ parameterList.append(this.urlEncode(entry.getValue()));
+ }
+
+ String httpUrl = this.serverPath;
+
+ if (useProxy)
+ // See RFC 2616 Section 5.1.2 "Request-URI"
+ // "The absolute URI form is REQUIRED when the request is being made to a proxy"
+ httpUrl = "http://" + this.serverHost + httpUrl;
+
+ if (HTTP_GET.equals(this.method)
+ || (body != null || multipart.parts.size() > 0))
+ httpUrl = httpUrl + "?" + parameterList;
+
+ // using HTTP/1.0 as this is supported by all HTTP-servers and
+ // proxys.
+ // We have no need for HTTP/1.1 at the moment.
+ header.append(this.method + " " + httpUrl + " HTTP/1.0" + CRLF);
+
+ // Setting the HTTP Header
+ Map<String, String> headers = new HashMap<String, String>();
+ headers.put("Host", this.serverHost);
+ headers.put("User-Agent",
+ "Mozilla/5.0; compatible (OpenRat android-client)");
+ headers.put("Accept", "application/json");
+ headers.put("Accept-Language", language);
+ headers.put("Accept-Charset", "utf-8");
+ headers.put("Connection", "close");
+ if (useCookie)
+ headers.put("Cookie", cookieName + "=" + cookieValue);
+
+ if (HTTP_POST.equals(this.method))
+ {
+ if (body == null && multipart.parts.size() == 0)
+ {
+ headers.put("Content-Type",
+ "application/x-www-form-urlencoded");
+ headers.put("Content-Length", "" + parameterList.length());
+ } else if (multipart.parts.size() > 0)
+ {
+
+ headers.put("Content-Type", multipart.getContentType());
+ headers.put("Content-Length", ""
+ + multipart.getPayload().length);
+
+ } else
+ {
+ headers.put("Content-Type", "text/plain");
+
+ }
+ }
+
+ headers.putAll(requestHeader);
+ for (String headerName : headers.keySet())
+ {
+ header.append(headerName + ": " + headers.get(headerName)
+ + CRLF);
+
+ }
+
+ header.append(CRLF);
+
+ final OutputStream outputStream = socket
+ .getOutputStream();
+ outputStream.write(header.toString().getBytes());
+
+ if (HTTP_POST.equals(this.method))
+ {
+ if (body == null && multipart.parts.size() == 0)
+ outputStream.write(parameterList.toString().getBytes());
+ else if (multipart.parts.size() > 0)
+ outputStream.write(multipart.getPayload());
+ else
+ outputStream.write(body.getBytes());
+ }
+
+ if (this.trace)
+ System.out.println("--- request ---");
+ if (this.trace)
+ System.out.println(header.toString());
+
+
+ outputStream.flush();
+
+ final InputStream inputStream = socket.getInputStream();
+// final int available = inputStream.available();
+
+ final BufferedReader bufferedReader = new BufferedReader(
+ new MyStreamReader(inputStream),1);
+
+ final String httpResponse = bufferedReader.readLine().trim();
+ final String httpRetCode = httpResponse.substring(9, 12);
+
+ if (this.trace)
+ System.out.println("--- response ---");
+ if (this.trace)
+ System.out.println(httpResponse);
+
+ // Check if we got the status 200=OK.
+ if (!httpRetCode.equals("200"))
+ {
+
+ // non-200-status seems to be an error.
+ throw new IOException("No HTTP 200: Status=" + httpRetCode
+ + " (" + httpResponse + ")");
+ }
+
+ while (true)
+ {
+
+ String responseHeader = bufferedReader.readLine().trim();
+
+ if (responseHeader.equals(""))
+ break;
+
+ if (this.trace)
+ System.out.println(responseHeader);
+ }
+ //inputStreamReader.reset();
+ //inputStream.reset();
+
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ int nRead;
+ byte[] data = new byte[1024];
+
+ while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
+ buffer.write(data, 0, nRead);
+ }
+ buffer.flush();
+
+ byte[] response = buffer.toByteArray();
+
+ if (this.trace)
+ System.out.println("--- response body ---");
+ if (this.trace)
+ System.out.println(response + "\n\n\n");
+
+ return response;
+ } finally
+ {
+ try
+ {
+ socket.close(); // Clean up the socket.
+ } catch (IOException e)
+ {
+ // We have done our very best.
+ }
+ }
+
+ }
+
+ public void setFile(String name, byte[] value, String filename,
+ String type, String encoding)
+ {
+
+ Part part = new Part();
+ part.file = value;
+ part.filename = filename;
+ part.encoding = encoding;
+ part.name = name;
+ part.contentType = type;
+ this.multipart.parts.add(part);
+ }
+
+ public void setText(String name, String value)
+ {
+
+ Part part = new Part();
+ part.name = name;
+ part.text = value;
+ part.contentType = "text/plain";
+ this.multipart.parts.add(part);
+ }
+
+ private class Multipart implements Serializable
+ {
+
+ private static final String CRLF = "\r\n";
+ private static final String BOUNDARY = "614BA262123F3B29656A745C5DD26";
+ List<Part> parts = new ArrayList<Part>();
+
+ public byte[] getPayload() throws IOException
+ {
+ HttpOutputStream body = new HttpOutputStream();
+
+ for (Part part : parts)
+ {
+ body.append("--" + BOUNDARY + CRLF);
+ body.append("Content-Type: " + part.contentType + CRLF);
+
+ if (part.encoding != null)
+ body.append("Content-Transfer-Encoding: " + part.encoding
+ + CRLF);
+
+ body.append("Content-Disposition: form-data; name=\""
+ + part.name
+ + "\""
+ + (part.filename != null ? ("; filename=\""
+ + part.filename + "\"") : "") + CRLF);
+ body.append(CRLF);
+ if (part.file.length > 0)
+ body.write(part.file);
+ else
+ body.append(part.text);
+ body.append(CRLF);
+ }
+ body.append("--" + BOUNDARY + "--");
+ return body.toByteArray();
+ }
+
+ public String getContentType()
+ {
+ return "multipart/form-data; boundary=" + Multipart.BOUNDARY;
+ }
+ }
+
+ private class Part implements Serializable
+ {
+ public byte[] file;
+ public String filename;
+ public String text;
+ public String name;
+ public String contentType;
+ public String encoding;
+ }
+
+ private class HttpOutputStream extends ByteArrayOutputStream
+ {
+
+ public void write(String s) throws IOException
+ {
+ super.write(s.getBytes());
+ }
+ public void append(String s) throws IOException
+ {
+ super.write(s.getBytes());
+ }
+ }
+}
diff --git a/src/de/openrat/android/blog/MailIntentService.java b/src/de/openrat/android/blog/MailIntentService.java
@@ -0,0 +1,99 @@
+/**
+ *
+ */
+package de.openrat.android.blog;
+
+import java.io.File;
+import java.io.IOException;
+
+import android.app.IntentService;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+/**
+ * @author dankert
+ *
+ */
+public class MailIntentService extends IntentService
+{
+
+ private static final int NOTIFICATION_UPLOAD = 1;
+
+ public MailIntentService()
+ {
+ super("UploadIntentService");
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see android.app.IntentService#onHandleIntent(android.content.Intent)
+ */
+ @Override
+ protected void onHandleIntent(Intent intent)
+ {
+ final String filePath = intent.getStringExtra(UploadIntentService.EXTRA_IMAGE);
+
+ final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+
+ final Intent notificationIntent = new Intent(this, Blog.class);
+ final PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
+ notificationIntent, 0);
+
+ final File file = new File(filePath);
+ final String tickerText = getResources()
+ .getString(R.string.upload_long);
+ final Notification notification = new Notification(
+ android.R.drawable.ic_menu_rotate, tickerText, System
+ .currentTimeMillis());
+ notification.setLatestEventInfo(getApplicationContext(), getResources()
+ .getString(R.string.upload), file.getName(), contentIntent);
+ notification.flags = Notification.FLAG_ONGOING_EVENT
+ | Notification.FLAG_NO_CLEAR;
+ nm.notify(NOTIFICATION_UPLOAD, notification);
+
+ SharedPreferences prefs = PreferenceManager
+ .getDefaultSharedPreferences(this);
+
+ try
+ {
+ HTTPRequest request = new HTTPRequest();
+ request.setFile(prefs.getString("param_image", "image"), FileUtils
+ .getBytesFromFile(file), "image.png", "image/png", "binary");
+ // Alles OK.
+ final String msgText = getResources().getString(R.string.upload_ok);
+ notification.tickerText = getResources().getString(
+ R.string.upload_ok_long);
+ notification.setLatestEventInfo(getApplicationContext(), msgText,
+ file.getName(), contentIntent);
+ notification.flags = Notification.FLAG_AUTO_CANCEL;
+ nm.notify(NOTIFICATION_UPLOAD, notification);
+ Log.d(this.getClass().getName(), msgText);
+ }
+ catch (IOException e)
+ {
+ // Fehler ist aufgetreten.
+ final String msgText = getResources().getString(
+ R.string.upload_fail);
+ notification.tickerText = getResources().getString(
+ R.string.upload_fail_long);
+ notification.setLatestEventInfo(getApplicationContext(), msgText, e
+ .getMessage()
+ + ": " + file.getName(), contentIntent);
+ notification.flags = Notification.FLAG_AUTO_CANCEL;
+ nm.notify(NOTIFICATION_UPLOAD, notification);
+
+ Log.e(this.getClass().getName(), msgText, e);
+ }
+ finally
+ {
+ }
+ }
+}
diff --git a/src/de/openrat/android/blog/MyStreamReader.java b/src/de/openrat/android/blog/MyStreamReader.java
@@ -0,0 +1,35 @@
+package de.openrat.android.blog;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+public class MyStreamReader extends Reader
+{
+
+ private InputStream stream;
+
+ public MyStreamReader(InputStream inputStream)
+ {
+ this.stream = inputStream;
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ stream.close();
+ }
+
+ @Override
+ public int read(char[] buf, int offset, int count) throws IOException
+ {
+ if (count != 1 || buf.length != 1 || offset != 0)
+ throw new IOException("Buffer size must be 1");
+ byte[] b = new byte[1];
+ this.stream.read(b);
+ char c = (char) b[0];
+ buf[0] = c;
+ return 1;
+ }
+
+}
diff --git a/src/de/openrat/android/blog/UploadIntentService.java b/src/de/openrat/android/blog/UploadIntentService.java
@@ -0,0 +1,103 @@
+/**
+ *
+ */
+package de.openrat.android.blog;
+
+import java.io.File;
+import java.io.IOException;
+
+import android.app.IntentService;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+/**
+ * @author dankert
+ *
+ */
+public class UploadIntentService extends IntentService
+{
+
+ public static final String EXTRA_TITLE = "title";
+ public static final String EXTRA_TEXT = "text";
+ public static final String EXTRA_IMAGE = "image";
+
+ private static final int NOTIFICATION_UPLOAD = 1;
+
+ public UploadIntentService()
+ {
+ super("UploadIntentService");
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see android.app.IntentService#onHandleIntent(android.content.Intent)
+ */
+ @Override
+ protected void onHandleIntent(Intent intent)
+ {
+ final String filePath = intent.getStringExtra(EXTRA_IMAGE);
+
+ final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+
+ final Intent notificationIntent = new Intent(this, Blog.class);
+ final PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
+ notificationIntent, 0);
+
+ final File file = new File(filePath);
+ final String tickerText = getResources()
+ .getString(R.string.upload_long);
+ final Notification notification = new Notification(
+ android.R.drawable.ic_menu_rotate, tickerText, System
+ .currentTimeMillis());
+ notification.setLatestEventInfo(getApplicationContext(), getResources()
+ .getString(R.string.upload), file.getName(), contentIntent);
+ notification.flags = Notification.FLAG_ONGOING_EVENT
+ | Notification.FLAG_NO_CLEAR;
+ nm.notify(NOTIFICATION_UPLOAD, notification);
+
+ SharedPreferences prefs = PreferenceManager
+ .getDefaultSharedPreferences(this);
+
+ try
+ {
+ HTTPRequest request = new HTTPRequest();
+ request.setFile(prefs.getString("param_image", "image"), FileUtils
+ .getBytesFromFile(file), "image.png", "image/png", "binary");
+ // Alles OK.
+ final String msgText = getResources().getString(R.string.upload_ok);
+ notification.tickerText = getResources().getString(
+ R.string.upload_ok_long);
+ notification.setLatestEventInfo(getApplicationContext(), msgText,
+ file.getName(), contentIntent);
+ notification.flags = Notification.FLAG_AUTO_CANCEL;
+ nm.notify(NOTIFICATION_UPLOAD, notification);
+ Log.d(this.getClass().getName(), msgText);
+ }
+ catch (IOException e)
+ {
+ // Fehler ist aufgetreten.
+ final String msgText = getResources().getString(
+ R.string.upload_fail);
+ notification.tickerText = getResources().getString(
+ R.string.upload_fail_long);
+ notification.setLatestEventInfo(getApplicationContext(), msgText, e
+ .getMessage()
+ + ": " + file.getName(), contentIntent);
+ notification.flags = Notification.FLAG_AUTO_CANCEL;
+ nm.notify(NOTIFICATION_UPLOAD, notification);
+
+ Log.e(this.getClass().getName(), msgText, e);
+ }
+ finally
+ {
+ }
+ }
+}