diff --git a/dialogflow/.gitignore b/dialogflow/.gitignore
new file mode 100644
index 00000000..39fb081a
--- /dev/null
+++ b/dialogflow/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/dialogflow/README.md b/dialogflow/README.md
new file mode 100644
index 00000000..8b2c0125
--- /dev/null
+++ b/dialogflow/README.md
@@ -0,0 +1,69 @@
+# Dialogflow Sample
+
+This app demonstrates how to make gRPC connections to the [Dialogflow API](https://cloud.google.com/dialogflow-enterprise/)
+
+The app demonstrates how to detect intents:
+- Via Text
+- Via Streaming Audio
+- With Sentiment Analysis
+- With Text-to-Speech
+- With Knowledge Connectors
+
+To call the Dialogflow API from Android, you need to get authorization tokens from Firebase Cloud Messaging for them to be accepted by the Dialogflow API. To get this token, this sample uses a Firebase Function (in Node.js) to generate these tokens on the behalf of a service account to be used by the app when making a request to the Dialogflow API.
+
+## Prerequisites
+- An Android device or emulator
+- Android Studio 3 or later
+
+## Setup
+- Create a project (or use an existing one) in the [Google Cloud Console][cloud-console]
+- Enable the [Dialogflow API](https://console.cloud.google.com/apis/library/dialogflow.googleapis.com).
+- Enable the [IAM Service Account Credentials API](https://pantheon.corp.google.com/apis/library/iamcredentials.googleapis.com).
+- [Enable billing][billing].
+- Be sure that you have gone through the steps by expanding the [Create an agent](https://cloud.google.com/dialogflow-enterprise/docs/quickstart-console#create-an-agent) to create and configure your stopwatch agent.
+- [Import the Dialogflow Agent](https://dialogflow.com/docs/agents/export-import-restore#import) using the `StopwatchAgent.zip` which is located in the `stopwatch` directory.
+- [Create a Service account](https://cloud.google.com/iam/docs/creating-managing-service-accounts) with the following IAM role: `Dialogflow API Client`. Example name: `dialogflow-client`. ([For more info on: how to add roles to a Service Account](https://cloud.google.com/iam/docs/granting-roles-to-service-accounts#granting_access_to_a_service_account_for_a_resource))
+- Enable beta features for:
+ - [Sentiment Analysis](https://cloud.google.com/dialogflow-enterprise/docs/sentiment#enable_beta_features)
+ - [Text-to-Speech](https://cloud.google.com/dialogflow-enterprise/docs/detect-intent-tts#enable_beta_features)
+ - [Knowledge Connectors](https://cloud.google.com/dialogflow-enterprise/docs/knowledge-connectors#enable_beta_features)
+
+### Setup the app
+-Clone this repository `git clone https://github.com/GoogleCloudPlatform/android-docs-samples.git`
+- Replace GCP_PROJECT_ID in strings.xml with your Project ID
+
+### Setup Firebase on the application:
+- Complete the steps for [Add Firebase to your app](https://firebase.google.com/docs/android/setup) and expand the "Create a Firebase project" section for instructions on how to add project to your Firebase console. Note: No need to complete any other sections, they are already done.
+- In the [Firebase console](https://console.firebase.google.com/), open the "Authentication" section under Develop.
+- On the **Sign-in Methods** page, enable the **Anonymous** sign-in method.
+- Give the package name of the app as `com.google.cloud.examples.dialogflow`
+
+### Setup and Deploy the Firebase Function
+The Firebase Function provides auth tokens to your app, You'll be using a provided sample function to be run with this app.
+
+- Follow the steps in this [guide](https://firebase.google.com/docs/functions/get-started) for:
+ - "1. Set up Node.js and the Firebase CLI"
+ - "2. Initialize Firebase SDK for Cloud Functions".
+- Replace `index.js` file with the [provided index.js](https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/master/functions/dialogflow/functions/index.js).
+- Open `index.js`, go to function "generateAccessToken", and replace “SERVICE-ACCOUNT-NAME@YOUR_PROJECT_ID.iam.gserviceaccount.com” with your Service account name (`dialogflow-client`) and project id.
+- Deploy getOAuthToken method by running command:
+```
+firebase deploy --only functions
+```
+- For your "App Engine Default Service Account" add the following IAM role: `Service Account Token Creator` . ([For more info on: how to add roles to a Service Account](https://cloud.google.com/iam/docs/granting-roles-to-service-accounts#granting_access_to_a_service_account_for_a_resource))
+
+- For more info please refer (https://firebase.google.com/docs/functions/get-started).
+
+## Run the app
+- You are now ready to build and run the project. In Android Studio you can do this by clicking the 'Play' button in the toolbar. This will launch the app on the emulator or on the device you've selected.
+- As soon the app launches, it will ask for the google sign-in.
+- After successful signing in, choose the option by selecting a checkbox and click on chat button
+- Type the message to send and click on the send button on the bottom right.
+- Alternatively tap on the mic button to speak and send the message to the Dialogflow.
+
+
+[cloud-console]: https://console.cloud.google.com
+[git]: https://git-scm.com/
+[android-studio]: https://developer.android.com/studio
+[billing]: https://console.cloud.google.com/billing?project=_
+[Firebase]: https://firebase.google.com/
diff --git a/dialogflow/StopwatchAgent.zip b/dialogflow/StopwatchAgent.zip
new file mode 100644
index 00000000..50ac1093
Binary files /dev/null and b/dialogflow/StopwatchAgent.zip differ
diff --git a/dialogflow/app/.gitignore b/dialogflow/app/.gitignore
new file mode 100644
index 00000000..796b96d1
--- /dev/null
+++ b/dialogflow/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/dialogflow/app/build.gradle b/dialogflow/app/build.gradle
new file mode 100644
index 00000000..90df7dba
--- /dev/null
+++ b/dialogflow/app/build.gradle
@@ -0,0 +1,63 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 28
+ defaultConfig {
+ applicationId "com.google.cloud.examples.dialogflow"
+ minSdkVersion 26
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ multiDexEnabled true
+ }
+ buildTypes {
+ release {
+ minifyEnabled true
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ packagingOptions {
+ exclude 'META-INF/DEPENDENCIES'
+ exclude 'META-INF/LICENSE'
+ exclude 'META-INF/LICENSE.txt'
+ exclude 'META-INF/license.txt'
+ exclude 'META-INF/NOTICE'
+ exclude 'META-INF/NOTICE.txt'
+ exclude 'META-INF/notice.txt'
+ exclude 'META-INF/ASL2.0'
+ exclude 'META-INF/INDEX.LIST'
+ exclude 'META-INF/io.netty.versions.properties'
+ }
+}
+
+dependencies {
+
+ implementation 'com.android.support:appcompat-v7:28.0.0'
+ implementation 'com.android.support.constraint:constraint-layout:1.1.3'
+ implementation 'com.android.support:design:28.0.0'
+ configurations.all {
+ resolutionStrategy.force 'com.android.support:support-annotations:25.3.0'
+ }
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation 'androidx.appcompat:appcompat:1.0.2'
+ implementation 'com.google.android.material:material:1.0.0'
+ implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test:runner:1.2.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+
+ implementation 'com.google.firebase:firebase-core:17.0.1'
+ implementation 'com.google.firebase:firebase-auth:18.1.0'
+ implementation 'com.firebaseui:firebase-ui-auth:4.1.0'
+ implementation 'com.google.firebase:firebase-messaging:19.0.1'
+ implementation 'com.google.firebase:firebase-functions:18.1.0'
+ implementation 'com.android.volley:volley:1.1.1'
+ implementation 'com.google.cloud:google-cloud-dialogflow:0.98.0-alpha'
+ implementation group: 'io.grpc', name: 'grpc-okhttp', version: '1.21.0'
+ implementation group: 'io.grpc', name: 'grpc-netty', version: '1.21.0'
+
+}
+
+
+apply plugin: 'com.google.gms.google-services'
diff --git a/dialogflow/app/gradle/wrapper/gradle-wrapper.jar b/dialogflow/app/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..f6b961fd
Binary files /dev/null and b/dialogflow/app/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/dialogflow/app/gradle/wrapper/gradle-wrapper.properties b/dialogflow/app/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..e03e4ccf
--- /dev/null
+++ b/dialogflow/app/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Jul 22 11:29:16 PDT 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
diff --git a/dialogflow/app/gradlew b/dialogflow/app/gradlew
new file mode 100644
index 00000000..cccdd3d5
--- /dev/null
+++ b/dialogflow/app/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/dialogflow/app/gradlew.bat b/dialogflow/app/gradlew.bat
new file mode 100644
index 00000000..e95643d6
--- /dev/null
+++ b/dialogflow/app/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dialogflow/app/proguard-rules.pro b/dialogflow/app/proguard-rules.pro
new file mode 100644
index 00000000..f1b42451
--- /dev/null
+++ b/dialogflow/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/dialogflow/app/src/androidTest/java/com/google/cloud/examples/dialogflow/ExampleInstrumentedTest.java b/dialogflow/app/src/androidTest/java/com/google/cloud/examples/dialogflow/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..98bb2547
--- /dev/null
+++ b/dialogflow/app/src/androidTest/java/com/google/cloud/examples/dialogflow/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.google.cloud.examples.dialogflow;
+
+import android.content.Context;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.example.mlapitest", appContext.getPackageName());
+ }
+}
diff --git a/dialogflow/app/src/main/AndroidManifest.xml b/dialogflow/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..726e7fa0
--- /dev/null
+++ b/dialogflow/app/src/main/AndroidManifest.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/AppController.java b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/AppController.java
new file mode 100644
index 00000000..096b614f
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/AppController.java
@@ -0,0 +1,43 @@
+package com.google.cloud.examples.dialogflow;
+
+import android.app.Application;
+
+import com.google.firebase.functions.FirebaseFunctions;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+public class AppController extends Application {
+
+ public static final String TOKEN_RECEIVED = "TOKEN_RECEIVED";
+ public static String PROJECT_ID = "";
+ public static final String SESSION_ID = "sessionId";
+ public static String firebaseInstanceId = "";
+
+ public static String token = "";
+ public static Date expiryTime;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ PROJECT_ID = getApplicationContext().getString(R.string.gcp_project_id);
+ }
+
+ /**
+ * function to call the firebase function which will send the fcm message containing token and expiry time to the device
+ */
+ public static void callFirebaseFunction() {
+ Map data = new HashMap<>();
+ data.put("deviceID", AppController.firebaseInstanceId);
+
+ FirebaseFunctions firebaseFunctions;
+ firebaseFunctions = FirebaseFunctions.getInstance();
+
+ firebaseFunctions
+ .getHttpsCallable("getOAuthToken")
+ .call(data);
+ }
+
+
+}
diff --git a/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/adapter/ChatRecyclerViewAdapter.java b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/adapter/ChatRecyclerViewAdapter.java
new file mode 100644
index 00000000..64c0ca81
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/adapter/ChatRecyclerViewAdapter.java
@@ -0,0 +1,67 @@
+package com.google.cloud.examples.dialogflow.adapter;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.cloud.examples.dialogflow.R;
+import com.google.cloud.examples.dialogflow.model.ChatMsgModel;
+
+import java.util.ArrayList;
+
+public class ChatRecyclerViewAdapter extends RecyclerView.Adapter {
+
+ private ArrayList chatMsgModels;
+
+ public ChatRecyclerViewAdapter(ArrayList chatMsgModels) {
+ this.chatMsgModels = chatMsgModels;
+
+ }
+
+ @Override
+ public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View itemView = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.custom_chat_recyclerview_item, parent, false);
+
+ return new MyViewHolder(itemView);
+ }
+
+ @Override
+ public void onBindViewHolder(MyViewHolder holder, final int position) {
+ final ChatMsgModel chatMsgModel = chatMsgModels.get(position);
+
+ if (chatMsgModel.getType() == 1) { // Message Sent
+ holder.tvMsgSent.setText(chatMsgModel.getMsg());
+ holder.tvMsgSent.setVisibility(View.VISIBLE);
+ holder.tvMsgReceived.setVisibility(View.GONE);
+ } else {
+ holder.tvMsgReceived.setText(chatMsgModel.getMsg());
+ holder.tvMsgReceived.setVisibility(View.VISIBLE);
+ holder.tvMsgSent.setVisibility(View.GONE);
+ }
+
+
+ }
+
+ @Override
+ public int getItemCount() {
+ return chatMsgModels.size();
+ }
+
+ public class MyViewHolder extends RecyclerView.ViewHolder {
+ RelativeLayout rlMain;
+ TextView tvMsgSent;
+ TextView tvMsgReceived;
+
+ public MyViewHolder(View view) {
+ super(view);
+ rlMain = view.findViewById(R.id.rlMain);
+ tvMsgSent = view.findViewById(R.id.tvMsgSent);
+ tvMsgReceived = view.findViewById(R.id.tvMsgReceived);
+ }
+ }
+}
\ No newline at end of file
diff --git a/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/model/ChatMsgModel.java b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/model/ChatMsgModel.java
new file mode 100644
index 00000000..9916154b
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/model/ChatMsgModel.java
@@ -0,0 +1,21 @@
+package com.google.cloud.examples.dialogflow.model;
+
+public class ChatMsgModel {
+
+ private String msg;
+ private int type;
+
+ public ChatMsgModel(String msg, int type) {
+ this.msg = msg;
+ this.type = type;
+ }
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+}
diff --git a/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/service/MyFirebaseCloudMessagingService.java b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/service/MyFirebaseCloudMessagingService.java
new file mode 100644
index 00000000..491ee9d2
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/service/MyFirebaseCloudMessagingService.java
@@ -0,0 +1,47 @@
+package com.google.cloud.examples.dialogflow.service;
+
+import android.content.Intent;
+import android.util.Log;
+
+import com.google.cloud.examples.dialogflow.AppController;
+import com.google.firebase.messaging.FirebaseMessagingService;
+import com.google.firebase.messaging.RemoteMessage;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Locale;
+
+public class MyFirebaseCloudMessagingService extends FirebaseMessagingService {
+
+ private static final String TAG = MyFirebaseCloudMessagingService.class.getSimpleName();
+
+ @Override
+ public void onMessageReceived(RemoteMessage remoteMessage) {
+ Log.i("FirebaseMessage", "From: " + remoteMessage.getFrom());
+
+ // Check if message contains a notification payload.
+ if (remoteMessage.getNotification() != null) {
+ Log.i(TAG, "Notification Body: " + remoteMessage.getNotification().getBody());
+ handleNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody());
+ }
+ }
+
+ /**
+ * function to save the token data in the AppController
+ *
+ * @param expiryTime : expiry time received from FCM
+ * @param token : token received from FCM
+ */
+ private void handleNotification(String expiryTime, String token) {
+ try {
+ AppController.expiryTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).parse(expiryTime);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ AppController.token = token;
+
+ Intent intent = new Intent(AppController.TOKEN_RECEIVED);
+ sendBroadcast(intent);
+ }
+
+}
\ No newline at end of file
diff --git a/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/service/MyFirebaseInstanceIDService.java b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/service/MyFirebaseInstanceIDService.java
new file mode 100644
index 00000000..bc5ee3d0
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/service/MyFirebaseInstanceIDService.java
@@ -0,0 +1,16 @@
+package com.google.cloud.examples.dialogflow.service;
+
+import com.google.cloud.examples.dialogflow.AppController;
+import com.google.firebase.messaging.FirebaseMessagingService;
+
+public class MyFirebaseInstanceIDService extends FirebaseMessagingService {
+
+ @Override
+ public void onNewToken(String refreshedToken) {
+ super.onNewToken(refreshedToken);
+
+ AppController.firebaseInstanceId = refreshedToken;
+
+ }
+
+}
\ No newline at end of file
diff --git a/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/ui/ChatActivity.java b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/ui/ChatActivity.java
new file mode 100644
index 00000000..e6ffb936
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/ui/ChatActivity.java
@@ -0,0 +1,410 @@
+package com.google.cloud.examples.dialogflow.ui;
+
+import android.Manifest;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.speech.RecognizerIntent;
+import android.speech.tts.TextToSpeech;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.PopupMenu;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.android.gms.tasks.Task;
+import com.google.cloud.examples.dialogflow.AppController;
+import com.google.cloud.examples.dialogflow.R;
+import com.google.cloud.examples.dialogflow.adapter.ChatRecyclerViewAdapter;
+import com.google.cloud.examples.dialogflow.model.ChatMsgModel;
+import com.google.cloud.examples.dialogflow.utils.ApiRequest;
+import com.google.firebase.auth.AuthResult;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.iid.FirebaseInstanceId;
+import com.google.firebase.iid.InstanceIdResult;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+public class ChatActivity extends AppCompatActivity {
+
+ private static TextToSpeech textToSpeech;
+ private static ChatRecyclerViewAdapter chatRecyclerViewAdapter;
+ private static ArrayList chatMsgModels;
+ private static RecyclerView rvChats;
+ private FirebaseAuth firebaseAuth;
+ private ApiRequest apiRequest;
+
+ private EditText etMsg;
+ private ImageButton btnSend;
+ private ImageButton btnMic;
+ private AlertDialog alert;
+
+ private ImageButton ibMore;
+
+ private boolean tts = false;
+ private boolean knowledge = false;
+ private boolean sentiment = false;
+
+ private String voiceInput = "";
+
+ /**
+ * Broadcast receiver to hide the progress dialog when token is received
+ */
+ private BroadcastReceiver br = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ alert.dismiss();
+ if (!voiceInput.equals("")) {
+ sendMsg(voiceInput);
+ } else if (!etMsg.getText().toString().trim().equals("")) {
+ sendMsg(etMsg.getText().toString().trim());
+ }
+ }
+ };
+
+ /**
+ * function to addMessage in the recyclerview
+ * @param msg : message to add
+ * @param type : Type of message (sent|received)
+ * @param voiceFeedback : Whether to output response as voice
+ */
+ public static void addMsg(String msg, int type, boolean voiceFeedback) {
+ chatMsgModels.add(new ChatMsgModel(msg, type));
+ chatRecyclerViewAdapter.notifyDataSetChanged();
+ scrollToBottom();
+ if (voiceFeedback) {
+ voiceOutput(msg);
+ }
+ }
+
+ /**
+ * function to speak the message
+ * @param msg : message to speak
+ */
+ private static void voiceOutput(String msg) {
+ textToSpeech.speak(msg, TextToSpeech.QUEUE_ADD, null, null);
+ }
+
+ /**
+ * function to scroll the recyclerview at the bottom after each message sent or received
+ */
+ private static void scrollToBottom() {
+ new Handler().post(new Runnable() {
+ @Override
+ public void run() {
+ if (chatMsgModels.size() > 0) {
+ rvChats.smoothScrollToPosition(chatMsgModels.size() - 1);
+ }
+ }
+ });
+ }
+
+ /**
+ * function to show the progress dialog
+ */
+ private void showProgressDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setMessage("Please wait...");
+ builder.setCancelable(false);
+
+ alert = builder.create();
+ alert.show();
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_chat);
+
+ checkPermissions();
+
+ signInAnonymously();
+ getFirebaseInstanceId();
+
+ initViews();
+ setupRecyclerView();
+ initListeners();
+
+ apiRequest = new ApiRequest();
+
+ initTextToSpeech();
+
+ }
+
+ /**
+ * function to initialize the Text To Speech for voice output
+ */
+ private void initTextToSpeech() {
+ textToSpeech = new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
+ @Override
+ public void onInit(int status) {
+ if (status == TextToSpeech.SUCCESS) {
+ int ttsLang = textToSpeech.setLanguage(Locale.US);
+
+ if (ttsLang == TextToSpeech.LANG_MISSING_DATA
+ || ttsLang == TextToSpeech.LANG_NOT_SUPPORTED) {
+ Log.e("TTS", "The Language is not supported!");
+ } else {
+ Log.i("TTS", "Language Supported.");
+ }
+ Log.i("TTS", "Initialization success.");
+ } else {
+ Toast.makeText(getApplicationContext(), "TTS Initialization failed!", Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+
+ }
+
+ /**
+ * function to initialize the views
+ */
+ private void initViews() {
+ etMsg = findViewById(R.id.etMsg);
+ btnSend = findViewById(R.id.btnSend);
+ btnMic = findViewById(R.id.btnMic);
+ rvChats = findViewById(R.id.rvChat);
+ ibMore = findViewById(R.id.ibMore);
+ }
+
+ /**
+ * function to initialize the recyclerview
+ */
+ private void setupRecyclerView() {
+ rvChats.setLayoutManager(new LinearLayoutManager(this));
+ chatMsgModels = new ArrayList<>();
+
+ chatRecyclerViewAdapter = new ChatRecyclerViewAdapter(chatMsgModels);
+ rvChats.setAdapter(chatRecyclerViewAdapter);
+ }
+
+ /**
+ * function to initialize the onClick listeners
+ */
+ private void initListeners() {
+ btnSend.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (checkSignIn()) {
+ sendMsg(etMsg.getText().toString());
+ scrollToBottom();
+ } else {
+ signInAnonymously();
+ }
+ }
+ });
+
+ btnMic.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (checkSignIn()) {
+ promptSpeechInput();
+ }
+ }
+ });
+
+ ibMore.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showMorePopup();
+ }
+ });
+ }
+
+ /**
+ * function to check the user is logged in
+ * @return boolean : returns true if user is logged inn
+ */
+ private boolean checkSignIn() {
+ return firebaseAuth != null && firebaseAuth.getCurrentUser() != null;
+ }
+
+ /**
+ * function to send the message
+ *
+ * @param msg : message sent from user
+ */
+ private void sendMsg(String msg) {
+ if (!TextUtils.isEmpty(msg)) {
+ // check if the token is received and expiry time is received and not expired
+ if (AppController.expiryTime != null && !AppController.token.equals("") && AppController.expiryTime.getTime() > System.currentTimeMillis()) {
+ addMsg(msg, 1, false);
+ etMsg.setText("");
+ voiceInput = "";
+ apiRequest.callAPI(this, AppController.token, AppController.expiryTime, msg, tts, sentiment, knowledge);
+ } else {
+ // get new token if expired or not received
+ getNewToken();
+ }
+ } else {
+ Toast.makeText(this, "Please enter or say some message to send.", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ private void getNewToken() {
+ showProgressDialog();
+ AppController.callFirebaseFunction();
+ }
+
+ private void promptSpeechInput() {
+ Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
+ intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
+ RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
+ intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1000);
+ intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "en-US");
+ intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
+ "Speak");
+ try {
+ startActivityForResult(intent, 101);
+ } catch (ActivityNotFoundException a) {
+ Toast.makeText(getApplicationContext(),
+ "Not Supported",
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (resultCode == RESULT_OK) {
+ if (requestCode == 101) {
+ ArrayList result = data
+ .getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
+ voiceInput = result.get(0);
+ sendMsg(result.get(0));
+ }
+ }
+ }
+
+ public void checkPermissions() {
+
+ ArrayList arrPerm = new ArrayList<>();
+ arrPerm.add(Manifest.permission.INTERNET);
+ arrPerm.add(Manifest.permission.RECORD_AUDIO);
+
+
+ if (!arrPerm.isEmpty()) {
+ String[] permissions = new String[arrPerm.size()];
+ permissions = arrPerm.toArray(permissions);
+ ActivityCompat.requestPermissions(this, permissions, 1);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ finish();
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ IntentFilter intentFilter = new IntentFilter(AppController.TOKEN_RECEIVED);
+ registerReceiver(br, intentFilter);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (br != null) {
+ try {
+ unregisterReceiver(br);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (textToSpeech != null) {
+ textToSpeech.stop();
+ textToSpeech.shutdown();
+ }
+ }
+
+ private void getFirebaseInstanceId() {
+ FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener() {
+ @Override
+ public void onSuccess(InstanceIdResult instanceIdResult) {
+ String deviceToken = instanceIdResult.getToken();
+ AppController.firebaseInstanceId = deviceToken;
+ Log.i("fcmId", deviceToken);
+ }
+ });
+ }
+
+ private void signInAnonymously() {
+ firebaseAuth = FirebaseAuth.getInstance();
+ firebaseAuth.signInAnonymously()
+ .addOnCompleteListener(this, new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ // Sign in success, update UI with the signed-in user's information
+ Toast.makeText(ChatActivity.this, "Sign In was successful",
+ Toast.LENGTH_SHORT).show();
+ } else {
+ // If sign in fails, display a message to the user.
+ Toast.makeText(ChatActivity.this, "Authentication failed.",
+ Toast.LENGTH_SHORT).show();
+ }
+
+ }
+ });
+ }
+
+ public void showMorePopup() {
+ PopupMenu popup = new PopupMenu(this, ibMore);
+ popup.inflate(R.menu.main_menu);
+ popup.getMenu().findItem(R.id.action_tts).setChecked(tts);
+ popup.getMenu().findItem(R.id.action_sentiment).setChecked(sentiment);
+ popup.getMenu().findItem(R.id.action_knowledge).setChecked(knowledge);
+ popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+
+ switch (item.getItemId()) {
+ case R.id.action_tts:
+ tts = !tts;
+ item.setChecked(!item.isChecked());
+ break;
+ case R.id.action_sentiment:
+ sentiment = !sentiment;
+ item.setChecked(!item.isChecked());
+ break;
+ case R.id.action_knowledge:
+ knowledge = !knowledge;
+ item.setChecked(!item.isChecked());
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+ });
+ popup.show();
+ }
+
+}
diff --git a/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/utils/ApiRequest.java b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/utils/ApiRequest.java
new file mode 100644
index 00000000..608f68b5
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/utils/ApiRequest.java
@@ -0,0 +1,248 @@
+package com.google.cloud.examples.dialogflow.utils;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.google.api.gax.core.FixedCredentialsProvider;
+import com.google.auth.Credentials;
+import com.google.auth.oauth2.AccessToken;
+import com.google.auth.oauth2.GoogleCredentials;
+import com.google.cloud.dialogflow.v2beta1.DetectIntentRequest;
+import com.google.cloud.dialogflow.v2beta1.DetectIntentResponse;
+import com.google.cloud.dialogflow.v2beta1.KnowledgeAnswers;
+import com.google.cloud.dialogflow.v2beta1.KnowledgeBaseName;
+import com.google.cloud.dialogflow.v2beta1.KnowledgeBasesSettings;
+import com.google.cloud.dialogflow.v2beta1.OutputAudioConfig;
+import com.google.cloud.dialogflow.v2beta1.OutputAudioEncoding;
+import com.google.cloud.dialogflow.v2beta1.QueryInput;
+import com.google.cloud.dialogflow.v2beta1.QueryParameters;
+import com.google.cloud.dialogflow.v2beta1.QueryResult;
+import com.google.cloud.dialogflow.v2beta1.SentimentAnalysisRequestConfig;
+import com.google.cloud.dialogflow.v2beta1.SessionName;
+import com.google.cloud.dialogflow.v2beta1.SessionsClient;
+import com.google.cloud.dialogflow.v2beta1.SessionsSettings;
+import com.google.cloud.dialogflow.v2beta1.TextInput;
+import com.google.cloud.examples.dialogflow.AppController;
+import com.google.cloud.examples.dialogflow.ui.ChatActivity;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.TimeZone;
+
+
+public class ApiRequest {
+
+ private String token = null;
+ private Date tokenExpiration = null;
+ private String response = "";
+
+ public ApiRequest() {
+ // Variables needed to retrieve an auth token
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
+
+ /**
+ * function to call: detect Intent Sentiment Analysis | Detect Intent With TTS | KnowledgeBase
+ *
+ * @param context : context
+ * @param accessToken : access token received from fcm
+ * @param expiryTime : expiry time received from fcm
+ * @param msg : message sent by the user
+ * @param tts : send message to text to speech if true
+ * @param sentiment : send message to sentiment analysis if true
+ * @param knowledge : send message to knowledge base if true
+ */
+ public void callAPI(Context context, String accessToken, Date expiryTime, String msg, boolean tts, boolean sentiment, boolean knowledge) {
+ Toast.makeText(context, "Calling the API", Toast.LENGTH_SHORT).show();
+ response = "";
+ this.token = accessToken;
+ this.tokenExpiration = expiryTime;
+ getResults(msg, tts, sentiment, knowledge);
+ }
+
+ private void sendMsgToScreen(String response, boolean voiceFeedback) {
+ ChatActivity.addMsg(response, 0, voiceFeedback);
+ }
+
+ /**
+ * function to getting the results from the dialogflow
+ *
+ * @param msg : message sent by the user
+ * @param tts : send message to text to speech if true
+ * @param sentiment : send message to sentiment analysis if true
+ * @param knowledge : send message to knowledge base if true
+ */
+ private void getResults(String msg, boolean tts, boolean sentiment, boolean knowledge) {
+ try {
+ AccessToken accessToken = new AccessToken(token, tokenExpiration);
+ Credentials credentials = GoogleCredentials.create(accessToken);
+ FixedCredentialsProvider fixedCredentialsProvider = FixedCredentialsProvider.create(credentials);
+ SessionsSettings sessionsSettings = SessionsSettings.newBuilder().setCredentialsProvider(fixedCredentialsProvider).build();
+ SessionsClient sessionsClient = SessionsClient.create(sessionsSettings);
+ SessionName sessionName = SessionName.of(AppController.PROJECT_ID, AppController.SESSION_ID);
+ System.out.println("Session Path: " + sessionName.toString());
+
+ // Set the text (hello) and language code (en-US) for the query
+ TextInput textInput = TextInput.newBuilder()
+ .setText(msg)
+ .setLanguageCode("en-US")
+ .build();
+
+ // Build the query with the TextInput
+ QueryInput queryInput = QueryInput.newBuilder()
+ .setText(textInput)
+ .build();
+
+ DetectIntentRequest detectIntentRequest = getDetectIntentRequest(sessionName, queryInput, tts, sentiment, knowledge, fixedCredentialsProvider);
+ if (detectIntentRequest != null) {
+ DetectIntentResponse detectIntentResponse = sessionsClient.detectIntent(detectIntentRequest);
+ // Display the query result
+ QueryResult queryResult = detectIntentResponse.getQueryResult();
+ StringBuilder knowledgebaseResponse = new StringBuilder();
+ String response;
+
+ if (knowledge) {
+ KnowledgeAnswers knowledgeAnswers = queryResult.getKnowledgeAnswers();
+ for (KnowledgeAnswers.Answer answer : knowledgeAnswers.getAnswersList()) {
+ knowledgebaseResponse.append(answer.getAnswer()).append("\n");
+ }
+ }
+
+ if (sentiment) {
+ response = queryResult.getFulfillmentText() + " (Magnitude " + queryResult.getSentimentAnalysisResult().getQueryTextSentiment().getMagnitude() + "" + "; score: " + queryResult.getSentimentAnalysisResult().getQueryTextSentiment().getScore() + ")";
+ } else {
+ response = queryResult.getFulfillmentText();
+ }
+
+ prepareResult(response, knowledgebaseResponse.toString(), tts, sentiment, knowledge);
+ } else {
+ Log.i("ApiRequest", "DetectIntentRequest is null");
+ }
+
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ /**
+ * function to prepare the dialogflow response
+ *
+ * @param response : response from tts|sentiment
+ * @param knowledgebaseResponse : response from knowledge base
+ * @param tts : if text to speech is true
+ * @param sentiment : if sentiment analysis is true
+ * @param knowledge : if knowledge base is true
+ */
+ private void prepareResult(String response, String knowledgebaseResponse, boolean tts, boolean sentiment, boolean knowledge) {
+ if (TextUtils.isEmpty(knowledgebaseResponse) && TextUtils.isEmpty(response)) {
+ sendMsgToScreen("No Response", tts);
+ } else if (!TextUtils.isEmpty(knowledgebaseResponse)) {
+ sendMsgToScreen(knowledgebaseResponse, tts);
+ } else if (tts || sentiment) {
+ sendMsgToScreen(response, tts);
+ } else if (!knowledge) {
+ sendMsgToScreen(response, tts);
+ } else {
+ sendMsgToScreen("No Response", tts);
+ }
+ }
+
+ /**
+ * function to get the DetectIntentRequest object
+ *
+ * @param sessionName : sessionName object
+ * @param queryInput : queryInput object
+ * @param tts : if text to speech is true
+ * @param sentiment : if sentiment analysis is true
+ * @param knowledge : if knowledge base is true
+ * @param fixedCredentialsProvider : fixedCredentialsProvider for knowledgebase
+ * @return : DetectIntentRequest object
+ */
+ private DetectIntentRequest getDetectIntentRequest(SessionName sessionName, QueryInput queryInput, boolean tts, boolean sentiment, boolean knowledge, FixedCredentialsProvider fixedCredentialsProvider) {
+ try {
+ OutputAudioEncoding audioEncoding = OutputAudioEncoding.OUTPUT_AUDIO_ENCODING_LINEAR_16;
+ int sampleRateHertz = 16000;
+ OutputAudioConfig outputAudioConfig = OutputAudioConfig.newBuilder()
+ .setAudioEncoding(audioEncoding)
+ .setSampleRateHertz(sampleRateHertz)
+ .build();
+
+ SentimentAnalysisRequestConfig sentimentAnalysisRequestConfig = SentimentAnalysisRequestConfig.newBuilder().setAnalyzeQueryTextSentiment(true).build();
+
+ DetectIntentRequest detectIntentRequest;
+ KnowledgeBaseName knowledgeBaseName = null;
+
+ if (knowledge) {
+ KnowledgeBasesSettings knowledgeSessionsSettings = KnowledgeBasesSettings.newBuilder().setCredentialsProvider(fixedCredentialsProvider).build();
+ ArrayList knowledgeBaseNames = KnowledgebaseUtils.listKnowledgeBases(AppController.PROJECT_ID, knowledgeSessionsSettings);
+ if (knowledgeBaseNames.size() > 0) {
+ String knowledgebaseId = knowledgeBaseNames.get(0);
+ knowledgebaseId = knowledgebaseId.substring(knowledgebaseId.lastIndexOf("/") + 1);
+ knowledgeBaseName = KnowledgeBaseName.of(AppController.PROJECT_ID, knowledgebaseId);
+ }
+ }
+
+ if (tts && sentiment && knowledge && knowledgeBaseName != null) {
+ QueryParameters queryParameters = QueryParameters.newBuilder()
+ .addKnowledgeBaseNames(knowledgeBaseName.toString())
+ .setSentimentAnalysisRequestConfig(sentimentAnalysisRequestConfig)
+ .build();
+ detectIntentRequest = DetectIntentRequest.newBuilder()
+ .setSession(sessionName.toString())
+ .setQueryInput(queryInput)
+ .setQueryParams(queryParameters)
+ .setOutputAudioConfig(outputAudioConfig)
+ .build();
+ } else if (tts && sentiment) {
+ QueryParameters queryParameters = QueryParameters.newBuilder()
+ .setSentimentAnalysisRequestConfig(sentimentAnalysisRequestConfig)
+ .build();
+ detectIntentRequest = DetectIntentRequest.newBuilder()
+ .setSession(sessionName.toString())
+ .setQueryInput(queryInput)
+ .setQueryParams(queryParameters)
+ .setOutputAudioConfig(outputAudioConfig)
+ .build();
+ } else if (tts) {
+ detectIntentRequest = DetectIntentRequest.newBuilder()
+ .setSession(sessionName.toString())
+ .setQueryInput(queryInput)
+ .setOutputAudioConfig(outputAudioConfig)
+ .build();
+ } else if (sentiment) {
+ QueryParameters queryParameters = QueryParameters.newBuilder()
+ .setSentimentAnalysisRequestConfig(sentimentAnalysisRequestConfig)
+ .build();
+ detectIntentRequest = DetectIntentRequest.newBuilder()
+ .setSession(sessionName.toString())
+ .setQueryInput(queryInput)
+ .setQueryParams(queryParameters)
+ .build();
+ } else if (knowledge) {
+ QueryParameters queryParameters = QueryParameters.newBuilder()
+ .addKnowledgeBaseNames(knowledgeBaseName.toString())
+ .build();
+ detectIntentRequest = DetectIntentRequest.newBuilder()
+ .setSession(sessionName.toString())
+ .setQueryInput(queryInput)
+ .setQueryParams(queryParameters)
+ .build();
+ } else {
+ detectIntentRequest = DetectIntentRequest.newBuilder()
+ .setSession(sessionName.toString())
+ .setQueryInput(queryInput)
+ .build();
+ }
+
+ return detectIntentRequest;
+ } catch (Exception ex) {
+ return null;
+ }
+ }
+}
+
+
diff --git a/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/utils/KnowledgebaseUtils.java b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/utils/KnowledgebaseUtils.java
new file mode 100644
index 00000000..87915fea
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/utils/KnowledgebaseUtils.java
@@ -0,0 +1,34 @@
+package com.google.cloud.examples.dialogflow.utils;
+
+
+import com.google.cloud.dialogflow.v2beta1.KnowledgeBase;
+import com.google.cloud.dialogflow.v2beta1.KnowledgeBasesClient;
+import com.google.cloud.dialogflow.v2beta1.KnowledgeBasesSettings;
+import com.google.cloud.dialogflow.v2beta1.ProjectName;
+
+import java.util.ArrayList;
+
+public class KnowledgebaseUtils {
+
+ /**
+ * List Knowledge bases
+ *
+ * @param projectId Project/agent id.
+ */
+ public static ArrayList listKnowledgeBases(String projectId, KnowledgeBasesSettings knowledgeBasesSettings) throws Exception {
+ ArrayList ids = new ArrayList<>();
+ // Instantiates a client
+ try (KnowledgeBasesClient knowledgeBasesClient = KnowledgeBasesClient.create(knowledgeBasesSettings)) {
+ // Set the entity type name using the projectID (my-project-id) and entityTypeId (KIND_LIST)
+ ProjectName projectName = ProjectName.of(projectId);
+ for (KnowledgeBase knowledgeBase :
+ knowledgeBasesClient.listKnowledgeBases(projectName).iterateAll()) {
+ System.out.format(" - Display Name: %s\n", knowledgeBase.getDisplayName());
+ System.out.format(" - Knowledge ID: %s\n", knowledgeBase.getName());
+ ids.add(knowledgeBase.getName());
+ }
+ }
+
+ return ids;
+ }
+}
diff --git a/dialogflow/app/src/main/res/drawable-hdpi/ic_mic.png b/dialogflow/app/src/main/res/drawable-hdpi/ic_mic.png
new file mode 100755
index 00000000..626b816a
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-hdpi/ic_mic.png differ
diff --git a/dialogflow/app/src/main/res/drawable-hdpi/ic_more_vert.png b/dialogflow/app/src/main/res/drawable-hdpi/ic_more_vert.png
new file mode 100755
index 00000000..51041c2e
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-hdpi/ic_more_vert.png differ
diff --git a/dialogflow/app/src/main/res/drawable-hdpi/ic_send.png b/dialogflow/app/src/main/res/drawable-hdpi/ic_send.png
new file mode 100755
index 00000000..04c04401
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-hdpi/ic_send.png differ
diff --git a/dialogflow/app/src/main/res/drawable-mdpi/ic_mic.png b/dialogflow/app/src/main/res/drawable-mdpi/ic_mic.png
new file mode 100755
index 00000000..db2e0156
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-mdpi/ic_mic.png differ
diff --git a/dialogflow/app/src/main/res/drawable-mdpi/ic_more_vert.png b/dialogflow/app/src/main/res/drawable-mdpi/ic_more_vert.png
new file mode 100755
index 00000000..00e448a7
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-mdpi/ic_more_vert.png differ
diff --git a/dialogflow/app/src/main/res/drawable-mdpi/ic_send.png b/dialogflow/app/src/main/res/drawable-mdpi/ic_send.png
new file mode 100755
index 00000000..6c9e2983
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-mdpi/ic_send.png differ
diff --git a/dialogflow/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/dialogflow/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 00000000..c7bd21db
--- /dev/null
+++ b/dialogflow/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dialogflow/app/src/main/res/drawable-xhdpi/ic_mic.png b/dialogflow/app/src/main/res/drawable-xhdpi/ic_mic.png
new file mode 100755
index 00000000..96032684
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-xhdpi/ic_mic.png differ
diff --git a/dialogflow/app/src/main/res/drawable-xhdpi/ic_more_vert.png b/dialogflow/app/src/main/res/drawable-xhdpi/ic_more_vert.png
new file mode 100755
index 00000000..6925c884
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-xhdpi/ic_more_vert.png differ
diff --git a/dialogflow/app/src/main/res/drawable-xhdpi/ic_send.png b/dialogflow/app/src/main/res/drawable-xhdpi/ic_send.png
new file mode 100755
index 00000000..8e78bf0a
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-xhdpi/ic_send.png differ
diff --git a/dialogflow/app/src/main/res/drawable-xxhdpi/ic_mic.png b/dialogflow/app/src/main/res/drawable-xxhdpi/ic_mic.png
new file mode 100755
index 00000000..7184522f
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-xxhdpi/ic_mic.png differ
diff --git a/dialogflow/app/src/main/res/drawable-xxhdpi/ic_more_vert.png b/dialogflow/app/src/main/res/drawable-xxhdpi/ic_more_vert.png
new file mode 100755
index 00000000..08bfd003
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-xxhdpi/ic_more_vert.png differ
diff --git a/dialogflow/app/src/main/res/drawable-xxhdpi/ic_send.png b/dialogflow/app/src/main/res/drawable-xxhdpi/ic_send.png
new file mode 100755
index 00000000..d589b778
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-xxhdpi/ic_send.png differ
diff --git a/dialogflow/app/src/main/res/drawable-xxxhdpi/ic_mic.png b/dialogflow/app/src/main/res/drawable-xxxhdpi/ic_mic.png
new file mode 100755
index 00000000..227df2b0
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-xxxhdpi/ic_mic.png differ
diff --git a/dialogflow/app/src/main/res/drawable-xxxhdpi/ic_more_vert.png b/dialogflow/app/src/main/res/drawable-xxxhdpi/ic_more_vert.png
new file mode 100755
index 00000000..e16d58f4
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-xxxhdpi/ic_more_vert.png differ
diff --git a/dialogflow/app/src/main/res/drawable-xxxhdpi/ic_send.png b/dialogflow/app/src/main/res/drawable-xxxhdpi/ic_send.png
new file mode 100755
index 00000000..08172491
Binary files /dev/null and b/dialogflow/app/src/main/res/drawable-xxxhdpi/ic_send.png differ
diff --git a/dialogflow/app/src/main/res/drawable/ic_launcher_background.xml b/dialogflow/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 00000000..d5fccc53
--- /dev/null
+++ b/dialogflow/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dialogflow/app/src/main/res/drawable/rounded_corner.xml b/dialogflow/app/src/main/res/drawable/rounded_corner.xml
new file mode 100644
index 00000000..982884bd
--- /dev/null
+++ b/dialogflow/app/src/main/res/drawable/rounded_corner.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dialogflow/app/src/main/res/drawable/rounded_corner_edittext.xml b/dialogflow/app/src/main/res/drawable/rounded_corner_edittext.xml
new file mode 100644
index 00000000..2619e851
--- /dev/null
+++ b/dialogflow/app/src/main/res/drawable/rounded_corner_edittext.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dialogflow/app/src/main/res/layout/activity_chat.xml b/dialogflow/app/src/main/res/layout/activity_chat.xml
new file mode 100644
index 00000000..fbb224cf
--- /dev/null
+++ b/dialogflow/app/src/main/res/layout/activity_chat.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dialogflow/app/src/main/res/layout/content_main.xml b/dialogflow/app/src/main/res/layout/content_main.xml
new file mode 100644
index 00000000..cbaaa0bf
--- /dev/null
+++ b/dialogflow/app/src/main/res/layout/content_main.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dialogflow/app/src/main/res/layout/custom_chat_recyclerview_item.xml b/dialogflow/app/src/main/res/layout/custom_chat_recyclerview_item.xml
new file mode 100644
index 00000000..70d3a8af
--- /dev/null
+++ b/dialogflow/app/src/main/res/layout/custom_chat_recyclerview_item.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dialogflow/app/src/main/res/menu/main_menu.xml b/dialogflow/app/src/main/res/menu/main_menu.xml
new file mode 100644
index 00000000..83fc54a9
--- /dev/null
+++ b/dialogflow/app/src/main/res/menu/main_menu.xml
@@ -0,0 +1,20 @@
+
\ No newline at end of file
diff --git a/dialogflow/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/dialogflow/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..eca70cfe
--- /dev/null
+++ b/dialogflow/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/dialogflow/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/dialogflow/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 00000000..eca70cfe
--- /dev/null
+++ b/dialogflow/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/dialogflow/app/src/main/res/mipmap-hdpi/ic_launcher.png b/dialogflow/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..898f3ed5
Binary files /dev/null and b/dialogflow/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/dialogflow/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/dialogflow/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 00000000..dffca360
Binary files /dev/null and b/dialogflow/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/dialogflow/app/src/main/res/mipmap-mdpi/ic_launcher.png b/dialogflow/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..64ba76f7
Binary files /dev/null and b/dialogflow/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/dialogflow/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/dialogflow/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 00000000..dae5e082
Binary files /dev/null and b/dialogflow/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/dialogflow/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/dialogflow/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..e5ed4659
Binary files /dev/null and b/dialogflow/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/dialogflow/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/dialogflow/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..14ed0af3
Binary files /dev/null and b/dialogflow/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/dialogflow/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/dialogflow/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..b0907cac
Binary files /dev/null and b/dialogflow/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/dialogflow/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/dialogflow/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..d8ae0315
Binary files /dev/null and b/dialogflow/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/dialogflow/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/dialogflow/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..2c18de9e
Binary files /dev/null and b/dialogflow/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/dialogflow/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/dialogflow/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..beed3cdd
Binary files /dev/null and b/dialogflow/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/dialogflow/app/src/main/res/values/colors.xml b/dialogflow/app/src/main/res/values/colors.xml
new file mode 100644
index 00000000..06feb4ac
--- /dev/null
+++ b/dialogflow/app/src/main/res/values/colors.xml
@@ -0,0 +1,7 @@
+
+
+ #ff9800
+ #ef6c00
+ #FF4081
+ #FFFFFF
+
diff --git a/dialogflow/app/src/main/res/values/dimens.xml b/dialogflow/app/src/main/res/values/dimens.xml
new file mode 100644
index 00000000..59a0b0c4
--- /dev/null
+++ b/dialogflow/app/src/main/res/values/dimens.xml
@@ -0,0 +1,3 @@
+
+ 16dp
+
diff --git a/dialogflow/app/src/main/res/values/strings.xml b/dialogflow/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..1285f841
--- /dev/null
+++ b/dialogflow/app/src/main/res/values/strings.xml
@@ -0,0 +1,15 @@
+
+Dialogflow
+ChannelId
+GCP_PROJECT_ID
+SIGN IN GOOGLE
+SIGN IN ANONYMOUSLY
+Knowledge Connectors
+NEXT
+Sentiment Analysis
+Text to speech
+We have few interesting features, Would you like to enable them!
+Welcome to Dialogflow
+MainActivity
+Mic
+
diff --git a/dialogflow/app/src/main/res/values/styles.xml b/dialogflow/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..545b9c6d
--- /dev/null
+++ b/dialogflow/app/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dialogflow/app/src/test/java/com/google/cloud/examples/dialogflow/ExampleUnitTest.java b/dialogflow/app/src/test/java/com/google/cloud/examples/dialogflow/ExampleUnitTest.java
new file mode 100644
index 00000000..66fc3351
--- /dev/null
+++ b/dialogflow/app/src/test/java/com/google/cloud/examples/dialogflow/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.google.cloud.examples.dialogflow;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/dialogflow/build.gradle b/dialogflow/build.gradle
new file mode 100644
index 00000000..41da7c24
--- /dev/null
+++ b/dialogflow/build.gradle
@@ -0,0 +1,28 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.4.2'
+
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ classpath 'com.google.gms:google-services:4.2.0'
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/dialogflow/gradle.properties b/dialogflow/gradle.properties
new file mode 100644
index 00000000..9e6fce10
--- /dev/null
+++ b/dialogflow/gradle.properties
@@ -0,0 +1,19 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+android.enableJetifier=true
+android.useAndroidX=true
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/dialogflow/gradle/wrapper/gradle-wrapper.jar b/dialogflow/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..13372aef
Binary files /dev/null and b/dialogflow/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/dialogflow/gradle/wrapper/gradle-wrapper.properties b/dialogflow/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..0e19bfe6
--- /dev/null
+++ b/dialogflow/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Jun 17 13:01:57 MDT 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
diff --git a/dialogflow/gradlew b/dialogflow/gradlew
new file mode 100755
index 00000000..9d82f789
--- /dev/null
+++ b/dialogflow/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/dialogflow/gradlew.bat b/dialogflow/gradlew.bat
new file mode 100644
index 00000000..aec99730
--- /dev/null
+++ b/dialogflow/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dialogflow/settings.gradle b/dialogflow/settings.gradle
new file mode 100644
index 00000000..e7b4def4
--- /dev/null
+++ b/dialogflow/settings.gradle
@@ -0,0 +1 @@
+include ':app'