├── .gitignore ├── .travis.yml ├── LICENSE.md ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── build.gradle ├── ic_launcher-web.png ├── proguard-project.txt └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── directions │ └── route │ ├── AbstractRouting.java │ ├── GoogleParser.java │ ├── Parser.java │ ├── Route.java │ ├── RouteException.java │ ├── Routing.java │ ├── RoutingListener.java │ ├── Segment.java │ └── XMLParser.java ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── directions │ │ └── sample │ │ ├── MainActivity.java │ │ ├── PlaceAutoCompleteAdapter.java │ │ └── Util.java │ └── res │ ├── drawable-xhdpi │ ├── Thumbs.db │ ├── end_green.png │ ├── ic_send_grey600_48dp.png │ ├── pushpin.png │ └── start_blue.png │ ├── drawable │ ├── Thumbs.db │ └── dotted.xml │ ├── layout │ └── activity_main.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── screenshots ├── Thumbs.db ├── device-2015-06-30-095135.png ├── device-2015-06-30-095241.png ├── device-2015-06-30-095323.png └── device-2015-06-30-100949.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | 16 | # Local configuration file (sdk path, etc) 17 | local.properties 18 | 19 | # Eclipse project files 20 | .classpath 21 | .project 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Intellij project files 27 | *.iml 28 | *.ipr 29 | *.iws 30 | .idea/ 31 | build 32 | 33 | # Stupid MAC 34 | .DS_STORE 35 | 36 | # gradle 37 | .gradle 38 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | before_install: 2 | - chmod +x gradlew 3 | 4 | language: android 5 | android: 6 | components: 7 | - build-tools-22.0.1 8 | - android-22 9 | - extra 10 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Joel Dean 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Google-Directions-Android 2 | ========================= 3 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.jd-alexander/library/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/com.github.jd-alexander/library/) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Google--Directions--Android-green.svg?style=flat)](https://android-arsenal.com/details/1/2090) [![Build Status](https://travis-ci.org/jd-alexander/Google-Directions-Android.svg?branch=master)](https://travis-ci.org/jd-alexander/Google-Directions-Android) 4 | 5 | This project allows you to calculate the direction between two locations and display the route on a Google Map using the Google Directions API - This project isn't actively been maintained. 6 | 7 | 8 | 9 | ![Example Image][1] 10 | 11 | Sample 12 | ------------ 13 | 14 | The sample makes use of the Google Places API for Android in order to provide a real life example of how the library can be used.[You can check it out on the store.](https://play.google.com/store/apps/details?id=com.directions.sample) 15 | 16 | Download 17 | -------- 18 | 19 | 20 | Grab via Maven: 21 | ```xml 22 | 23 | com.github.jd-alexander 24 | library 25 | 1.1.0 26 | 27 | ``` 28 | or Gradle: 29 | ```groovy 30 | compile 'com.github.jd-alexander:library:1.1.0' 31 | ``` 32 | 33 | Usage 34 | ----- 35 | 36 | To calculate the route you simply instantiate a Routing object and trigger the execute function. 37 | 38 | 39 | *You can execute the task in this manner. ( See the example for more details on the exact implementation) 40 | 41 | 42 | 43 | ``` java 44 | 45 | Routing routing = new Routing.Builder() 46 | .travelMode(/* Travel Mode */) 47 | .withListener(/* Listener that delivers routing results.*/) 48 | .waypoints(/*waypoints*/) 49 | .key(/*api key for quota management*/) 50 | .build(); 51 | routing.execute(); 52 | 53 | ``` 54 | 55 | 56 | 57 | actual code 58 | ``` java 59 | start = new LatLng(18.015365, -77.499382); 60 | waypoint= new LatLng(18.01455, -77.499333); 61 | end = new LatLng(18.012590, -77.500659); 62 | 63 | Routing routing = new Routing.Builder() 64 | .travelMode(Routing.TravelMode.WALKING) 65 | .withListener(this) 66 | .waypoints(start, waypoint, end) 67 | .build(); 68 | routing.execute(); 69 | 70 | ..... 71 | 72 | @Override 73 | public void onRoutingSuccess(ArrayList route, int shortestRouteIndex) 74 | { 75 | //code to add route to map here. See sample app for more details. 76 | } 77 | ``` 78 | 79 | Demostration 80 | ------------ 81 | * https://www.youtube.com/watch?v=58AxNh2cWRU 82 | 83 | Demo App 84 | ------------ 85 | * https://github.com/hamza-ameer/GoogleMaps-Find-Routes/tree/Updated 86 | 87 | 88 | Known Issues 89 | ------------ 90 | * If the AutoComplete TextView/Map of the sample app isnt working then probably the API key hasn't been set in the manifest. 91 | 92 | * If the route is not being displayed then type "Routing" in your log cat to see the potential error messages from the library. 93 | 94 | 95 | Contribution 96 | ------------ 97 | 98 | Please fork repository and contribute using pull requests. 99 | 100 | Any contributions, large or small, major features, bug fixes, additional language translations, unit/integration tests are welcomed and appreciated but will be thoroughly reviewed and discussed. 101 | 102 | Contributors 103 | ------------ 104 | * [Cyrille Berliat](https://github.com/licryle) 105 | * [Felipe Duarte](https://github.com/fcduarte) 106 | * [Kedar Sarmalkar](https://github.com/ksarmalkar) 107 | * [Fernando Gil](https://github.com/fgil) 108 | * [Furkan Tektas](https://github.com/furkantektas) 109 | * [João Pedro Nardari dos Santos](https://github.com/joaopedronardari) 110 | * [Hesham Saeed](https://github.com/HeshamSaeed) 111 | 112 | License 113 | -------- 114 | 115 | Copyright 2016 Joel Dean 116 | 117 | Licensed under the Apache License, Version 2.0 (the "License"); 118 | you may not use this file except in compliance with the License. 119 | You may obtain a copy of the License at 120 | 121 | http://www.apache.org/licenses/LICENSE-2.0 122 | 123 | Unless required by applicable law or agreed to in writing, software 124 | distributed under the License is distributed on an "AS IS" BASIS, 125 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 126 | See the License for the specific language governing permissions and 127 | limitations under the License. 128 | 129 | 130 | 131 | 132 | 133 | 134 | [1]:http://i57.tinypic.com/2m7j04x.png 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:1.1.2' 7 | classpath 'com.github.dcendents:android-maven-plugin:1.2' 8 | classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.1" 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Jan 26 22:38:14 EST 2014 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | apply plugin: "com.jfrog.bintray" 4 | 5 | 6 | dependencies { 7 | compile fileTree(dir: 'libs', include: '*.jar') 8 | compile 'com.google.android.gms:play-services-maps:8.4.0' 9 | } 10 | // This is the library version used when deploying the artifact 11 | version = "1.0.9" 12 | 13 | android { 14 | compileSdkVersion 22 15 | buildToolsVersion "22.0.1" 16 | 17 | defaultConfig { 18 | minSdkVersion 10 19 | targetSdkVersion 22 20 | } 21 | } 22 | 23 | 24 | 25 | def siteUrl = 'https://github.com/jd-alexander/Google-Directions-Android' // Homepage URL of the library 26 | def gitUrl = 'https://github.com/jd-alexander/Google-Directions-Android.git' // Git repository URL 27 | group = "com.github.jd-alexander" // Maven Group ID for the artifact 28 | 29 | 30 | install { 31 | repositories.mavenInstaller { 32 | // This generates POM.xml with proper parameters 33 | pom { 34 | project { 35 | packaging 'aar' 36 | 37 | // Add your description here 38 | name 'Google Directions Android' 39 | description = 'This project allows you to calculate the route between two locations and displays it on a map.' 40 | 41 | url siteUrl 42 | 43 | // Set your license 44 | licenses { 45 | license { 46 | name 'The Apache Software License, Version 2.0' 47 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 48 | } 49 | } 50 | developers { 51 | developer { 52 | id 'com.github.jd-alexander ' 53 | name 'Joel Dean' 54 | email 'jdeanjj1000@gmail.com' 55 | } 56 | } 57 | scm { 58 | connection gitUrl 59 | developerConnection gitUrl 60 | url siteUrl 61 | 62 | } 63 | } 64 | } 65 | } 66 | } 67 | 68 | 69 | 70 | //Only necessary to push to bintray. Causes Travis CI builds to fail. 71 | /* 72 | Properties properties = new Properties() 73 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 74 | 75 | 76 | // https://github.com/bintray/gradle-bintray-plugin 77 | bintray { 78 | user = properties.getProperty("bintray.user") 79 | key = properties.getProperty("bintray.apikey") 80 | 81 | configurations = ['archives'] 82 | pkg { 83 | repo = "maven" 84 | // it is the name that appears in bintray when logged 85 | name = "Google-Directions-Android" 86 | websiteUrl = siteUrl 87 | vcsUrl = gitUrl 88 | licenses = ["Apache-2.0"] 89 | publish = true 90 | version { 91 | gpg { 92 | sign = true //Determines whether to GPG sign the files. The default is false 93 | passphrase = properties.getProperty("bintray.gpg.password") 94 | //Optional. The passphrase for GPG signing' 95 | } 96 | mavenCentralSync { 97 | sync = true 98 | //Optional (true by default). Determines whether to sync the version to Maven Central. 99 | user = properties.getProperty("bintray.oss.user") //OSS user token 100 | password = properties.getProperty("bintray.oss.password") //OSS user password 101 | close = '1' 102 | //Optional property. By default the staging repository is closed and artifacts are released to Maven Central. You can optionally turn this behaviour off (by puting 0 as value) and release the version manually. 103 | } 104 | } 105 | } 106 | 107 | 108 | } 109 | */ 110 | -------------------------------------------------------------------------------- /library/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/library/ic_launcher-web.png -------------------------------------------------------------------------------- /library/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /library/src/main/java/com/directions/route/AbstractRouting.java: -------------------------------------------------------------------------------- 1 | package com.directions.route; 2 | 3 | /** 4 | * Async Task to access the Google Direction API and return the routing data 5 | * which is then parsed and converting to a route overlay using some classes created by Hesham Saeed. 6 | * @author Joel Dean 7 | * @author Furkan Tektas 8 | * Requires an instance of the map activity and the application's current context for the progress dialog. 9 | * 10 | */ 11 | 12 | import android.os.AsyncTask; 13 | 14 | import com.google.android.gms.maps.model.LatLng; 15 | import com.google.android.gms.maps.model.PolylineOptions; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | 21 | public abstract class AbstractRouting extends AsyncTask> { 22 | protected List alisteners; 23 | 24 | protected static final String DIRECTIONS_API_URL = "https://maps.googleapis.com/maps/api/directions/json?"; 25 | 26 | /* Private member variable that will hold the RouteException instance created in the background thread */ 27 | private RouteException mException = null; 28 | 29 | public enum TravelMode { 30 | BIKING("bicycling"), 31 | DRIVING("driving"), 32 | WALKING("walking"), 33 | TRANSIT("transit"); 34 | 35 | protected String sValue; 36 | 37 | TravelMode(String sValue) { 38 | this.sValue = sValue; 39 | } 40 | 41 | protected String getValue() { 42 | return sValue; 43 | } 44 | } 45 | 46 | public enum AvoidKind { 47 | TOLLS (1, "tolls"), 48 | HIGHWAYS (1 << 1, "highways"), 49 | FERRIES (1 << 2, "ferries"); 50 | 51 | private final String sRequestParam; 52 | private final int sBitValue; 53 | 54 | AvoidKind(int bit, String param) { 55 | this.sBitValue = bit; 56 | this.sRequestParam = param; 57 | } 58 | 59 | protected int getBitValue () { 60 | return sBitValue; 61 | } 62 | 63 | protected static String getRequestParam (int bit) { 64 | StringBuilder ret = new StringBuilder(); 65 | for (AvoidKind kind : AvoidKind.values()) { 66 | if ((bit & kind.sBitValue) == kind.sBitValue) { 67 | ret.append(kind.sRequestParam).append('|'); 68 | } 69 | } 70 | return ret.toString(); 71 | } 72 | } 73 | 74 | protected AbstractRouting (RoutingListener listener) { 75 | this.alisteners = new ArrayList(); 76 | registerListener(listener); 77 | } 78 | 79 | public void registerListener(RoutingListener mListener) { 80 | if (mListener != null) { 81 | alisteners.add(mListener); 82 | } 83 | } 84 | 85 | protected void dispatchOnStart() { 86 | for (RoutingListener mListener : alisteners) { 87 | mListener.onRoutingStart(); 88 | } 89 | } 90 | 91 | protected void dispatchOnFailure(RouteException exception) { 92 | for (RoutingListener mListener : alisteners) { 93 | mListener.onRoutingFailure(exception); 94 | } 95 | } 96 | 97 | protected void dispatchOnSuccess(List route, int shortestRouteIndex) { 98 | for (RoutingListener mListener : alisteners) { 99 | mListener.onRoutingSuccess(route, shortestRouteIndex); 100 | } 101 | } 102 | 103 | private void dispatchOnCancelled() { 104 | for (RoutingListener mListener : alisteners) { 105 | mListener.onRoutingCancelled(); 106 | } 107 | } 108 | 109 | /** 110 | * Performs the call to the google maps API to acquire routing data and 111 | * deserializes it to a format the map can display. 112 | * 113 | * @return an array list containing the routes 114 | */ 115 | @Override 116 | protected List doInBackground(Void... voids) { 117 | List result = new ArrayList(); 118 | try { 119 | result = new GoogleParser(constructURL()).parse(); 120 | }catch(RouteException e){ 121 | mException = e; 122 | } 123 | return result; 124 | } 125 | 126 | protected abstract String constructURL(); 127 | 128 | @Override 129 | protected void onPreExecute() { 130 | dispatchOnStart(); 131 | } 132 | 133 | @Override 134 | protected void onPostExecute(List result) { 135 | if (!result.isEmpty()) { 136 | int shortestRouteIndex = 0; 137 | int minDistance = Integer.MAX_VALUE; 138 | 139 | for (int i = 0; i < result.size(); i++) { 140 | PolylineOptions mOptions = new PolylineOptions(); 141 | Route route = result.get(i); 142 | 143 | //Find the shortest route index 144 | if (route.getLength() < minDistance) { 145 | shortestRouteIndex = i; 146 | minDistance = route.getLength(); 147 | } 148 | 149 | for (LatLng point : route.getPoints()) { 150 | mOptions.add(point); 151 | } 152 | result.get(i).setPolyOptions(mOptions); 153 | } 154 | dispatchOnSuccess(result, shortestRouteIndex); 155 | } else { 156 | dispatchOnFailure(mException); 157 | } 158 | }//end onPostExecute method 159 | 160 | @Override 161 | protected void onCancelled() { 162 | dispatchOnCancelled(); 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /library/src/main/java/com/directions/route/GoogleParser.java: -------------------------------------------------------------------------------- 1 | package com.directions.route; 2 | 3 | import android.util.Log; 4 | 5 | import com.google.android.gms.maps.model.LatLng; 6 | 7 | import org.json.JSONArray; 8 | import org.json.JSONException; 9 | import org.json.JSONObject; 10 | 11 | import java.io.BufferedReader; 12 | import java.io.IOException; 13 | import java.io.InputStream; 14 | import java.io.InputStreamReader; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | public class GoogleParser extends XMLParser implements Parser { 19 | 20 | private static final String VALUE = "value"; 21 | private static final String DISTANCE = "distance"; 22 | /** 23 | * Distance covered. * 24 | */ 25 | private int distance; 26 | 27 | /* Status code returned when the request succeeded */ 28 | private static final String OK = "OK"; 29 | 30 | public GoogleParser(String feedUrl) { 31 | super(feedUrl); 32 | } 33 | 34 | /** 35 | * Parses a url pointing to a Google JSON object to a Route object. 36 | * 37 | * @return a Route object based on the JSON object by Haseem Saheed 38 | */ 39 | 40 | public final List parse() throws RouteException { 41 | List routes = new ArrayList<>(); 42 | 43 | // turn the stream into a string 44 | final String result = convertStreamToString(this.getInputStream()); 45 | if (result == null) { 46 | throw new RouteException("Result is null"); 47 | } 48 | 49 | try { 50 | //Tranform the string into a json object 51 | final JSONObject json = new JSONObject(result); 52 | //Get the route object 53 | 54 | if(!json.getString("status").equals(OK)){ 55 | throw new RouteException(json); 56 | } 57 | 58 | JSONArray jsonRoutes = json.getJSONArray("routes"); 59 | 60 | for (int i = 0; i < jsonRoutes.length(); i++) { 61 | Route route = new Route(); 62 | //Create an empty segment 63 | Segment segment = new Segment(); 64 | 65 | JSONObject jsonRoute = jsonRoutes.getJSONObject(i); 66 | //Get the bounds - northeast and southwest 67 | final JSONObject jsonBounds = jsonRoute.getJSONObject("bounds"); 68 | final JSONObject jsonNortheast = jsonBounds.getJSONObject("northeast"); 69 | final JSONObject jsonSouthwest = jsonBounds.getJSONObject("southwest"); 70 | 71 | route.setLatLgnBounds(new LatLng(jsonNortheast.getDouble("lat"), jsonNortheast.getDouble("lng")), new LatLng(jsonSouthwest.getDouble("lat"), jsonSouthwest.getDouble("lng"))); 72 | 73 | //Get the leg, only one leg as we don't support waypoints 74 | final JSONObject leg = jsonRoute.getJSONArray("legs").getJSONObject(0); 75 | //Get the steps for this leg 76 | final JSONArray steps = leg.getJSONArray("steps"); 77 | //Number of steps for use in for loop 78 | final int numSteps = steps.length(); 79 | //Set the name of this route using the start & end addresses 80 | route.setName(leg.getString("start_address") + " to " + leg.getString("end_address")); 81 | //Get google's copyright notice (tos requirement) 82 | route.setCopyright(jsonRoute.getString("copyrights")); 83 | //Get distance and time estimation 84 | route.setDurationText(leg.getJSONObject("duration").getString("text")); 85 | route.setDurationValue(leg.getJSONObject("duration").getInt(VALUE)); 86 | route.setDistanceText(leg.getJSONObject(DISTANCE).getString("text")); 87 | route.setDistanceValue(leg.getJSONObject(DISTANCE).getInt(VALUE)); 88 | route.setEndAddressText(leg.getString("end_address")); 89 | //Get the total length of the route. 90 | route.setLength(leg.getJSONObject(DISTANCE).getInt(VALUE)); 91 | //Get any warnings provided (tos requirement) 92 | if (!jsonRoute.getJSONArray("warnings").isNull(0)) { 93 | route.setWarning(jsonRoute.getJSONArray("warnings").getString(0)); 94 | } 95 | 96 | /* Loop through the steps, creating a segment for each one and 97 | * decoding any polylines found as we go to add to the route object's 98 | * map array. Using an explicit for loop because it is faster! 99 | */ 100 | for (int y = 0; y < numSteps; y++) { 101 | //Get the individual step 102 | final JSONObject step = steps.getJSONObject(y); 103 | //Get the start position for this step and set it on the segment 104 | final JSONObject start = step.getJSONObject("start_location"); 105 | final LatLng position = new LatLng(start.getDouble("lat"), 106 | start.getDouble("lng")); 107 | segment.setPoint(position); 108 | //Set the length of this segment in metres 109 | final int length = step.getJSONObject(DISTANCE).getInt(VALUE); 110 | distance += length; 111 | segment.setLength(length); 112 | segment.setDistance((double)distance / (double)1000); 113 | //Strip html from google directions and set as turn instruction 114 | segment.setInstruction(step.getString("html_instructions").replaceAll("<(.*?)*>", "")); 115 | 116 | if(step.has("maneuver")) 117 | segment.setManeuver(step.getString("maneuver")); 118 | 119 | //Retrieve & decode this segment's polyline and add it to the route. 120 | route.addPoints(decodePolyLine(step.getJSONObject("polyline").getString("points"))); 121 | //Push a copy of the segment to the route 122 | route.addSegment(segment.copy()); 123 | } 124 | 125 | routes.add(route); 126 | } 127 | 128 | } catch (JSONException e) { 129 | throw new RouteException("JSONException. Msg: "+e.getMessage()); 130 | } 131 | return routes; 132 | } 133 | 134 | /** 135 | * Convert an inputstream to a string. 136 | * 137 | * @param input inputstream to convert. 138 | * @return a String of the inputstream. 139 | */ 140 | 141 | private static String convertStreamToString(final InputStream input) { 142 | if (input == null) return null; 143 | 144 | final BufferedReader reader = new BufferedReader(new InputStreamReader(input)); 145 | final StringBuilder sBuf = new StringBuilder(); 146 | 147 | String line; 148 | try { 149 | while ((line = reader.readLine()) != null) { 150 | sBuf.append(line); 151 | } 152 | } catch (IOException e) { 153 | Log.e("Routing Error", e.getMessage()); 154 | } finally { 155 | try { 156 | input.close(); 157 | reader.close(); 158 | } catch (IOException e) { 159 | Log.e("Routing Error", e.getMessage()); 160 | } 161 | } 162 | return sBuf.toString(); 163 | } 164 | 165 | /** 166 | * Decode a polyline string into a list of GeoPoints. 167 | * 168 | * @param poly polyline encoded string to decode. 169 | * @return the list of GeoPoints represented by this polystring. 170 | */ 171 | 172 | private List decodePolyLine(final String poly) { 173 | int len = poly.length(); 174 | int index = 0; 175 | List decoded = new ArrayList(); 176 | int lat = 0; 177 | int lng = 0; 178 | 179 | while (index < len) { 180 | int b; 181 | int shift = 0; 182 | int result = 0; 183 | do { 184 | b = poly.charAt(index++) - 63; 185 | result |= (b & 0x1f) << shift; 186 | shift += 5; 187 | } while (b >= 0x20); 188 | int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); 189 | lat += dlat; 190 | 191 | shift = 0; 192 | result = 0; 193 | do { 194 | b = poly.charAt(index++) - 63; 195 | result |= (b & 0x1f) << shift; 196 | shift += 5; 197 | } while (b >= 0x20); 198 | int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); 199 | lng += dlng; 200 | 201 | decoded.add(new LatLng( 202 | lat / 100000d, lng / 100000d 203 | )); 204 | } 205 | 206 | return decoded; 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /library/src/main/java/com/directions/route/Parser.java: -------------------------------------------------------------------------------- 1 | package com.directions.route; 2 | 3 | import java.util.List; 4 | 5 | //. by Haseem Saheed 6 | public interface Parser { 7 | List parse() throws RouteException; 8 | } -------------------------------------------------------------------------------- /library/src/main/java/com/directions/route/Route.java: -------------------------------------------------------------------------------- 1 | package com.directions.route; 2 | //by Haseem Saheed 3 | 4 | import android.os.Parcel; 5 | import android.os.Parcelable; 6 | 7 | import com.google.android.gms.maps.model.LatLng; 8 | import com.google.android.gms.maps.model.LatLngBounds; 9 | import com.google.android.gms.maps.model.PolylineOptions; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | public class Route implements Parcelable { 15 | private String name; 16 | private final List points; 17 | private List segments; 18 | private String copyright; 19 | private String warning; 20 | private String country; 21 | private LatLngBounds latLgnBounds; 22 | private int length; 23 | private String polyline; 24 | private String durationText; 25 | private int durationValue; 26 | private String distanceText; 27 | private int distanceValue; 28 | private String endAddressText; 29 | private PolylineOptions polyOptions; 30 | 31 | public Route() { 32 | points = new ArrayList<>(); 33 | segments = new ArrayList<>(); 34 | } 35 | 36 | private Route(Parcel in) { 37 | name = in.readString(); 38 | 39 | // points 40 | if (in.readInt() == 1) { 41 | points = new ArrayList<>(); 42 | in.readList(points, LatLng.class.getClassLoader()); 43 | } else { 44 | points = null; 45 | } 46 | 47 | // segments 48 | if (in.readInt() == 1) { 49 | segments = new ArrayList<>(); 50 | in.readList(segments, Segment.class.getClassLoader()); 51 | } else { 52 | segments = null; 53 | } 54 | 55 | copyright = in.readString(); 56 | warning = in.readString(); 57 | country = in.readString(); 58 | latLgnBounds = in.readParcelable(LatLngBounds.class.getClassLoader()); 59 | length = in.readInt(); 60 | polyline = in.readString(); 61 | durationText = in.readString(); 62 | durationValue = in.readInt(); 63 | distanceText = in.readString(); 64 | distanceValue = in.readInt(); 65 | endAddressText = in.readString(); 66 | polyOptions = in.readParcelable(PolylineOptions.class.getClassLoader()); 67 | } 68 | 69 | public PolylineOptions getPolyOptions() { 70 | return polyOptions; 71 | } 72 | 73 | public void setPolyOptions(PolylineOptions polyOptions) { 74 | this.polyOptions = polyOptions; 75 | } 76 | 77 | public String getEndAddressText() { 78 | return endAddressText; 79 | } 80 | 81 | public void setEndAddressText(String endAddressText) { 82 | this.endAddressText = endAddressText; 83 | } 84 | 85 | public String getDurationText() { 86 | return durationText; 87 | } 88 | 89 | public void setDurationText(String durationText) { 90 | this.durationText = durationText; 91 | } 92 | 93 | public String getDistanceText() { 94 | return distanceText; 95 | } 96 | 97 | public void setDistanceText(String distanceText) { 98 | this.distanceText = distanceText; 99 | } 100 | 101 | public int getDurationValue() { 102 | return durationValue; 103 | } 104 | 105 | public void setDurationValue(int durationValue) { 106 | this.durationValue = durationValue; 107 | } 108 | 109 | public int getDistanceValue() { 110 | return distanceValue; 111 | } 112 | 113 | public void setDistanceValue(int distanceValue) { 114 | this.distanceValue = distanceValue; 115 | } 116 | 117 | public void setSegments(List segments) { 118 | this.segments = segments; 119 | } 120 | 121 | public void addPoint(final LatLng p) { 122 | points.add(p); 123 | } 124 | 125 | public void addPoints(final List points) { 126 | this.points.addAll(points); 127 | } 128 | 129 | public List getPoints() { 130 | return points; 131 | } 132 | 133 | public void addSegment(final Segment s) { 134 | segments.add(s); 135 | } 136 | 137 | public List getSegments() { 138 | return segments; 139 | } 140 | 141 | /** 142 | * @param name the name to set 143 | */ 144 | public void setName(final String name) { 145 | this.name = name; 146 | } 147 | 148 | /** 149 | * @return the name 150 | */ 151 | public String getName() { 152 | return name; 153 | } 154 | 155 | /** 156 | * @param copyright the copyright to set 157 | */ 158 | public void setCopyright(String copyright) { 159 | this.copyright = copyright; 160 | } 161 | 162 | /** 163 | * @return the copyright 164 | */ 165 | public String getCopyright() { 166 | return copyright; 167 | } 168 | 169 | /** 170 | * @param warning the warning to set 171 | */ 172 | public void setWarning(String warning) { 173 | this.warning = warning; 174 | } 175 | 176 | /** 177 | * @return the warning 178 | */ 179 | public String getWarning() { 180 | return warning; 181 | } 182 | 183 | /** 184 | * @param country the country to set 185 | */ 186 | public void setCountry(String country) { 187 | this.country = country; 188 | } 189 | 190 | /** 191 | * @return the country 192 | */ 193 | public String getCountry() { 194 | return country; 195 | } 196 | 197 | /** 198 | * @param length the length to set 199 | */ 200 | public void setLength(int length) { 201 | this.length = length; 202 | } 203 | 204 | /** 205 | * @return the length 206 | */ 207 | public int getLength() { 208 | return length; 209 | } 210 | 211 | /** 212 | * @param polyline the polyline to set 213 | */ 214 | public void setPolyline(String polyline) { 215 | this.polyline = polyline; 216 | } 217 | 218 | /** 219 | * @return the polyline 220 | */ 221 | public String getPolyline() { 222 | return polyline; 223 | } 224 | 225 | /** 226 | * @return the LatLngBounds object to map camera 227 | */ 228 | public LatLngBounds getLatLgnBounds() { 229 | return latLgnBounds; 230 | } 231 | 232 | public void setLatLgnBounds(LatLng northeast, LatLng southwest) { 233 | LatLngBounds.Builder builder = new LatLngBounds.Builder(); 234 | builder.include(northeast); 235 | builder.include(southwest); 236 | this.latLgnBounds = builder.build(); 237 | } 238 | 239 | @Override 240 | public int describeContents() { 241 | return hashCode(); 242 | } 243 | 244 | @Override 245 | public void writeToParcel(Parcel dest, int flags) { 246 | dest.writeString(name); 247 | 248 | // points 249 | if (points == null) { 250 | dest.writeInt(0); 251 | } else { 252 | dest.writeInt(1); 253 | dest.writeList(points); 254 | } 255 | 256 | // segments 257 | if (segments == null) { 258 | dest.writeInt(0); 259 | } else { 260 | dest.writeInt(1); 261 | dest.writeList(segments); 262 | } 263 | 264 | dest.writeString(copyright); 265 | dest.writeString(warning); 266 | dest.writeString(country); 267 | dest.writeParcelable(latLgnBounds, flags); 268 | dest.writeInt(length); 269 | dest.writeString(polyline); 270 | dest.writeString(durationText); 271 | dest.writeInt(durationValue); 272 | dest.writeString(distanceText); 273 | dest.writeInt(distanceValue); 274 | dest.writeString(endAddressText); 275 | dest.writeParcelable(polyOptions, flags); 276 | } 277 | 278 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 279 | @Override 280 | public Route createFromParcel(Parcel in) { 281 | return new Route(in); 282 | } 283 | 284 | @Override 285 | public Route[] newArray(int size) { 286 | return new Route[size]; 287 | } 288 | }; 289 | } 290 | 291 | -------------------------------------------------------------------------------- /library/src/main/java/com/directions/route/RouteException.java: -------------------------------------------------------------------------------- 1 | package com.directions.route; 2 | 3 | import android.util.Log; 4 | 5 | import org.json.JSONException; 6 | import org.json.JSONObject; 7 | 8 | /** 9 | * Created by nelson on 1/13/16. 10 | */ 11 | public class RouteException extends Exception { 12 | private static final String TAG = "RouteException"; 13 | private static final String KEY_STATUS = "status"; 14 | private static final String KEY_MESSAGE = "error_message"; 15 | 16 | private String statusCode; 17 | private String message; 18 | 19 | public RouteException(JSONObject json){ 20 | if(json == null){ 21 | statusCode = ""; 22 | message = "Parsing error"; 23 | return; 24 | } 25 | try { 26 | statusCode = json.getString(KEY_STATUS); 27 | message = json.getString(KEY_MESSAGE); 28 | } catch (JSONException e) { 29 | Log.e(TAG, "JSONException while parsing RouteException argument. Msg: " + e.getMessage()); 30 | } 31 | } 32 | 33 | public RouteException(String msg){ 34 | message = msg; 35 | } 36 | 37 | @Override 38 | public String getMessage() { 39 | return message; 40 | } 41 | 42 | public String getStatusCode() { 43 | return statusCode; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /library/src/main/java/com/directions/route/Routing.java: -------------------------------------------------------------------------------- 1 | package com.directions.route; 2 | 3 | import com.google.android.gms.maps.model.LatLng; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.List; 8 | 9 | /** 10 | * Async Task to access the Google Direction API and return the routing data. 11 | * Created by Furkan Tektas on 10/14/14. 12 | */ 13 | public class Routing extends AbstractRouting { 14 | 15 | private final TravelMode travelMode; 16 | private final boolean alternativeRoutes; 17 | private final List waypoints; 18 | private final int avoidKinds; 19 | private final boolean optimize; 20 | private final String language; 21 | private final String key; 22 | 23 | private Routing(Builder builder) { 24 | super(builder.listener); 25 | this.travelMode = builder.travelMode; 26 | this.waypoints = builder.waypoints; 27 | this.avoidKinds = builder.avoidKinds; 28 | this.optimize = builder.optimize; 29 | this.alternativeRoutes = builder.alternativeRoutes; 30 | this.language = builder.language; 31 | this.key = builder.key; 32 | } 33 | 34 | protected String constructURL () { 35 | final StringBuilder stringBuilder = new StringBuilder(AbstractRouting.DIRECTIONS_API_URL); 36 | 37 | // origin 38 | final LatLng origin = waypoints.get(0); 39 | stringBuilder.append("origin=") 40 | .append(origin.latitude) 41 | .append(',') 42 | .append(origin.longitude); 43 | 44 | // destination 45 | final LatLng destination = waypoints.get(waypoints.size() - 1); 46 | stringBuilder.append("&destination=") 47 | .append(destination.latitude) 48 | .append(',') 49 | .append(destination.longitude); 50 | 51 | // travel 52 | stringBuilder.append("&mode=").append(travelMode.getValue()); 53 | 54 | // waypoints 55 | if (waypoints.size() > 2) { 56 | stringBuilder.append("&waypoints="); 57 | if(optimize) 58 | stringBuilder.append("optimize:true|"); 59 | for (int i = 1; i < waypoints.size() - 1; i++) { 60 | final LatLng p = waypoints.get(i); 61 | stringBuilder.append("via:"); // we don't want to parse the resulting JSON for 'legs'. 62 | stringBuilder.append(p.latitude); 63 | stringBuilder.append(','); 64 | stringBuilder.append(p.longitude); 65 | stringBuilder.append('|'); 66 | } 67 | } 68 | 69 | // avoid 70 | if (avoidKinds > 0) { 71 | stringBuilder.append("&avoid="); 72 | stringBuilder.append(AvoidKind.getRequestParam(avoidKinds)); 73 | } 74 | 75 | if (alternativeRoutes) { 76 | stringBuilder.append("&alternatives=true"); 77 | } 78 | 79 | // sensor 80 | stringBuilder.append("&sensor=true"); 81 | 82 | // language 83 | if (language != null) { 84 | stringBuilder.append("&language=").append(language); 85 | } 86 | 87 | // API key 88 | if(key != null) { 89 | stringBuilder.append("&key=").append(key); 90 | } 91 | return stringBuilder.toString(); 92 | } 93 | 94 | public static class Builder { 95 | 96 | private TravelMode travelMode; 97 | private boolean alternativeRoutes; 98 | private List waypoints; 99 | private int avoidKinds; 100 | private RoutingListener listener; 101 | private boolean optimize; 102 | private String language; 103 | private String key; 104 | 105 | public Builder () { 106 | this.travelMode = TravelMode.DRIVING; 107 | this.alternativeRoutes = false; 108 | this.waypoints = new ArrayList<>(); 109 | this.avoidKinds = 0; 110 | this.listener = null; 111 | this.optimize = false; 112 | this.language = null; 113 | this.key = null; 114 | } 115 | 116 | public Builder travelMode (TravelMode travelMode) { 117 | this.travelMode = travelMode; 118 | return this; 119 | } 120 | 121 | public Builder alternativeRoutes (boolean alternativeRoutes) { 122 | this.alternativeRoutes = alternativeRoutes; 123 | return this; 124 | } 125 | 126 | public Builder waypoints (LatLng... points) { 127 | waypoints.clear(); 128 | Collections.addAll(waypoints, points); 129 | return this; 130 | } 131 | 132 | public Builder waypoints (List waypoints) { 133 | this.waypoints = new ArrayList<>(waypoints); 134 | return this; 135 | } 136 | 137 | public Builder optimize(boolean optimize) { 138 | this.optimize = optimize; 139 | return this; 140 | } 141 | 142 | public Builder avoid (AvoidKind... avoids) { 143 | for (AvoidKind avoidKind : avoids) { 144 | this.avoidKinds |= avoidKind.getBitValue(); 145 | } 146 | return this; 147 | } 148 | 149 | public Builder language (String language) { 150 | this.language = language; 151 | return this; 152 | } 153 | 154 | public Builder key(String key) { 155 | this.key = key; 156 | return this; 157 | } 158 | 159 | public Builder withListener (RoutingListener listener) { 160 | this.listener = listener; 161 | return this; 162 | } 163 | 164 | public Routing build () { 165 | if (this.waypoints.size() < 2) { 166 | throw new IllegalArgumentException("Must supply at least two waypoints to route between."); 167 | } 168 | if (this.waypoints.size() <= 2 && this.optimize) { 169 | throw new IllegalArgumentException("You need at least three waypoints to enable optimize"); 170 | } 171 | return new Routing(this); 172 | } 173 | 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /library/src/main/java/com/directions/route/RoutingListener.java: -------------------------------------------------------------------------------- 1 | package com.directions.route; 2 | 3 | import java.util.List; 4 | 5 | public interface RoutingListener { 6 | void onRoutingFailure(RouteException e); 7 | 8 | void onRoutingStart(); 9 | 10 | void onRoutingSuccess(List route, int shortestRouteIndex); 11 | 12 | void onRoutingCancelled(); 13 | } 14 | -------------------------------------------------------------------------------- /library/src/main/java/com/directions/route/Segment.java: -------------------------------------------------------------------------------- 1 | package com.directions.route; 2 | //by Haseem Saheed 3 | 4 | import android.os.Parcel; 5 | import android.os.Parcelable; 6 | 7 | import com.google.android.gms.maps.model.LatLng; 8 | 9 | public class Segment implements Parcelable { 10 | /** 11 | * Points in this segment. * 12 | */ 13 | private LatLng start; 14 | /** 15 | * Turn instruction to reach next segment. * 16 | */ 17 | private String instruction; 18 | /** 19 | * Length of segment. * 20 | */ 21 | private int length; 22 | /** 23 | * Distance covered. * 24 | */ 25 | private double distance; 26 | 27 | /* Maneuver instructions */ 28 | private String maneuver; 29 | 30 | /** 31 | * Create an empty segment. 32 | */ 33 | 34 | public Segment() { 35 | } 36 | 37 | private Segment(Parcel in) { 38 | start = in.readParcelable(LatLng.class.getClassLoader()); 39 | instruction = in.readString(); 40 | length = in.readInt(); 41 | distance = in.readDouble(); 42 | maneuver = in.readString(); 43 | } 44 | 45 | /** 46 | * Set the turn instruction. 47 | * 48 | * @param turn Turn instruction string. 49 | */ 50 | 51 | public void setInstruction(final String turn) { 52 | this.instruction = turn; 53 | } 54 | 55 | /** 56 | * Get the turn instruction to reach next segment. 57 | * 58 | * @return a String of the turn instruction. 59 | */ 60 | 61 | public String getInstruction() { 62 | return instruction; 63 | } 64 | 65 | /** 66 | * Add a point to this segment. 67 | * 68 | * @param point GeoPoint to add. 69 | */ 70 | 71 | public void setPoint(final LatLng point) { 72 | start = point; 73 | } 74 | 75 | /** 76 | * Get the starting point of this 77 | * segment. 78 | * 79 | * @return a GeoPoint 80 | */ 81 | 82 | public LatLng startPoint() { 83 | return start; 84 | } 85 | 86 | /** 87 | * Creates a segment which is a copy of this one. 88 | * 89 | * @return a Segment that is a copy of this one. 90 | */ 91 | 92 | public Segment copy() { 93 | final Segment copy = new Segment(); 94 | copy.start = start; 95 | copy.instruction = instruction; 96 | copy.length = length; 97 | copy.distance = distance; 98 | copy.maneuver = maneuver; 99 | return copy; 100 | } 101 | 102 | /** 103 | * @param length the length to set 104 | */ 105 | public void setLength(final int length) { 106 | this.length = length; 107 | } 108 | 109 | /** 110 | * @return the length 111 | */ 112 | public int getLength() { 113 | return length; 114 | } 115 | 116 | /** 117 | * @param distance the distance to set 118 | */ 119 | public void setDistance(double distance) { 120 | this.distance = distance; 121 | } 122 | 123 | /** 124 | * @return the distance 125 | */ 126 | public double getDistance() { 127 | return distance; 128 | } 129 | 130 | public void setManeuver(String man) { 131 | maneuver = man; 132 | } 133 | 134 | public String getManeuver() { 135 | return maneuver; 136 | } 137 | 138 | @Override 139 | public int describeContents() { 140 | return hashCode(); 141 | } 142 | 143 | @Override 144 | public void writeToParcel(Parcel dest, int flags) { 145 | dest.writeParcelable(start, flags); 146 | dest.writeString(instruction); 147 | dest.writeInt(length); 148 | dest.writeDouble(distance); 149 | dest.writeString(maneuver); 150 | } 151 | 152 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 153 | @Override 154 | public Segment createFromParcel(Parcel in) { 155 | return new Segment(in); 156 | } 157 | 158 | @Override 159 | public Segment[] newArray(int size) { 160 | return new Segment[size]; 161 | } 162 | }; 163 | } 164 | -------------------------------------------------------------------------------- /library/src/main/java/com/directions/route/XMLParser.java: -------------------------------------------------------------------------------- 1 | package com.directions.route; 2 | //by Haseem Saheed 3 | 4 | import android.util.Log; 5 | 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.net.MalformedURLException; 9 | import java.net.URL; 10 | 11 | public class XMLParser { 12 | // names of the XML tags 13 | protected static final String MARKERS = "markers"; 14 | protected static final String MARKER = "marker"; 15 | 16 | protected URL feedUrl; 17 | 18 | protected XMLParser(final String feedUrl) { 19 | try { 20 | this.feedUrl = new URL(feedUrl); 21 | } catch (MalformedURLException e) { 22 | Log.e("Routing Error", e.getMessage()); 23 | } 24 | } 25 | 26 | protected InputStream getInputStream() { 27 | try { 28 | return feedUrl.openConnection().getInputStream(); 29 | } catch (IOException e) { 30 | Log.e("Routing Error", "Exception: " + e.getMessage()); 31 | return null; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "22.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.directions.sample" 9 | minSdkVersion 15 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:22.2.0' 25 | compile project(':library') 26 | compile "com.google.android.gms:play-services-location:7.5.0" 27 | compile 'com.android.support:cardview-v7:21.0.2' 28 | compile 'com.jakewharton:butterknife:6.1.0' 29 | } 30 | -------------------------------------------------------------------------------- /sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\Joel\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 23 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /sample/src/main/java/com/directions/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.directions.sample; 2 | 3 | import android.app.ProgressDialog; 4 | import android.location.Location; 5 | import android.location.LocationListener; 6 | import android.location.LocationManager; 7 | import android.os.Bundle; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.text.Editable; 10 | import android.text.TextWatcher; 11 | import android.util.Log; 12 | import android.view.View; 13 | import android.widget.AdapterView; 14 | import android.widget.AutoCompleteTextView; 15 | import android.widget.ImageView; 16 | import android.widget.Toast; 17 | 18 | import com.directions.route.AbstractRouting; 19 | import com.directions.route.Route; 20 | import com.directions.route.RouteException; 21 | import com.directions.route.Routing; 22 | import com.directions.route.RoutingListener; 23 | import com.google.android.gms.common.ConnectionResult; 24 | import com.google.android.gms.common.api.GoogleApiClient; 25 | import com.google.android.gms.common.api.PendingResult; 26 | import com.google.android.gms.common.api.ResultCallback; 27 | import com.google.android.gms.location.places.Place; 28 | import com.google.android.gms.location.places.PlaceBuffer; 29 | import com.google.android.gms.location.places.Places; 30 | import com.google.android.gms.maps.CameraUpdate; 31 | import com.google.android.gms.maps.CameraUpdateFactory; 32 | import com.google.android.gms.maps.GoogleMap; 33 | import com.google.android.gms.maps.MapsInitializer; 34 | import com.google.android.gms.maps.SupportMapFragment; 35 | import com.google.android.gms.maps.model.BitmapDescriptorFactory; 36 | import com.google.android.gms.maps.model.CameraPosition; 37 | import com.google.android.gms.maps.model.LatLng; 38 | import com.google.android.gms.maps.model.LatLngBounds; 39 | import com.google.android.gms.maps.model.MarkerOptions; 40 | import com.google.android.gms.maps.model.Polyline; 41 | import com.google.android.gms.maps.model.PolylineOptions; 42 | 43 | import java.util.ArrayList; 44 | import java.util.List; 45 | 46 | import butterknife.ButterKnife; 47 | import butterknife.InjectView; 48 | import butterknife.OnClick; 49 | 50 | public class MainActivity extends AppCompatActivity implements RoutingListener, GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks { 51 | protected GoogleMap map; 52 | protected LatLng start; 53 | protected LatLng end; 54 | @InjectView(R.id.start) 55 | AutoCompleteTextView starting; 56 | @InjectView(R.id.destination) 57 | AutoCompleteTextView destination; 58 | @InjectView(R.id.send) 59 | ImageView send; 60 | private static final String LOG_TAG = "MyActivity"; 61 | protected GoogleApiClient mGoogleApiClient; 62 | private PlaceAutoCompleteAdapter mAdapter; 63 | private ProgressDialog progressDialog; 64 | private List polylines; 65 | private static final int[] COLORS = new int[]{R.color.primary_dark,R.color.primary,R.color.primary_light,R.color.accent,R.color.primary_dark_material_light}; 66 | 67 | 68 | private static final LatLngBounds BOUNDS_JAMAICA= new LatLngBounds(new LatLng(-57.965341647205726, 144.9987719580531), 69 | new LatLng(72.77492067739843, -9.998857788741589)); 70 | 71 | /** 72 | * This activity loads a map and then displays the route and pushpins on it. 73 | */ 74 | @Override 75 | public void onCreate(Bundle savedInstanceState) { 76 | super.onCreate(savedInstanceState); 77 | setContentView(R.layout.activity_main); 78 | ButterKnife.inject(this); 79 | getSupportActionBar().setDisplayShowHomeEnabled(true); 80 | 81 | polylines = new ArrayList<>(); 82 | mGoogleApiClient = new GoogleApiClient.Builder(this) 83 | .addApi(Places.GEO_DATA_API) 84 | .addConnectionCallbacks(this) 85 | .addOnConnectionFailedListener(this) 86 | .build(); 87 | MapsInitializer.initialize(this); 88 | mGoogleApiClient.connect(); 89 | 90 | SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); 91 | 92 | if (mapFragment == null) { 93 | mapFragment = SupportMapFragment.newInstance(); 94 | getSupportFragmentManager().beginTransaction().replace(R.id.map, mapFragment).commit(); 95 | } 96 | map = mapFragment.getMap(); 97 | 98 | mAdapter = new PlaceAutoCompleteAdapter(this, android.R.layout.simple_list_item_1, 99 | mGoogleApiClient, BOUNDS_JAMAICA, null); 100 | 101 | 102 | /* 103 | * Updates the bounds being used by the auto complete adapter based on the position of the 104 | * map. 105 | * */ 106 | map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() { 107 | @Override 108 | public void onCameraChange(CameraPosition position) { 109 | LatLngBounds bounds = map.getProjection().getVisibleRegion().latLngBounds; 110 | mAdapter.setBounds(bounds); 111 | } 112 | }); 113 | 114 | 115 | CameraUpdate center = CameraUpdateFactory.newLatLng(new LatLng(18.013610, -77.498803)); 116 | CameraUpdate zoom = CameraUpdateFactory.zoomTo(16); 117 | 118 | map.moveCamera(center); 119 | map.animateCamera(zoom); 120 | 121 | LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); 122 | 123 | locationManager.requestLocationUpdates( 124 | LocationManager.NETWORK_PROVIDER, 5000, 0, 125 | new LocationListener() { 126 | @Override 127 | public void onLocationChanged(Location location) { 128 | 129 | CameraUpdate center = CameraUpdateFactory.newLatLng(new LatLng(location.getLatitude(),location.getLongitude())); 130 | CameraUpdate zoom = CameraUpdateFactory.zoomTo(16); 131 | 132 | map.moveCamera(center); 133 | map.animateCamera(zoom); 134 | } 135 | 136 | @Override 137 | public void onStatusChanged(String provider, int status, Bundle extras) { 138 | 139 | } 140 | 141 | @Override 142 | public void onProviderEnabled(String provider) { 143 | 144 | } 145 | 146 | @Override 147 | public void onProviderDisabled(String provider) { 148 | 149 | } 150 | }); 151 | 152 | 153 | locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 154 | 3000, 0, new LocationListener() { 155 | @Override 156 | public void onLocationChanged(Location location) { 157 | CameraUpdate center = CameraUpdateFactory.newLatLng(new LatLng(location.getLatitude(),location.getLongitude())); 158 | CameraUpdate zoom = CameraUpdateFactory.zoomTo(16); 159 | 160 | map.moveCamera(center); 161 | map.animateCamera(zoom); 162 | 163 | } 164 | 165 | @Override 166 | public void onStatusChanged(String provider, int status, Bundle extras) { 167 | 168 | } 169 | 170 | @Override 171 | public void onProviderEnabled(String provider) { 172 | 173 | } 174 | 175 | @Override 176 | public void onProviderDisabled(String provider) { 177 | 178 | } 179 | }); 180 | 181 | 182 | 183 | /* 184 | * Adds auto complete adapter to both auto complete 185 | * text views. 186 | * */ 187 | starting.setAdapter(mAdapter); 188 | destination.setAdapter(mAdapter); 189 | 190 | 191 | /* 192 | * Sets the start and destination points based on the values selected 193 | * from the autocomplete text views. 194 | * */ 195 | 196 | starting.setOnItemClickListener(new AdapterView.OnItemClickListener() { 197 | @Override 198 | public void onItemClick(AdapterView parent, View view, int position, long id) { 199 | 200 | final PlaceAutoCompleteAdapter.PlaceAutocomplete item = mAdapter.getItem(position); 201 | final String placeId = String.valueOf(item.placeId); 202 | Log.i(LOG_TAG, "Autocomplete item selected: " + item.description); 203 | 204 | /* 205 | Issue a request to the Places Geo Data API to retrieve a Place object with additional 206 | details about the place. 207 | */ 208 | PendingResult placeResult = Places.GeoDataApi 209 | .getPlaceById(mGoogleApiClient, placeId); 210 | placeResult.setResultCallback(new ResultCallback() { 211 | @Override 212 | public void onResult(PlaceBuffer places) { 213 | if (!places.getStatus().isSuccess()) { 214 | // Request did not complete successfully 215 | Log.e(LOG_TAG, "Place query did not complete. Error: " + places.getStatus().toString()); 216 | places.release(); 217 | return; 218 | } 219 | // Get the Place object from the buffer. 220 | final Place place = places.get(0); 221 | 222 | start=place.getLatLng(); 223 | } 224 | }); 225 | 226 | } 227 | }); 228 | destination.setOnItemClickListener(new AdapterView.OnItemClickListener() { 229 | @Override 230 | public void onItemClick(AdapterView parent, View view, int position, long id) { 231 | 232 | final PlaceAutoCompleteAdapter.PlaceAutocomplete item = mAdapter.getItem(position); 233 | final String placeId = String.valueOf(item.placeId); 234 | Log.i(LOG_TAG, "Autocomplete item selected: " + item.description); 235 | 236 | /* 237 | Issue a request to the Places Geo Data API to retrieve a Place object with additional 238 | details about the place. 239 | */ 240 | PendingResult placeResult = Places.GeoDataApi 241 | .getPlaceById(mGoogleApiClient, placeId); 242 | placeResult.setResultCallback(new ResultCallback() { 243 | @Override 244 | public void onResult(PlaceBuffer places) { 245 | if (!places.getStatus().isSuccess()) { 246 | // Request did not complete successfully 247 | Log.e(LOG_TAG, "Place query did not complete. Error: " + places.getStatus().toString()); 248 | places.release(); 249 | return; 250 | } 251 | // Get the Place object from the buffer. 252 | final Place place = places.get(0); 253 | 254 | end=place.getLatLng(); 255 | } 256 | }); 257 | 258 | } 259 | }); 260 | 261 | /* 262 | These text watchers set the start and end points to null because once there's 263 | * a change after a value has been selected from the dropdown 264 | * then the value has to reselected from dropdown to get 265 | * the correct location. 266 | * */ 267 | starting.addTextChangedListener(new TextWatcher() { 268 | @Override 269 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 270 | 271 | } 272 | 273 | @Override 274 | public void onTextChanged(CharSequence s, int startNum, int before, int count) { 275 | if (start != null) { 276 | start = null; 277 | } 278 | } 279 | 280 | @Override 281 | public void afterTextChanged(Editable s) { 282 | 283 | } 284 | }); 285 | 286 | destination.addTextChangedListener(new TextWatcher() { 287 | @Override 288 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 289 | 290 | } 291 | 292 | @Override 293 | public void onTextChanged(CharSequence s, int start, int before, int count) { 294 | 295 | 296 | if(end!=null) 297 | { 298 | end=null; 299 | } 300 | } 301 | 302 | @Override 303 | public void afterTextChanged(Editable s) { 304 | 305 | } 306 | }); 307 | 308 | } 309 | 310 | @OnClick(R.id.send) 311 | public void sendRequest() 312 | { 313 | if(Util.Operations.isOnline(this)) 314 | { 315 | route(); 316 | } 317 | else 318 | { 319 | Toast.makeText(this,"No internet connectivity",Toast.LENGTH_SHORT).show(); 320 | } 321 | } 322 | 323 | public void route() 324 | { 325 | if(start==null || end==null) 326 | { 327 | if(start==null) 328 | { 329 | if(starting.getText().length()>0) 330 | { 331 | starting.setError("Choose location from dropdown."); 332 | } 333 | else 334 | { 335 | Toast.makeText(this,"Please choose a starting point.",Toast.LENGTH_SHORT).show(); 336 | } 337 | } 338 | if(end==null) 339 | { 340 | if(destination.getText().length()>0) 341 | { 342 | destination.setError("Choose location from dropdown."); 343 | } 344 | else 345 | { 346 | Toast.makeText(this,"Please choose a destination.",Toast.LENGTH_SHORT).show(); 347 | } 348 | } 349 | } 350 | else 351 | { 352 | progressDialog = ProgressDialog.show(this, "Please wait.", 353 | "Fetching route information.", true); 354 | Routing routing = new Routing.Builder() 355 | .travelMode(AbstractRouting.TravelMode.DRIVING) 356 | .withListener(this) 357 | .alternativeRoutes(true) 358 | .waypoints(start, end) 359 | .build(); 360 | routing.execute(); 361 | } 362 | } 363 | 364 | 365 | @Override 366 | public void onRoutingFailure(RouteException e) { 367 | // The Routing request failed 368 | progressDialog.dismiss(); 369 | if(e != null) { 370 | Toast.makeText(this, "Error: " + e.getMessage(), Toast.LENGTH_LONG).show(); 371 | }else { 372 | Toast.makeText(this, "Something went wrong, Try again", Toast.LENGTH_SHORT).show(); 373 | } 374 | } 375 | 376 | @Override 377 | public void onRoutingStart() { 378 | // The Routing Request starts 379 | } 380 | 381 | @Override 382 | public void onRoutingSuccess(List route, int shortestRouteIndex) 383 | { 384 | progressDialog.dismiss(); 385 | CameraUpdate center = CameraUpdateFactory.newLatLng(start); 386 | CameraUpdate zoom = CameraUpdateFactory.zoomTo(16); 387 | 388 | map.moveCamera(center); 389 | 390 | 391 | if(polylines.size()>0) { 392 | for (Polyline poly : polylines) { 393 | poly.remove(); 394 | } 395 | } 396 | 397 | polylines = new ArrayList<>(); 398 | //add route(s) to the map. 399 | for (int i = 0; i 46 | * objects 47 | * that contain both the Place ID and the text description from the autocomplete query. 48 | *

