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..8e80166e
--- /dev/null
+++ b/dialogflow/README.md
@@ -0,0 +1,83 @@
+# 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 / Audio
+- With Sentiment Analysis
+- With Text-to-Speech
+- With Knowledge Connectors
+
+To call the Dialogflow API from Android, you need provide authorization tokens with each request. To
+get this token, this sample uses a Firebase Function to genereate these tokens on the behalf of a
+service account. The token is returned to the app via Firebase Cloud Messaging.
+
+## 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://console.cloud.google.com/apis/library/iamcredentials.googleapis.com).
+- [Enable billing](https://console.cloud.google.com/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 `SampleAgent.zip` which is located in the `resources` directory.
+- [Create a Service account](https://cloud.google.com/iam/docs/creating-managing-service-accounts)
+with the following IAM roles: (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))
+ - Dialogflow Client (Used by the app to make detect intent requests)
+ - Dialogflow Reader (Used by the app to list knowledge bases)
+- 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:
+ - "2. Set up Node.js and the Firebase CLI"
+ - "3. 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/tokenservice/functions/index.js).
+- Open `index.js`, go to the `generateAccessToken` function, 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
+```
+- On the GCP console, add the following IAM role: `Service Account Token Creator` to your
+"App Engine Default Service Account" ([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))
+- Open the [Firebase console](https://console.firebase.google.com/)
+ - Select Databases on the side menu
+ - Select Firestore
+ - Click `Start collection`
+ - Title your collection `ShortLivedAuthTOkens` and click Next
+ - Enter `OauthToken` for the Document title and Save
+- 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
+[Firebase]: https://firebase.google.com/
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..38f3eda9
--- /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.1.0'
+ implementation 'com.google.firebase:firebase-auth:19.0.0'
+ implementation 'com.firebaseui:firebase-ui-auth:4.1.0'
+ implementation 'com.google.firebase:firebase-messaging:20.0.0'
+ implementation 'com.google.firebase:firebase-functions:19.0.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..02eef2da
--- /dev/null
+++ b/dialogflow/app/src/main/AndroidManifest.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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..5fd06c4a
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/AppController.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.examples.dialogflow;
+
+import android.app.Application;
+import android.media.MediaPlayer;
+import android.os.Environment;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class AppController extends Application {
+
+ public static final String TOKEN_RECEIVED = "TOKEN_RECEIVED";
+ public static final String SESSION_ID = "sessionId";
+ public static String PROJECT_ID = "";
+
+ public static void playAudio(byte[] byteArray) {
+ MediaPlayer mediaPlayer = new MediaPlayer();
+ try {
+ File tempFile = File.createTempFile("dialogFlow", null,
+ Environment.getExternalStorageDirectory());
+ tempFile.deleteOnExit();
+ FileOutputStream fos = new FileOutputStream(tempFile);
+ fos.write(byteArray);
+ fos.close();
+ mediaPlayer.reset();
+ FileInputStream fis = new FileInputStream(tempFile);
+ mediaPlayer.setDataSource(fis.getFD());
+
+ mediaPlayer.prepare();
+ mediaPlayer.start();
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ PROJECT_ID = getApplicationContext().getString(R.string.gcp_project_id);
+ }
+
+}
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..7e793002
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/adapter/ChatRecyclerViewAdapter.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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..8aca92f9
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/model/ChatMsgModel.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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..837eca7c
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/service/MyFirebaseCloudMessagingService.java
@@ -0,0 +1,58 @@
+
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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.cloud.examples.dialogflow.utils.AuthUtils;
+import com.google.firebase.messaging.FirebaseMessagingService;
+import com.google.firebase.messaging.RemoteMessage;
+
+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) {
+ AuthUtils.setExpiryTime(expiryTime);
+ AuthUtils.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/ui/ChatActivity.java b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/ui/ChatActivity.java
new file mode 100644
index 00000000..71cc26cb
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/ui/ChatActivity.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.speech.RecognizerIntent;
+import android.text.TextUtils;
+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.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.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.cloud.examples.dialogflow.utils.AuthUtils;
+
+import java.util.ArrayList;
+import java.util.Date;
+
+public class ChatActivity extends AppCompatActivity {
+
+ private static ChatRecyclerViewAdapter chatRecyclerViewAdapter;
+ private static ArrayList chatMsgModels;
+ private static RecyclerView rvChats;
+ 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 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 addMessage in the recyclerview
+ *
+ * @param msg : message to add
+ * @param type : Type of message (sent|received)
+ */
+ private void addMsg(String msg, int type) {
+ chatMsgModels.add(new ChatMsgModel(msg, type));
+ chatRecyclerViewAdapter.notifyDataSetChanged();
+ scrollToBottom();
+ }
+
+ /**
+ * function to show the progress dialog
+ */
+ private void showProgressDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setMessage("Fetching auth token...");
+ builder.setCancelable(false);
+
+ alert = builder.create();
+ alert.show();
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_chat);
+
+ if (AppController.PROJECT_ID.equals("GCP_PROJECT_ID")) {
+ Toast.makeText(this, "Please update the GCP_PROJECT_ID in strings.xml",
+ Toast.LENGTH_LONG).show();
+ finish();
+ return;
+ }
+
+ checkPermissions();
+
+ AuthUtils.signInAnonymously(this);
+ AuthUtils.getFirebaseInstanceId();
+
+ initViews();
+ setupRecyclerView();
+ initListeners();
+
+ apiRequest = new ApiRequest();
+
+ }
+
+ /**
+ * 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 (AuthUtils.checkSignIn()) {
+ sendMsg(etMsg.getText().toString());
+ scrollToBottom();
+ } else {
+ AuthUtils.signInAnonymously(ChatActivity.this);
+ }
+ }
+ });
+
+ btnMic.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (AuthUtils.checkSignIn()) {
+ promptSpeechInput();
+ }
+ }
+ });
+
+ ibMore.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showMorePopup();
+ }
+ });
+ }
+
+
+ /**
+ * 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 (AuthUtils.isTokenValid()) {
+ addMsg(msg, 1);
+ etMsg.setText("");
+ voiceInput = "";
+ new APIRequest(AuthUtils.token, AuthUtils.expiryTime, msg, tts, sentiment,
+ knowledge).execute();
+ } 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();
+ AuthUtils.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);
+ arrPerm.add(Manifest.permission.READ_EXTERNAL_STORAGE);
+ arrPerm.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+
+
+ 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();
+ }
+ }
+ }
+
+ 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();
+ }
+
+ private class APIRequest extends AsyncTask {
+ private String token;
+ private Date expiryTime;
+ private String msg;
+ private boolean tts;
+ private boolean sentiment;
+ private boolean knowledge;
+
+ public APIRequest(String token, Date expiryTime, String msg, boolean tts, boolean sentiment,
+ boolean knowledge) {
+ this.token = token;
+ this.expiryTime = expiryTime;
+ this.msg = msg;
+ this.tts = tts;
+ this.sentiment = sentiment;
+ this.knowledge = knowledge;
+ }
+
+ @Override
+ protected String doInBackground(Void... voids) {
+ return apiRequest.callAPI(token, expiryTime, msg, tts, sentiment, knowledge);
+ }
+
+ @Override
+ protected void onPostExecute(String response) {
+ super.onPostExecute(response);
+ addMsg(response, 0);
+ }
+ }
+
+}
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..1add1efc
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/utils/ApiRequest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.examples.dialogflow.utils;
+
+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.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 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;
+
+ public ApiRequest() {
+ // Variables needed to retrieve an auth token
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'",
+ java.util.Locale.getDefault());
+ simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
+
+ /**
+ * function to call: detect Intent Sentiment Analysis | Detect Intent With TTS | KnowledgeBase
+ *
+ * @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
+ * @return : response from the server
+ */
+ public String callAPI(String accessToken, Date expiryTime, String msg, boolean tts,
+ boolean sentiment, boolean knowledge) {
+ this.token = accessToken;
+ this.tokenExpiration = expiryTime;
+ return detectIntent(msg, tts, sentiment, knowledge);
+ }
+
+ /**
+ * 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
+ * @return : response from the server
+ */
+ private String detectIntent(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);
+
+ // 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);
+
+ DetectIntentResponse detectIntentResponse =
+ sessionsClient.detectIntent(detectIntentRequest);
+
+ sessionsClient.close();
+
+ if (tts) {
+ AppController.playAudio(detectIntentResponse.getOutputAudio().toByteArray());
+ }
+
+ return handleResults(detectIntentResponse);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ return ex.getMessage();
+ }
+ }
+
+ /**
+ * 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) throws Exception {
+
+ DetectIntentRequest.Builder detectIntentRequestBuilder = DetectIntentRequest.newBuilder()
+ .setSession(sessionName.toString())
+ .setQueryInput(queryInput);
+
+ QueryParameters.Builder queryParametersBuilder = QueryParameters.newBuilder();
+
+ if (tts) {
+ OutputAudioEncoding audioEncoding = OutputAudioEncoding.OUTPUT_AUDIO_ENCODING_MP3;
+ int sampleRateHertz = 16000;
+ OutputAudioConfig outputAudioConfig = OutputAudioConfig.newBuilder()
+ .setAudioEncoding(audioEncoding)
+ .setSampleRateHertz(sampleRateHertz)
+ .build();
+
+ detectIntentRequestBuilder.setOutputAudioConfig(outputAudioConfig);
+ }
+
+ if (sentiment) {
+ SentimentAnalysisRequestConfig sentimentAnalysisRequestConfig =
+ SentimentAnalysisRequestConfig.newBuilder()
+ .setAnalyzeQueryTextSentiment(true).build();
+
+ queryParametersBuilder
+ .setSentimentAnalysisRequestConfig(sentimentAnalysisRequestConfig);
+ }
+
+
+ if (knowledge) {
+ KnowledgeBasesSettings knowledgeSessionsSettings = KnowledgeBasesSettings.newBuilder()
+ .setCredentialsProvider(fixedCredentialsProvider).build();
+ ArrayList knowledgeBaseNames =
+ KnowledgeBaseUtils.listKnowledgeBases(
+ AppController.PROJECT_ID, knowledgeSessionsSettings);
+
+ if (knowledgeBaseNames.size() > 0) {
+ // As an example, we'll only grab the first Knowledge Base
+ queryParametersBuilder.addKnowledgeBaseNames(knowledgeBaseNames.get(0));
+ }
+ }
+
+ QueryParameters queryParameters = queryParametersBuilder.build();
+ detectIntentRequestBuilder.setQueryParams(queryParameters);
+
+ return detectIntentRequestBuilder.build();
+ }
+
+ /**
+ * function to handle the results
+ *
+ * @param detectIntentResponse : detectIntentResponse object
+ * @return : String response
+ */
+ private String handleResults(DetectIntentResponse detectIntentResponse) {
+ QueryResult queryResult = detectIntentResponse.getQueryResult();
+ StringBuilder response = new StringBuilder();
+
+ KnowledgeAnswers knowledgeAnswers = queryResult.getKnowledgeAnswers();
+ for (KnowledgeAnswers.Answer answer : knowledgeAnswers.getAnswersList()) {
+ response.append(answer.getAnswer()).append("\n");
+ }
+
+ response.append(queryResult.getFulfillmentText());
+
+ if (queryResult.hasSentimentAnalysisResult()) {
+ String magnitude = String.format("(Magnitude: %s; ",
+ queryResult.getSentimentAnalysisResult().getQueryTextSentiment().getMagnitude());
+ response.append(magnitude);
+
+ String score = String.format("score: %s)",
+ queryResult.getSentimentAnalysisResult().getQueryTextSentiment().getScore());
+ response.append(score);
+ }
+
+ return response.toString();
+ }
+}
+
+
diff --git a/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/utils/AuthUtils.java b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/utils/AuthUtils.java
new file mode 100644
index 00000000..28366fab
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/utils/AuthUtils.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.examples.dialogflow.utils;
+
+import android.app.Activity;
+import android.util.Log;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.android.gms.tasks.Task;
+import com.google.firebase.auth.AuthResult;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.functions.FirebaseFunctions;
+import com.google.firebase.iid.FirebaseInstanceId;
+import com.google.firebase.iid.InstanceIdResult;
+
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+
+public class AuthUtils {
+
+ private static String firebaseInstanceId = "";
+ private static FirebaseAuth firebaseAuth;
+
+ public static String token = "";
+ public static Date expiryTime;
+
+ /**
+ * 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", firebaseInstanceId);
+
+ FirebaseFunctions.getInstance()
+ .getHttpsCallable("getOAuthToken")
+ .call(data);
+ }
+
+ /**
+ * function to store the token expiry time
+ * @param expiryTime : expiry time in UTC timezone
+ */
+ public static void setExpiryTime(String expiryTime) {
+ AuthUtils.expiryTime = getConvertedDateTime(expiryTime);
+ }
+
+ /**
+ * function to convert the time from UTC to local TimeZone
+ * @param expiryTime : expiry time in UTC timezone
+ * @return Date : converted datetime to local timezonne
+ */
+ private static Date getConvertedDateTime(String expiryTime) {
+ try {
+ final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+ DateTimeFormatter format = DateTimeFormatter.ofPattern(DATE_FORMAT);
+ LocalDateTime ldt = LocalDateTime.parse(expiryTime, format);
+ ZoneId fromZoneId = ZoneId.of(TimeZone.getTimeZone("UTC").getID());
+ ZonedDateTime fromZoneDateTime = ldt.atZone(fromZoneId);
+ ZoneId currentZoneId = TimeZone.getDefault().toZoneId();
+ ZonedDateTime zonedDateTime = fromZoneDateTime.withZoneSameInstant(currentZoneId);
+ return new SimpleDateFormat(DATE_FORMAT, Locale.US).parse(format.format(zonedDateTime));
+ } catch(Exception ex) {
+ ex.printStackTrace();
+ }
+
+ return null;
+ }
+
+ /**
+ * function to signin to Firebase Anonymously
+ * @param activity : Instance of the Activity
+ */
+ public static void signInAnonymously(final Activity activity) {
+ firebaseAuth = FirebaseAuth.getInstance();
+ firebaseAuth.signInAnonymously()
+ .addOnCompleteListener(activity, 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(activity, "Sign In was successful",
+ Toast.LENGTH_SHORT).show();
+ } else {
+ // If sign in fails, display a message to the user.
+ Toast.makeText(activity, "Authentication failed.",
+ Toast.LENGTH_SHORT).show();
+ }
+
+ }
+ });
+ }
+
+ /**
+ * function to check the user is logged in
+ *
+ * @return boolean : returns true if user is logged inn
+ */
+ public static boolean checkSignIn() {
+ return firebaseAuth != null && firebaseAuth.getCurrentUser() != null;
+ }
+
+ /**
+ * function to get the firebase instance id
+ */
+ public static void getFirebaseInstanceId() {
+ FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(
+ new OnSuccessListener() {
+ @Override
+ public void onSuccess(InstanceIdResult instanceIdResult) {
+ String deviceToken = instanceIdResult.getToken();
+ firebaseInstanceId = deviceToken;
+ Log.i("fcmId", deviceToken);
+ }
+ });
+ }
+
+ /**
+ * function to check if the token is valid
+ * @return boolean : indicates the status of the signin
+ */
+ public static boolean isTokenValid() {
+ return AuthUtils.expiryTime != null && !AuthUtils.token.equals("")
+ && AuthUtils.expiryTime.getTime() > System.currentTimeMillis();
+ }
+
+}
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..bf53aa43
--- /dev/null
+++ b/dialogflow/app/src/main/java/com/google/cloud/examples/dialogflow/utils/KnowledgeBaseUtils.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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)) {
+ ProjectName projectName = ProjectName.of(projectId);
+ for (KnowledgeBase knowledgeBase :
+ knowledgeBasesClient.listKnowledgeBases(projectName).iterateAll()) {
+ 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/strings.xml b/dialogflow/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..a3be94b9
--- /dev/null
+++ b/dialogflow/app/src/main/res/values/strings.xml
@@ -0,0 +1,8 @@
+
+Dialogflow
+GCP_PROJECT_ID
+Knowledge Connectors
+Sentiment Analysis
+Text to speech
+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/resources/SampleAgent.zip b/dialogflow/resources/SampleAgent.zip
new file mode 100644
index 00000000..50ac1093
Binary files /dev/null and b/dialogflow/resources/SampleAgent.zip differ
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'