Build the Android tutorial app by gradle
diff --git a/java/android/app/.gitignore b/java/android/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/java/android/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/java/android/app/build.gradle b/java/android/app/build.gradle
new file mode 100644
index 0000000..6940ad0
--- /dev/null
+++ b/java/android/app/build.gradle
@@ -0,0 +1,34 @@
+apply plugin: 'com.android.application'
+
+android {
+    compileSdkVersion 21
+    buildToolsVersion "21.1.2"
+
+    defaultConfig {
+        applicationId "io.grpc.helloworldexample"
+        minSdkVersion 7
+        targetSdkVersion 21
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+    compile 'com.android.support:appcompat-v7:21.0.3'
+    compile 'com.google.code.findbugs:jsr305:3.0.0'
+    compile 'com.squareup.okhttp:okhttp:2.2.0'
+    compile 'com.google.guava:guava:18.0'
+
+    // You need to build the https://github.com/grpc/grpc-java
+    // to obtain these libraries below.
+    compile 'io.grpc:grpc-core:0.1.0-SNAPSHOT'
+    compile 'io.grpc:grpc-nano:0.1.0-SNAPSHOT'
+    compile 'io.grpc:grpc-okhttp:0.1.0-SNAPSHOT'
+    compile 'io.grpc:grpc-stub:0.1.0-SNAPSHOT'
+}
diff --git a/java/android/app/proguard-rules.pro b/java/android/app/proguard-rules.pro
new file mode 100644
index 0000000..3e659b9
--- /dev/null
+++ b/java/android/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 /Users/thagikura/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/java/android/app/src/main/AndroidManifest.xml b/java/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..8c40f11
--- /dev/null
+++ b/java/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="io.grpc.helloworldexample" >
+
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/Base.V7.Theme.AppCompat.Light" >
+        <activity
+            android:name=".HelloworldActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/java/android/app/src/main/java/io/grpc/helloworldexample/GreeterGrpc.java b/java/android/app/src/main/java/io/grpc/helloworldexample/GreeterGrpc.java
new file mode 100644
index 0000000..595c140
--- /dev/null
+++ b/java/android/app/src/main/java/io/grpc/helloworldexample/GreeterGrpc.java
@@ -0,0 +1,179 @@
+package io.grpc.helloworldexample;
+
+import java.io.IOException;
+
+import static io.grpc.stub.Calls.asyncUnaryCall;
+import static io.grpc.stub.Calls.blockingUnaryCall;
+import static io.grpc.stub.Calls.createMethodDescriptor;
+import static io.grpc.stub.Calls.unaryFutureCall;
+import static io.grpc.stub.ServerCalls.asyncUnaryRequestCall;
+import static io.grpc.stub.ServerCalls.createMethodDefinition;
+
+public class GreeterGrpc {
+
+    private static final io.grpc.stub.Method<Helloworld.HelloRequest,
+            Helloworld.HelloReply> METHOD_SAY_HELLO =
+            io.grpc.stub.Method.create(
+                    io.grpc.MethodType.UNARY, "SayHello",
+                    io.grpc.nano.NanoUtils.<Helloworld.HelloRequest>marshaller(
+                            new io.grpc.nano.Parser<Helloworld.HelloRequest>() {
+                                @Override
+                                public Helloworld.HelloRequest parse(com.google.protobuf.nano.CodedInputByteBufferNano input) throws IOException {
+                                    return Helloworld.HelloRequest.parseFrom(input);
+                                }
+                            }),
+                    io.grpc.nano.NanoUtils.<Helloworld.HelloReply>marshaller(
+                            new io.grpc.nano.Parser<Helloworld.HelloReply>() {
+                                @Override
+                                public Helloworld.HelloReply parse(com.google.protobuf.nano.CodedInputByteBufferNano input) throws IOException {
+                                    return Helloworld.HelloReply.parseFrom(input);
+                                }
+                            }));
+
+    public static GreeterStub newStub(io.grpc.Channel channel) {
+        return new GreeterStub(channel, CONFIG);
+    }
+
+    public static GreeterBlockingStub newBlockingStub(
+            io.grpc.Channel channel) {
+        return new GreeterBlockingStub(channel, CONFIG);
+    }
+
+    public static GreeterFutureStub newFutureStub(
+            io.grpc.Channel channel) {
+        return new GreeterFutureStub(channel, CONFIG);
+    }
+
+    public static final GreeterServiceDescriptor CONFIG =
+            new GreeterServiceDescriptor();
+
+    public static class GreeterServiceDescriptor extends
+            io.grpc.stub.AbstractServiceDescriptor<GreeterServiceDescriptor> {
+        public final io.grpc.MethodDescriptor<Helloworld.HelloRequest,
+                Helloworld.HelloReply> sayHello;
+
+        private GreeterServiceDescriptor() {
+            sayHello = createMethodDescriptor(
+                    "helloworld.Greeter", METHOD_SAY_HELLO);
+        }
+
+        private GreeterServiceDescriptor(
+                java.util.Map<java.lang.String, io.grpc.MethodDescriptor<?, ?>> methodMap) {
+            sayHello = (io.grpc.MethodDescriptor<Helloworld.HelloRequest,
+                    Helloworld.HelloReply>) methodMap.get(
+                    CONFIG.sayHello.getName());
+        }
+
+        @java.lang.Override
+        protected GreeterServiceDescriptor build(
+                java.util.Map<java.lang.String, io.grpc.MethodDescriptor<?, ?>> methodMap) {
+            return new GreeterServiceDescriptor(methodMap);
+        }
+
+        @java.lang.Override
+        public com.google.common.collect.ImmutableList<io.grpc.MethodDescriptor<?, ?>> methods() {
+            return com.google.common.collect.ImmutableList.<io.grpc.MethodDescriptor<?, ?>>of(
+                    sayHello);
+        }
+    }
+
+    public static interface Greeter {
+
+        public void sayHello(Helloworld.HelloRequest request,
+                io.grpc.stub.StreamObserver<Helloworld.HelloReply> responseObserver);
+    }
+
+    public static interface GreeterBlockingClient {
+
+        public Helloworld.HelloReply sayHello(Helloworld.HelloRequest request);
+    }
+
+    public static interface GreeterFutureClient {
+
+        public com.google.common.util.concurrent.ListenableFuture<Helloworld.HelloReply> sayHello(
+                Helloworld.HelloRequest request);
+    }
+
+    public static class GreeterStub extends
+            io.grpc.stub.AbstractStub<GreeterStub, GreeterServiceDescriptor>
+            implements Greeter {
+        private GreeterStub(io.grpc.Channel channel,
+                GreeterServiceDescriptor config) {
+            super(channel, config);
+        }
+
+        @java.lang.Override
+        protected GreeterStub build(io.grpc.Channel channel,
+                GreeterServiceDescriptor config) {
+            return new GreeterStub(channel, config);
+        }
+
+        @java.lang.Override
+        public void sayHello(Helloworld.HelloRequest request,
+                io.grpc.stub.StreamObserver<Helloworld.HelloReply> responseObserver) {
+            asyncUnaryCall(
+                    channel.newCall(config.sayHello), request, responseObserver);
+        }
+    }
+
+    public static class GreeterBlockingStub extends
+            io.grpc.stub.AbstractStub<GreeterBlockingStub, GreeterServiceDescriptor>
+            implements GreeterBlockingClient {
+        private GreeterBlockingStub(io.grpc.Channel channel,
+                GreeterServiceDescriptor config) {
+            super(channel, config);
+        }
+
+        @java.lang.Override
+        protected GreeterBlockingStub build(io.grpc.Channel channel,
+                GreeterServiceDescriptor config) {
+            return new GreeterBlockingStub(channel, config);
+        }
+
+        @java.lang.Override
+        public Helloworld.HelloReply sayHello(Helloworld.HelloRequest request) {
+            return blockingUnaryCall(
+                    channel.newCall(config.sayHello), request);
+        }
+    }
+
+    public static class GreeterFutureStub extends
+            io.grpc.stub.AbstractStub<GreeterFutureStub, GreeterServiceDescriptor>
+            implements GreeterFutureClient {
+        private GreeterFutureStub(io.grpc.Channel channel,
+                GreeterServiceDescriptor config) {
+            super(channel, config);
+        }
+
+        @java.lang.Override
+        protected GreeterFutureStub build(io.grpc.Channel channel,
+                GreeterServiceDescriptor config) {
+            return new GreeterFutureStub(channel, config);
+        }
+
+        @java.lang.Override
+        public com.google.common.util.concurrent.ListenableFuture<Helloworld.HelloReply> sayHello(
+                Helloworld.HelloRequest request) {
+            return unaryFutureCall(
+                    channel.newCall(config.sayHello), request);
+        }
+    }
+
+    public static io.grpc.ServerServiceDefinition bindService(
+            final Greeter serviceImpl) {
+        return io.grpc.ServerServiceDefinition.builder("helloworld.Greeter")
+                .addMethod(createMethodDefinition(
+                        METHOD_SAY_HELLO,
+                        asyncUnaryRequestCall(
+                                new io.grpc.stub.ServerCalls.UnaryRequestMethod<
+                                        Helloworld.HelloRequest,
+                                        Helloworld.HelloReply>() {
+                                    @java.lang.Override
+                                    public void invoke(
+                                            Helloworld.HelloRequest request,
+                                            io.grpc.stub.StreamObserver<Helloworld.HelloReply> responseObserver) {
+                                        serviceImpl.sayHello(request, responseObserver);
+                                    }
+                                }))).build();
+    }
+}
\ No newline at end of file
diff --git a/java/android/app/src/main/java/io/grpc/helloworldexample/Helloworld.java b/java/android/app/src/main/java/io/grpc/helloworldexample/Helloworld.java
new file mode 100644
index 0000000..28da5a9
--- /dev/null
+++ b/java/android/app/src/main/java/io/grpc/helloworldexample/Helloworld.java
@@ -0,0 +1,175 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+
+package io.grpc.helloworldexample;
+
+@SuppressWarnings("hiding")
+public interface Helloworld {
+
+    public static final class HelloRequest extends
+            com.google.protobuf.nano.MessageNano {
+
+        private static volatile HelloRequest[] _emptyArray;
+        public static HelloRequest[] emptyArray() {
+            // Lazily initializes the empty array
+            if (_emptyArray == null) {
+                synchronized (
+                        com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) {
+                    if (_emptyArray == null) {
+                        _emptyArray = new HelloRequest[0];
+                    }
+                }
+            }
+            return _emptyArray;
+        }
+
+        // optional string name = 1;
+        public java.lang.String name;
+
+        public HelloRequest() {
+            clear();
+        }
+
+        public HelloRequest clear() {
+            name = "";
+            cachedSize = -1;
+            return this;
+        }
+
+        @Override
+        public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)
+                throws java.io.IOException {
+            if (!this.name.equals("")) {
+                output.writeString(1, this.name);
+            }
+            super.writeTo(output);
+        }
+
+        @Override
+        protected int computeSerializedSize() {
+            int size = super.computeSerializedSize();
+            if (!this.name.equals("")) {
+                size += com.google.protobuf.nano.CodedOutputByteBufferNano
+                        .computeStringSize(1, this.name);
+            }
+            return size;
+        }
+
+        @Override
+        public HelloRequest mergeFrom(
+                com.google.protobuf.nano.CodedInputByteBufferNano input)
+                throws java.io.IOException {
+            while (true) {
+                int tag = input.readTag();
+                switch (tag) {
+                    case 0:
+                        return this;
+                    default: {
+                        if (!com.google.protobuf.nano.WireFormatNano.parseUnknownField(input, tag)) {
+                            return this;
+                        }
+                        break;
+                    }
+                    case 10: {
+                        this.name = input.readString();
+                        break;
+                    }
+                }
+            }
+        }
+
+        public static HelloRequest parseFrom(byte[] data)
+                throws com.google.protobuf.nano.InvalidProtocolBufferNanoException {
+            return com.google.protobuf.nano.MessageNano.mergeFrom(new HelloRequest(), data);
+        }
+
+        public static HelloRequest parseFrom(
+                com.google.protobuf.nano.CodedInputByteBufferNano input)
+                throws java.io.IOException {
+            return new HelloRequest().mergeFrom(input);
+        }
+    }
+
+    public static final class HelloReply extends
+            com.google.protobuf.nano.MessageNano {
+
+        private static volatile HelloReply[] _emptyArray;
+        public static HelloReply[] emptyArray() {
+            // Lazily initializes the empty array
+            if (_emptyArray == null) {
+                synchronized (
+                        com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) {
+                    if (_emptyArray == null) {
+                        _emptyArray = new HelloReply[0];
+                    }
+                }
+            }
+            return _emptyArray;
+        }
+
+        // optional string message = 1;
+        public java.lang.String message;
+
+        public HelloReply() {
+            clear();
+        }
+
+        public HelloReply clear() {
+            message = "";
+            cachedSize = -1;
+            return this;
+        }
+
+        @Override
+        public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)
+                throws java.io.IOException {
+            if (!this.message.equals("")) {
+                output.writeString(1, this.message);
+            }
+            super.writeTo(output);
+        }
+
+        @Override
+        protected int computeSerializedSize() {
+            int size = super.computeSerializedSize();
+            if (!this.message.equals("")) {
+                size += com.google.protobuf.nano.CodedOutputByteBufferNano
+                        .computeStringSize(1, this.message);
+            }
+            return size;
+        }
+
+        @Override
+        public HelloReply mergeFrom(
+                com.google.protobuf.nano.CodedInputByteBufferNano input)
+                throws java.io.IOException {
+            while (true) {
+                int tag = input.readTag();
+                switch (tag) {
+                    case 0:
+                        return this;
+                    default: {
+                        if (!com.google.protobuf.nano.WireFormatNano.parseUnknownField(input, tag)) {
+                            return this;
+                        }
+                        break;
+                    }
+                    case 10: {
+                        this.message = input.readString();
+                        break;
+                    }
+                }
+            }
+        }
+
+        public static HelloReply parseFrom(byte[] data)
+                throws com.google.protobuf.nano.InvalidProtocolBufferNanoException {
+            return com.google.protobuf.nano.MessageNano.mergeFrom(new HelloReply(), data);
+        }
+
+        public static HelloReply parseFrom(
+                com.google.protobuf.nano.CodedInputByteBufferNano input)
+                throws java.io.IOException {
+            return new HelloReply().mergeFrom(input);
+        }
+    }
+}
\ No newline at end of file
diff --git a/java/android/app/src/main/java/io/grpc/helloworldexample/HelloworldActivity.java b/java/android/app/src/main/java/io/grpc/helloworldexample/HelloworldActivity.java
new file mode 100644
index 0000000..b6d734f
--- /dev/null
+++ b/java/android/app/src/main/java/io/grpc/helloworldexample/HelloworldActivity.java
@@ -0,0 +1,90 @@
+package io.grpc.helloworldexample;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v7.app.ActionBarActivity;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.util.concurrent.TimeUnit;
+
+import io.grpc.ChannelImpl;
+import io.grpc.helloworldexample.Helloworld.HelloReply;
+import io.grpc.helloworldexample.Helloworld.HelloRequest;
+import io.grpc.transport.okhttp.OkHttpChannelBuilder;
+
+public class HelloworldActivity extends ActionBarActivity {
+    private Button mSendButton;
+    private EditText mHostEdit;
+    private EditText mPortEdit;
+    private EditText mMessageEdit;
+    private TextView mResultText;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_helloworld);
+        mSendButton = (Button) findViewById(R.id.send_button);
+        mHostEdit = (EditText) findViewById(R.id.host_edit_text);
+        mPortEdit = (EditText) findViewById(R.id.port_edit_text);
+        mMessageEdit = (EditText) findViewById(R.id.message_edit_text);
+        mResultText = (TextView) findViewById(R.id.grpc_response_text);
+    }
+
+    public void sendMessage(View view) {
+        ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE))
+                .hideSoftInputFromWindow(mHostEdit.getWindowToken(), 0);
+        mSendButton.setEnabled(false);
+        new GrpcTask().execute();
+    }
+
+    private class GrpcTask extends AsyncTask<Void, Void, String> {
+        private String mHost;
+        private String mMessage;
+        private int mPort;
+        private ChannelImpl mChannel;
+
+        @Override
+        protected void onPreExecute() {
+            mHost = mHostEdit.getText().toString();
+            mMessage = mMessageEdit.getText().toString();
+            String portStr = mPortEdit.getText().toString();
+            mPort = TextUtils.isEmpty(portStr) ? 0 : Integer.valueOf(portStr);
+            mResultText.setText("");
+        }
+
+        private String sayHello(ChannelImpl channel) {
+            GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel);
+            HelloRequest message = new HelloRequest();
+            message.name = mMessage;
+            HelloReply reply = stub.sayHello(message);
+            return reply.message;
+        }
+
+        @Override
+        protected String doInBackground(Void... nothing) {
+            try {
+                mChannel = OkHttpChannelBuilder.forAddress(mHost, mPort).build();
+                return sayHello(mChannel);
+            } catch (Exception e) {
+                return "Failed... : " + e.getMessage();
+            }
+        }
+
+        @Override
+        protected void onPostExecute(String result) {
+            try {
+                mChannel.shutdown().awaitTerminated(1, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+            }
+            mResultText.setText(result);
+            mSendButton.setEnabled(true);
+        }
+    }
+}
\ No newline at end of file
diff --git a/java/android/app/src/main/res/layout/activity_helloworld.xml b/java/android/app/src/main/res/layout/activity_helloworld.xml
new file mode 100644
index 0000000..00ca04c
--- /dev/null
+++ b/java/android/app/src/main/res/layout/activity_helloworld.xml
@@ -0,0 +1,54 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              tools:context=".MainActivity"
+              android:orientation="vertical" >
+
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+        <EditText
+                android:id="@+id/host_edit_text"
+                android:layout_weight="2"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:hint="Enter Host" />
+        <EditText
+                android:id="@+id/port_edit_text"
+                android:layout_weight="1"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:inputType="numberDecimal"
+                android:hint="Enter Port" />
+    </LinearLayout>
+
+
+    <EditText
+            android:id="@+id/message_edit_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:hint="Enter message to send" />
+
+    <Button
+            android:id="@+id/send_button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:onClick="sendMessage"
+            android:text="Send Grpc Request" />
+
+    <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="12dp"
+            android:paddingBottom="12dp"
+            android:textSize="16dp"
+            android:text="Response:" />
+
+    <TextView
+            android:id="@+id/grpc_response_text"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:textSize="16dp" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/java/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/java/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/java/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/java/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/java/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/java/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/java/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/java/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/java/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/java/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/java/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/java/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/java/android/app/src/main/res/values/strings.xml b/java/android/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..64cb312
--- /dev/null
+++ b/java/android/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">GrpcHelloworldExample</string>
+</resources>