49 | * Note that this adapter requires a valid {@link GoogleApiClient}. 50 | * The API client must be maintained in the encapsulating Activity, including all lifecycle and 51 | * connection states. The API client must be connected with the {@link Places#GEO_DATA_API} API. 52 | */ 53 | public class PlaceAutoCompleteAdapter 54 | extends ArrayAdapter implements Filterable { 55 | 56 | private static final String TAG = "PlaceAutocomplete"; 57 | /** 58 | * Current results returned by this adapter. 59 | */ 60 | private ArrayList mResultList; 61 | 62 | /** 63 | * Handles autocomplete requests. 64 | */ 65 | private final GoogleApiClient mGoogleApiClient; 66 | 67 | /** 68 | * The bounds used for Places Geo Data autocomplete API requests. 69 | */ 70 | private LatLngBounds mBounds; 71 | 72 | /** 73 | * The autocomplete filter used to restrict queries to a specific set of place types. 74 | */ 75 | private final AutocompleteFilter mPlaceFilter; 76 | 77 | /** 78 | * Initializes with a resource for text rows and autocomplete query bounds. 79 | * 80 | * @see ArrayAdapter#ArrayAdapter(Context, int) 81 | */ 82 | public PlaceAutoCompleteAdapter(Context context, int resource, GoogleApiClient googleApiClient, 83 | LatLngBounds bounds, AutocompleteFilter filter) { 84 | super(context, resource); 85 | mGoogleApiClient = googleApiClient; 86 | mBounds = bounds; 87 | mPlaceFilter = filter; 88 | } 89 | 90 | /** 91 | * Sets the bounds for all subsequent queries. 92 | */ 93 | public void setBounds(LatLngBounds bounds) { 94 | mBounds = bounds; 95 | } 96 | 97 | /** 98 | * Returns the number of results received in the last autocomplete query. 99 | */ 100 | @Override 101 | public int getCount() { 102 | return mResultList.size(); 103 | } 104 | 105 | /** 106 | * Returns an item from the last autocomplete query. 107 | */ 108 | @Override 109 | public PlaceAutocomplete getItem(int position) { 110 | return mResultList.get(position); 111 | } 112 | 113 | /** 114 | * Returns the filter for the current set of autocomplete results. 115 | */ 116 | @Override 117 | public Filter getFilter() { 118 | Filter filter = new Filter() { 119 | @Override 120 | protected FilterResults performFiltering(CharSequence constraint) { 121 | FilterResults results = new FilterResults(); 122 | // Skip the autocomplete query if no constraints are given. 123 | if (constraint != null) { 124 | // Query the autocomplete API for the (constraint) search string. 125 | mResultList = getAutocomplete(constraint); 126 | if (mResultList != null) { 127 | // The API successfully returned results. 128 | results.values = mResultList; 129 | results.count = mResultList.size(); 130 | } 131 | } 132 | return results; 133 | } 134 | 135 | @Override 136 | protected void publishResults(CharSequence constraint, FilterResults results) { 137 | if (results != null && results.count > 0) { 138 | // The API returned at least one result, update the data. 139 | notifyDataSetChanged(); 140 | } else { 141 | // The API did not return any results, invalidate the data set. 142 | notifyDataSetInvalidated(); 143 | } 144 | } 145 | }; 146 | return filter; 147 | } 148 | 149 | /** 150 | * Submits an autocomplete query to the Places Geo Data Autocomplete API. 151 | *

152 | * objects to store the Place ID and description that the API returns. 153 | * Returns an empty list if no results were found. 154 | * Returns null if the API client is not available or the query did not complete 155 | * successfully. 156 | * This method MUST be called off the main UI thread, as it will block until data is returned 157 | * from the API, which may include a network request. 158 | * 159 | * @param constraint Autocomplete query string 160 | * @return Results from the autocomplete API or null if the query was not successful. 161 | * @see Places#GEO_DATA_API#getAutocomplete(CharSequence) 162 | */ 163 | private ArrayList getAutocomplete(CharSequence constraint) { 164 | if (mGoogleApiClient.isConnected()) { 165 | Log.i(TAG, "Starting autocomplete query for: " + constraint); 166 | 167 | // Submit the query to the autocomplete API and retrieve a PendingResult that will 168 | // contain the results when the query completes. 169 | PendingResult results = 170 | Places.GeoDataApi 171 | .getAutocompletePredictions(mGoogleApiClient, constraint.toString(), 172 | mBounds, mPlaceFilter); 173 | 174 | // This method should have been called off the main UI thread. Block and wait for at most 60s 175 | // for a result from the API. 176 | AutocompletePredictionBuffer autocompletePredictions = results 177 | .await(60, TimeUnit.SECONDS); 178 | 179 | // Confirm that the query completed successfully, otherwise return null 180 | final Status status = autocompletePredictions.getStatus(); 181 | if (!status.isSuccess()) { 182 | Toast.makeText(getContext(), "Error contacting API: " + status.toString(), 183 | Toast.LENGTH_SHORT).show(); 184 | Log.e(TAG, "Error getting autocomplete prediction API call: " + status.getStatusMessage()+status.getStatus().getStatusMessage()); 185 | autocompletePredictions.release(); 186 | return null; 187 | } 188 | 189 | Log.i(TAG, "Query completed. Received " + autocompletePredictions.getCount() 190 | + " predictions."); 191 | 192 | // Copy the results into our own data structure, because we can't hold onto the buffer. 193 | // AutocompletePrediction objects encapsulate the API response (place ID and description). 194 | 195 | Iterator iterator = autocompletePredictions.iterator(); 196 | ArrayList resultList = new ArrayList<>(autocompletePredictions.getCount()); 197 | while (iterator.hasNext()) { 198 | AutocompletePrediction prediction = iterator.next(); 199 | // Get the details of this prediction and copy it into a new PlaceAutocomplete object. 200 | resultList.add(new PlaceAutocomplete(prediction.getPlaceId(), 201 | prediction.getDescription())); 202 | } 203 | 204 | // Release the buffer now that all data has been copied. 205 | autocompletePredictions.release(); 206 | 207 | return resultList; 208 | } 209 | Log.e(TAG, "Google API client is not connected for autocomplete query."); 210 | return null; 211 | } 212 | 213 | /** 214 | * Holder for Places Geo Data Autocomplete API results. 215 | */ 216 | class PlaceAutocomplete { 217 | 218 | public CharSequence placeId; 219 | public CharSequence description; 220 | 221 | PlaceAutocomplete(CharSequence placeId, CharSequence description) { 222 | this.placeId = placeId; 223 | this.description = description; 224 | } 225 | 226 | @Override 227 | public String toString() { 228 | return description.toString(); 229 | } 230 | 231 | 232 | } 233 | 234 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/directions/sample/Util.java: -------------------------------------------------------------------------------- 1 | package com.directions.sample; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | 7 | /** 8 | * Created by Joel on 30/06/2015. 9 | */ 10 | public final class Util { 11 | public static final class Operations { 12 | private Operations() throws InstantiationException { 13 | throw new InstantiationException("This class is not for instantiation"); 14 | } 15 | /** 16 | * Checks to see if the device is online before carrying out any operations. 17 | * 18 | * @return 19 | */ 20 | public static boolean isOnline(Context context) { 21 | ConnectivityManager cm = 22 | (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 23 | NetworkInfo netInfo = cm.getActiveNetworkInfo(); 24 | if (netInfo != null && netInfo.isConnectedOrConnecting()) { 25 | return true; 26 | } 27 | return false; 28 | } 29 | } 30 | private Util() throws InstantiationException { 31 | throw new InstantiationException("This class is not for instantiation"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xhdpi/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/sample/src/main/res/drawable-xhdpi/Thumbs.db -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xhdpi/end_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/sample/src/main/res/drawable-xhdpi/end_green.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xhdpi/ic_send_grey600_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/sample/src/main/res/drawable-xhdpi/ic_send_grey600_48dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xhdpi/pushpin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/sample/src/main/res/drawable-xhdpi/pushpin.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xhdpi/start_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/sample/src/main/res/drawable-xhdpi/start_blue.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/sample/src/main/res/drawable/Thumbs.db -------------------------------------------------------------------------------- /sample/src/main/res/drawable/dotted.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 25 | 26 | 30 | 31 | 36 | 37 | 44 | 45 | 52 | 53 | 59 | 60 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /sample/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 |

4 | 6 | 7 | -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/sample/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/sample/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/sample/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /sample/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #00BCD4 4 | #0097A7 5 | #B2EBF2 6 | #607D8B 7 | #212121 8 | #727272 9 | #FFFFFF 10 | #B6B6B6 11 | -------------------------------------------------------------------------------- /sample/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /sample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Google Directions Sample 3 | 4 | Hello world! 5 | Settings 6 | 7 | -------------------------------------------------------------------------------- /sample/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /screenshots/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/screenshots/Thumbs.db -------------------------------------------------------------------------------- /screenshots/device-2015-06-30-095135.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/screenshots/device-2015-06-30-095135.png -------------------------------------------------------------------------------- /screenshots/device-2015-06-30-095241.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/screenshots/device-2015-06-30-095241.png -------------------------------------------------------------------------------- /screenshots/device-2015-06-30-095323.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/screenshots/device-2015-06-30-095323.png -------------------------------------------------------------------------------- /screenshots/device-2015-06-30-100949.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-alexander/Google-Directions-Android/1020635df008737b2e4b956109e1b44693af95c6/screenshots/device-2015-06-30-100949.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':library', ':sample' --------------------------------------------------------------------------------