diff --git a/examples/android/.gitignore b/examples/android/helloworld/.gitignore similarity index 100% rename from examples/android/.gitignore rename to examples/android/helloworld/.gitignore diff --git a/examples/android/README.md b/examples/android/helloworld/README.md similarity index 100% rename from examples/android/README.md rename to examples/android/helloworld/README.md diff --git a/examples/android/app/build.gradle b/examples/android/helloworld/app/build.gradle similarity index 100% rename from examples/android/app/build.gradle rename to examples/android/helloworld/app/build.gradle diff --git a/examples/android/app/proguard-rules.pro b/examples/android/helloworld/app/proguard-rules.pro similarity index 100% rename from examples/android/app/proguard-rules.pro rename to examples/android/helloworld/app/proguard-rules.pro diff --git a/examples/android/app/src/main/AndroidManifest.xml b/examples/android/helloworld/app/src/main/AndroidManifest.xml similarity index 100% rename from examples/android/app/src/main/AndroidManifest.xml rename to examples/android/helloworld/app/src/main/AndroidManifest.xml diff --git a/examples/android/app/src/main/java/io/grpc/helloworldexample/HelloworldActivity.java b/examples/android/helloworld/app/src/main/java/io/grpc/helloworldexample/HelloworldActivity.java similarity index 100% rename from examples/android/app/src/main/java/io/grpc/helloworldexample/HelloworldActivity.java rename to examples/android/helloworld/app/src/main/java/io/grpc/helloworldexample/HelloworldActivity.java diff --git a/examples/android/app/src/main/proto/helloworld.proto b/examples/android/helloworld/app/src/main/proto/helloworld.proto similarity index 100% rename from examples/android/app/src/main/proto/helloworld.proto rename to examples/android/helloworld/app/src/main/proto/helloworld.proto diff --git a/examples/android/app/src/main/res/layout/activity_helloworld.xml b/examples/android/helloworld/app/src/main/res/layout/activity_helloworld.xml similarity index 100% rename from examples/android/app/src/main/res/layout/activity_helloworld.xml rename to examples/android/helloworld/app/src/main/res/layout/activity_helloworld.xml diff --git a/examples/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/examples/android/helloworld/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from examples/android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to examples/android/helloworld/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/examples/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/examples/android/helloworld/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from examples/android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to examples/android/helloworld/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/examples/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/examples/android/helloworld/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from examples/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to examples/android/helloworld/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/examples/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/examples/android/helloworld/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from examples/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to examples/android/helloworld/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/examples/android/app/src/main/res/values/strings.xml b/examples/android/helloworld/app/src/main/res/values/strings.xml similarity index 100% rename from examples/android/app/src/main/res/values/strings.xml rename to examples/android/helloworld/app/src/main/res/values/strings.xml diff --git a/examples/android/build.gradle b/examples/android/helloworld/build.gradle similarity index 100% rename from examples/android/build.gradle rename to examples/android/helloworld/build.gradle diff --git a/examples/android/gradle/wrapper/gradle-wrapper.jar b/examples/android/helloworld/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from examples/android/gradle/wrapper/gradle-wrapper.jar rename to examples/android/helloworld/gradle/wrapper/gradle-wrapper.jar diff --git a/examples/android/gradle/wrapper/gradle-wrapper.properties b/examples/android/helloworld/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from examples/android/gradle/wrapper/gradle-wrapper.properties rename to examples/android/helloworld/gradle/wrapper/gradle-wrapper.properties diff --git a/examples/android/gradlew b/examples/android/helloworld/gradlew similarity index 100% rename from examples/android/gradlew rename to examples/android/helloworld/gradlew diff --git a/examples/android/gradlew.bat b/examples/android/helloworld/gradlew.bat similarity index 100% rename from examples/android/gradlew.bat rename to examples/android/helloworld/gradlew.bat diff --git a/examples/android/settings.gradle b/examples/android/helloworld/settings.gradle similarity index 100% rename from examples/android/settings.gradle rename to examples/android/helloworld/settings.gradle diff --git a/examples/android/routeguide/.gitignore b/examples/android/routeguide/.gitignore new file mode 100644 index 0000000000..6345b76a48 --- /dev/null +++ b/examples/android/routeguide/.gitignore @@ -0,0 +1,21 @@ +.gradle +/local.properties +/gradle.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +.idea/ + +*.iml +*.apk +*.ap_ +*.dex +*.class +bin/ +gen/ +.gradle/ +/*/build/ +local.properties +proguard/ +*.log diff --git a/examples/android/app/.gitignore b/examples/android/routeguide/app/.gitignore similarity index 100% rename from examples/android/app/.gitignore rename to examples/android/routeguide/app/.gitignore diff --git a/examples/android/routeguide/app/build.gradle b/examples/android/routeguide/app/build.gradle new file mode 100644 index 0000000000..806fbc41a1 --- /dev/null +++ b/examples/android/routeguide/app/build.gradle @@ -0,0 +1,67 @@ +apply plugin: 'com.android.application' +apply plugin: 'com.google.protobuf' + +android { + compileSdkVersion 23 + buildToolsVersion "24.0.0" + + defaultConfig { + applicationId "io.grpc.routeguideexample" + minSdkVersion 23 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + lintOptions { + disable 'InvalidPackage' + } +} + +protobuf { + protoc { + artifact = 'com.google.protobuf:protoc:3.0.0-beta-3' + } + plugins { + grpc { + artifact = 'io.grpc:protoc-gen-grpc-java:1.1.0-SNAPSHOT' // CURRENT_GRPC_VERSION + } + } + generateProtoTasks { + all().each { task -> + task.builtins { + // Javanano is installed by default, but needs to be removed to use protobuf lite.. + remove javanano + java { + // Options added to --java_out + option 'lite' + } + } + + task.plugins { + grpc { + // Options added to --grpc_out + option 'lite' + } + } + } + } +} + +dependencies { + compile 'com.android.support:appcompat-v7:23.+' + compile 'com.google.code.findbugs:jsr305:3.0.0' + compile 'com.google.guava:guava:18.0' + compile 'com.squareup.okhttp:okhttp:2.2.0' + + // You need to build grpc-java to obtain these libraries below. + compile 'io.grpc:grpc-okhttp:1.1.0-SNAPSHOT' // CURRENT_GRPC_VERSION + compile 'io.grpc:grpc-protobuf-lite:1.1.0-SNAPSHOT' // CURRENT_GRPC_VERSION + compile 'io.grpc:grpc-stub:1.1.0-SNAPSHOT' // CURRENT_GRPC_VERSION + compile 'javax.annotation:javax.annotation-api:1.2' +} diff --git a/examples/android/routeguide/app/proguard-rules.pro b/examples/android/routeguide/app/proguard-rules.pro new file mode 100644 index 0000000000..34ff0b3a7b --- /dev/null +++ b/examples/android/routeguide/app/proguard-rules.pro @@ -0,0 +1,15 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /usr/local/google/home/rocking/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: + +-dontwarn sun.misc.Unsafe +-dontwarn com.google.common.** +-dontwarn okio.** + diff --git a/examples/android/routeguide/app/src/main/AndroidManifest.xml b/examples/android/routeguide/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..d557afc085 --- /dev/null +++ b/examples/android/routeguide/app/src/main/AndroidManifest.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + diff --git a/examples/android/routeguide/app/src/main/java/io/grpc/routeguideexample/RouteGuideActivity.java b/examples/android/routeguide/app/src/main/java/io/grpc/routeguideexample/RouteGuideActivity.java new file mode 100644 index 0000000000..432e338ff0 --- /dev/null +++ b/examples/android/routeguide/app/src/main/java/io/grpc/routeguideexample/RouteGuideActivity.java @@ -0,0 +1,432 @@ +/* + * Copyright 2016, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.grpc.routeguideexample; + +import android.content.Context; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import android.text.method.ScrollingMovementMethod; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import io.grpc.routeguideexample.RouteGuideGrpc.RouteGuideBlockingStub; +import io.grpc.routeguideexample.RouteGuideGrpc.RouteGuideStub; +import io.grpc.stub.StreamObserver; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class RouteGuideActivity extends AppCompatActivity { + private static final Logger logger = Logger.getLogger(RouteGuideActivity.class.getName()); + private EditText mHostEdit; + private EditText mPortEdit; + private Button mStartRouteGuideButton; + private Button mExitRouteGuideButton; + private Button mGetFeatureButton; + private Button mListFeaturesButton; + private Button mRecordRouteButton; + private Button mRouteChatButton; + private TextView mResultText; + + private ManagedChannel mChannel; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_routeguide); + mHostEdit = (EditText) findViewById(R.id.host_edit_text); + mPortEdit = (EditText) findViewById(R.id.port_edit_text); + mStartRouteGuideButton = (Button) findViewById(R.id.start_route_guide_button); + mExitRouteGuideButton = (Button) findViewById(R.id.exit_route_guide_button); + mGetFeatureButton = (Button) findViewById(R.id.get_feature_button); + mListFeaturesButton = (Button) findViewById(R.id.list_features_button); + mRecordRouteButton = (Button) findViewById(R.id.record_route_button); + mRouteChatButton = (Button) findViewById(R.id.route_chat_button); + mResultText = (TextView) findViewById(R.id.result_text); + mResultText.setMovementMethod(new ScrollingMovementMethod()); + disableButtons(); + } + + public void startRouteGuide(View view) { + String host = mHostEdit.getText().toString(); + String portStr = mPortEdit.getText().toString(); + int port = TextUtils.isEmpty(portStr) ? 0 : Integer.valueOf(portStr); + ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)) + .hideSoftInputFromWindow(mHostEdit.getWindowToken(), 0); + mChannel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build(); + mHostEdit.setEnabled(false); + mPortEdit.setEnabled(false); + mStartRouteGuideButton.setEnabled(false); + enableButtons(); + } + + public void exitRouteGuide(View view) { + mChannel.shutdown(); + disableButtons(); + mHostEdit.setEnabled(true); + mPortEdit.setEnabled(true); + mStartRouteGuideButton.setEnabled(true); + } + + public void getFeature(View view) { + new GrpcTask(new GetFeatureRunnable()).execute(); + } + + public void listFeatures(View view) { + new GrpcTask(new ListFeaturesRunnable()).execute(); + } + + public void recordRoute(View view) { + new GrpcTask(new RecordRouteRunnable()).execute(); + } + + public void routeChat(View view) { + new GrpcTask(new RouteChatRunnable()).execute(); + } + + private void disableButtons() { + mGetFeatureButton.setEnabled(false); + mListFeaturesButton.setEnabled(false); + mRecordRouteButton.setEnabled(false); + mRouteChatButton.setEnabled(false); + mExitRouteGuideButton.setEnabled(false); + } + + private void enableButtons() { + mExitRouteGuideButton.setEnabled(true); + mGetFeatureButton.setEnabled(true); + mListFeaturesButton.setEnabled(true); + mRecordRouteButton.setEnabled(true); + mRouteChatButton.setEnabled(true); + } + + private class GrpcTask extends AsyncTask { + private final GrpcRunnable mGrpc; + + GrpcTask(GrpcRunnable grpc) { + this.mGrpc = grpc; + } + + @Override + protected void onPreExecute() { + mResultText.setText(""); + disableButtons(); + } + + @Override + protected String doInBackground(Void... nothing) { + try { + String logs = mGrpc.run(RouteGuideGrpc.newBlockingStub(mChannel), + RouteGuideGrpc.newStub(mChannel)); + return "Success!" + System.lineSeparator() + logs; + } catch (Exception e) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); + return "Failed... : " + System.lineSeparator() + sw; + } + } + + @Override + protected void onPostExecute(String result) { + mResultText.setText(result); + enableButtons(); + } + } + + private interface GrpcRunnable { + /** + * Perform a grpc and return all the logs. + */ + String run(RouteGuideBlockingStub blockingStub, RouteGuideStub asyncStub) throws Exception; + } + + private class GetFeatureRunnable implements GrpcRunnable { + @Override + public String run(RouteGuideBlockingStub blockingStub, RouteGuideStub asyncStub) + throws Exception { + return getFeature(409146138, -746188906, blockingStub); + } + + /** + * Blocking unary call example. Calls getFeature and prints the response. + */ + private String getFeature(int lat, int lon, RouteGuideBlockingStub blockingStub) + throws StatusRuntimeException { + StringBuffer logs = new StringBuffer(); + appendLogs(logs, "*** GetFeature: lat={0} lon={1}", lat, lon); + + Point request = Point.newBuilder().setLatitude(lat).setLongitude(lon).build(); + + Feature feature; + feature = blockingStub.getFeature(request); + if (RouteGuideUtil.exists(feature)) { + appendLogs(logs, "Found feature called \"{0}\" at {1}, {2}", + feature.getName(), + RouteGuideUtil.getLatitude(feature.getLocation()), + RouteGuideUtil.getLongitude(feature.getLocation())); + } else { + appendLogs(logs, "Found no feature at {0}, {1}", + RouteGuideUtil.getLatitude(feature.getLocation()), + RouteGuideUtil.getLongitude(feature.getLocation())); + } + return logs.toString(); + } + } + + private class ListFeaturesRunnable implements GrpcRunnable { + @Override + public String run(RouteGuideBlockingStub blockingStub, RouteGuideStub asyncStub) + throws Exception { + return listFeatures(400000000, -750000000, 420000000, -730000000, blockingStub); + } + + /** + * Blocking server-streaming example. Calls listFeatures with a rectangle of interest. + * Prints each response feature as it arrives. + */ + private String listFeatures(int lowLat, int lowLon, int hiLat, int hiLon, + RouteGuideBlockingStub blockingStub) throws StatusRuntimeException { + StringBuffer logs = new StringBuffer("Result: "); + appendLogs(logs, "*** ListFeatures: lowLat={0} lowLon={1} hiLat={2} hiLon={3}", + lowLat, lowLon, hiLat, hiLon); + + Rectangle request = Rectangle.newBuilder() + .setLo(Point.newBuilder().setLatitude(lowLat).setLongitude(lowLon).build()) + .setHi(Point.newBuilder().setLatitude(hiLat).setLongitude(hiLon).build()) + .build(); + Iterator features; + features = blockingStub.listFeatures(request); + + while (features.hasNext()) { + Feature feature = features.next(); + appendLogs(logs, feature.toString()); + } + return logs.toString(); + } + } + + private class RecordRouteRunnable implements GrpcRunnable { + private Throwable failed; + + @Override + public String run(RouteGuideBlockingStub blockingStub, RouteGuideStub asyncStub) + throws Exception { + List points = new ArrayList(); + points.add(Point.newBuilder() + .setLatitude(407838351).setLongitude(-746143763).build()); + points.add(Point.newBuilder() + .setLatitude(408122808).setLongitude(-743999179).build()); + points.add(Point.newBuilder() + .setLatitude(413628156).setLongitude(-749015468).build()); + return recordRoute(points, 5, asyncStub); + } + + /** + * Async client-streaming example. Sends {@code numPoints} randomly chosen points from + * {@code features} with a variable delay in between. Prints the statistics when they are + * sent from the server. + */ + private String recordRoute(List points, int numPoints, RouteGuideStub asyncStub) + throws InterruptedException, RuntimeException { + final StringBuffer logs = new StringBuffer(); + appendLogs(logs, "*** RecordRoute"); + + final CountDownLatch finishLatch = new CountDownLatch(1); + StreamObserver responseObserver = new StreamObserver() { + @Override + public void onNext(RouteSummary summary) { + appendLogs(logs, "Finished trip with {0} points. Passed {1} features. " + + "Travelled {2} meters. It took {3} seconds.", summary.getPointCount(), + summary.getFeatureCount(), summary.getDistance(), + summary.getElapsedTime()); + } + + @Override + public void onError(Throwable t) { + failed = t; + finishLatch.countDown(); + } + + @Override + public void onCompleted() { + appendLogs(logs, "Finished RecordRoute"); + finishLatch.countDown(); + } + }; + + StreamObserver requestObserver = asyncStub.recordRoute(responseObserver); + try { + // Send numPoints points randomly selected from the points list. + Random rand = new Random(); + for (int i = 0; i < numPoints; ++i) { + int index = rand.nextInt(points.size()); + Point point = points.get(index); + appendLogs(logs, "Visiting point {0}, {1}", RouteGuideUtil.getLatitude(point), + RouteGuideUtil.getLongitude(point)); + requestObserver.onNext(point); + // Sleep for a bit before sending the next one. + Thread.sleep(rand.nextInt(1000) + 500); + if (finishLatch.getCount() == 0) { + // RPC completed or errored before we finished sending. + // Sending further requests won't error, but they will just be thrown away. + break; + } + } + } catch (RuntimeException e) { + // Cancel RPC + requestObserver.onError(e); + throw e; + } + // Mark the end of requests + requestObserver.onCompleted(); + + // Receiving happens asynchronously + if (!finishLatch.await(1, TimeUnit.MINUTES)) { + throw new RuntimeException( + "Could not finish rpc within 1 minute, the server is likely down"); + } + + if (failed != null) { + throw new RuntimeException(failed); + } + return logs.toString(); + } + } + + private class RouteChatRunnable implements GrpcRunnable { + private Throwable failed; + + @Override + public String run(RouteGuideBlockingStub blockingStub, RouteGuideStub asyncStub) + throws Exception { + return routeChat(asyncStub); + } + + /** + * Bi-directional example, which can only be asynchronous. Send some chat messages, and + * print any chat messages that are sent from the server. + */ + private String routeChat(RouteGuideStub asyncStub) throws InterruptedException, + RuntimeException { + final StringBuffer logs = new StringBuffer(); + appendLogs(logs, "*** RouteChat"); + final CountDownLatch finishLatch = new CountDownLatch(1); + StreamObserver requestObserver = + asyncStub.routeChat(new StreamObserver() { + @Override + public void onNext(RouteNote note) { + appendLogs(logs, "Got message \"{0}\" at {1}, {2}", note.getMessage(), + note.getLocation().getLatitude(), + note.getLocation().getLongitude()); + } + + @Override + public void onError(Throwable t) { + failed = t; + finishLatch.countDown(); + } + + @Override + public void onCompleted() { + appendLogs(logs,"Finished RouteChat"); + finishLatch.countDown(); + } + }); + + try { + RouteNote[] requests = + {newNote("First message", 0, 0), newNote("Second message", 0, 1), + newNote("Third message", 1, 0), newNote("Fourth message", 1, 1)}; + + for (RouteNote request : requests) { + appendLogs(logs, "Sending message \"{0}\" at {1}, {2}", request.getMessage(), + request.getLocation().getLatitude(), + request.getLocation().getLongitude()); + requestObserver.onNext(request); + } + } catch (RuntimeException e) { + // Cancel RPC + requestObserver.onError(e); + throw e; + } + // Mark the end of requests + requestObserver.onCompleted(); + + // Receiving happens asynchronously + if (!finishLatch.await(1, TimeUnit.MINUTES)) { + throw new RuntimeException( + "Could not finish rpc within 1 minute, the server is likely down"); + } + + if (failed != null) { + throw new RuntimeException(failed); + } + + return logs.toString(); + } + } + + private static void appendLogs(StringBuffer logs, String msg, Object... params) { + if (params.length > 0) { + logs.append(MessageFormat.format(msg, params)); + } else { + logs.append(msg); + } + logs.append(System.lineSeparator()); + } + + private static RouteNote newNote(String message, int lat, int lon) { + return RouteNote.newBuilder().setMessage(message) + .setLocation(Point.newBuilder().setLatitude(lat).setLongitude(lon).build()).build(); + } +} diff --git a/examples/android/routeguide/app/src/main/java/io/grpc/routeguideexample/RouteGuideUtil.java b/examples/android/routeguide/app/src/main/java/io/grpc/routeguideexample/RouteGuideUtil.java new file mode 100644 index 0000000000..775f1beb9f --- /dev/null +++ b/examples/android/routeguide/app/src/main/java/io/grpc/routeguideexample/RouteGuideUtil.java @@ -0,0 +1,67 @@ +/* + * Copyright 2015, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.grpc.routeguideexample; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.util.List; + +/** + * Common utilities for the RouteGuide demo. + */ +public class RouteGuideUtil { + private static final double COORD_FACTOR = 1e7; + + /** + * Gets the latitude for the given point. + */ + public static double getLatitude(Point location) { + return location.getLatitude() / COORD_FACTOR; + } + + /** + * Gets the longitude for the given point. + */ + public static double getLongitude(Point location) { + return location.getLongitude() / COORD_FACTOR; + } + + /** + * Indicates whether the given feature exists (i.e. has a valid name). + */ + public static boolean exists(Feature feature) { + return feature != null && !feature.getName().isEmpty(); + } +} diff --git a/examples/android/routeguide/app/src/main/proto/route_guide.proto b/examples/android/routeguide/app/src/main/proto/route_guide.proto new file mode 100644 index 0000000000..f765fc5e16 --- /dev/null +++ b/examples/android/routeguide/app/src/main/proto/route_guide.proto @@ -0,0 +1,131 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.grpc.routeguideexample"; +option java_outer_classname = "RouteGuideProto"; +option objc_class_prefix = "RTG"; + +package routeguide; + +// Interface exported by the server. +service RouteGuide { + // A simple RPC. + // + // Obtains the feature at a given position. + // + // A feature with an empty name is returned if there's no feature at the given + // position. + rpc GetFeature(Point) returns (Feature) {} + + // A server-to-client streaming RPC. + // + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} + + // A client-to-server streaming RPC. + // + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} + + // A Bidirectional streaming RPC. + // + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +} + +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + int32 latitude = 1; + int32 longitude = 2; +} + +// A latitude-longitude rectangle, represented as two diagonally opposite +// points "lo" and "hi". +message Rectangle { + // One corner of the rectangle. + Point lo = 1; + + // The other corner of the rectangle. + Point hi = 2; +} + +// A feature names something at a given point. +// +// If a feature could not be named, the name is empty. +message Feature { + // The name of the feature. + string name = 1; + + // The point where the feature is detected. + Point location = 2; +} + +// Not used in the RPC. Instead, this is here for the form serialized to disk. +message FeatureDatabase { + repeated Feature feature = 1; +} + +// A RouteNote is a message sent while at a given point. +message RouteNote { + // The location from which the message is sent. + Point location = 1; + + // The message to be sent. + string message = 2; +} + +// A RouteSummary is received in response to a RecordRoute rpc. +// +// It contains the number of individual points received, the number of +// detected features, and the total distance covered as the cumulative sum of +// the distance between each point. +message RouteSummary { + // The number of points received. + int32 point_count = 1; + + // The number of known features passed while traversing the route. + int32 feature_count = 2; + + // The distance covered in metres. + int32 distance = 3; + + // The duration of the traversal in seconds. + int32 elapsed_time = 4; +} diff --git a/examples/android/routeguide/app/src/main/res/layout/activity_routeguide.xml b/examples/android/routeguide/app/src/main/res/layout/activity_routeguide.xml new file mode 100644 index 0000000000..4b73bf34ab --- /dev/null +++ b/examples/android/routeguide/app/src/main/res/layout/activity_routeguide.xml @@ -0,0 +1,81 @@ + + + + + + + + +