17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SpeechRecognition
3 | Permission Denial, you must grant RECORD_AUDIO permission or set handleAudioPermissions(true)
4 | This operation is not supported. Set handleAudioPermissions(true) to allow
5 | OnSpeechRecognitionPermissionListener has not been initialized
6 | OnSpeechRecognitionListener has not been initialized
7 | Speech Recognition is not available on this device
8 |
9 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values/errors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | There is a problem with your audio recording device
4 | A client error has occurred
5 | You do not have sufficient permissions. Make sure RECORD_AUDIO permission is granted
6 | A network error has occurred. If you are using Marshmallow and above you can temporarily set offlinemode true
7 | SpeechRecognition could not find a match. Make sure the right language is set
8 | SpeechRecognition is busy at the moment. Try using multiple instances to listen
9 | No speech input detected
10 | SpeechRecognition server error. Try again in few minutes
11 | Undefined error
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Maxwell Obi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/maxwell/speechrecognition/SpeechRecognitionUtilities.java:
--------------------------------------------------------------------------------
1 | package com.maxwell.speechrecognition;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.content.pm.PackageManager;
6 | import android.content.pm.ResolveInfo;
7 | import android.net.ConnectivityManager;
8 | import android.net.NetworkInfo;
9 | import android.speech.RecognizerIntent;
10 |
11 | import java.util.List;
12 |
13 | /**
14 | * Created by Maxwell on 14-Jan-18.
15 | */
16 |
17 | final class SpeechRecognitionUtilities {
18 |
19 | static boolean isInternetEnabled(Context context)
20 | {
21 | boolean isWifiConnected = false;
22 | boolean isMobileConnected = false;
23 |
24 | try {
25 | ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
26 | NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
27 |
28 | if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
29 | if (networkInfo.isConnected())
30 | isWifiConnected = true;
31 | }
32 |
33 | if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
34 | if (networkInfo.isConnected())
35 | isMobileConnected = true;
36 | }
37 |
38 | }catch (Exception e){ }
39 |
40 | return isWifiConnected || isMobileConnected;
41 | }
42 |
43 | static boolean isSpeechRecognitionEnabled(Context context){
44 |
45 | PackageManager pm = context.getPackageManager();
46 | List activities = pm.queryIntentActivities(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
47 | if (activities.size() == 0)
48 | return false;
49 |
50 | return true;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/com/maxwell/speechrecognition/OnSpeechRecognitionListener.java:
--------------------------------------------------------------------------------
1 | package com.maxwell.speechrecognition;
2 |
3 | /**
4 | * Created by Maxwell on 14-Jan-18.
5 | */
6 |
7 | public interface OnSpeechRecognitionListener {
8 |
9 | /**
10 | * This callback is fired once you call {@link SpeechRecognition#startSpeechRecognition()}
11 | * to inform you that speech recognition has started listening.
12 | */
13 | void OnSpeechRecognitionStarted();
14 |
15 | /**
16 | * This callback is the opposite of {@link #OnSpeechRecognitionStarted()}.
17 | * It is fired once you call {@link SpeechRecognition#stopSpeechRecognition()}
18 | * and informs you that speech recognition has stopped listening.
19 | */
20 | void OnSpeechRecognitionStopped();
21 |
22 | /**
23 | * Returns the translates text when SpeechRecognition is complete,
24 | * i.e when it is done translating your speech to text.
25 | * Note: when this callback is triggered, it means SpeechRecognition
26 | * is not actively listening but has not been explicitly stopped via
27 | * {@link SpeechRecognition#stopSpeechRecognition()}. You will need
28 | * to start speech recognition again to continue listening after this.
29 | *
30 | * @param finalSentence translated text to return from speech
31 | */
32 | void OnSpeechRecognitionFinalResult(String finalSentence);
33 |
34 |
35 | /**
36 | * Returns the text it is currently translating.
37 | * This callback is triggered multiple times even when SpeechRecognition
38 | * is still listening. It returns the live result of its translations
39 | *
40 | * @param currentWord current translated word
41 | */
42 | void OnSpeechRecognitionCurrentResult(String currentWord);
43 |
44 | /**
45 | * This callback is fired if there is an error with {@link SpeechRecognition}.
46 | * It returns an errorCode and errorMsg for describing the type of error
47 | * that occurred
48 | *
49 | * @param errorCode An integer that indicates the error category.
50 | * (Static defined in {@link android.speech.SpeechRecognizer})
51 | * errorCode cannot be 0. A value less than zero (i.e -1) indicates an
52 | * undefined error.
53 | * @param errorMsg The description of the error
54 | */
55 | void OnSpeechRecognitionError(int errorCode, String errorMsg);
56 | }
57 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/java/com/maxwell/speechrecognition/SpeechRecognitionPermissions.java:
--------------------------------------------------------------------------------
1 | package com.maxwell.speechrecognition;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.app.Fragment;
6 | import android.content.Context;
7 | import android.content.pm.PackageManager;
8 | import android.os.Build;
9 | import android.os.Bundle;
10 | import android.support.annotation.NonNull;
11 | import android.support.annotation.Nullable;
12 | import android.util.Log;
13 |
14 | /**
15 | * Created by Maxwell on 14-Jan-18.
16 | */
17 |
18 | public class SpeechRecognitionPermissions extends Fragment {
19 |
20 | private static final int PERMISSION_REQUEST_AUDIO = 123;
21 | private OnSpeechRecognitionPermissionListener onSpeechRecognitionPermissionListener;
22 |
23 | @Override
24 | public void onCreate(@Nullable Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setRetainInstance(true);
27 | }
28 |
29 | void setSpeechRecognitionPermissionListener(@NonNull OnSpeechRecognitionPermissionListener onSpeechRecognitionPermissionListener){
30 | this.onSpeechRecognitionPermissionListener = onSpeechRecognitionPermissionListener;
31 | }
32 |
33 | void requestPermissions(){
34 |
35 | /*
36 | * Using requestPermissions from Marshmallow and above (>= API 23)
37 | * Below Marshmallow, the app will automatically request
38 | * for the permission in manifest when installed
39 | */
40 | if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
41 | requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, PERMISSION_REQUEST_AUDIO);
42 | }
43 |
44 | Boolean isPermissionGiven(@NonNull Context context){
45 |
46 | if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
47 | return context.checkSelfPermission(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
48 |
49 | return true; //permission already request on install if < API 23
50 | }
51 |
52 | @Override
53 | public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults){
54 |
55 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
56 | if(requestCode == PERMISSION_REQUEST_AUDIO){
57 |
58 | // If request is granted, the result arrays are not empty.
59 | if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
60 | onSpeechRecognitionPermissionListener.onPermissionGranted();
61 | return;
62 | }
63 | }
64 |
65 | onSpeechRecognitionPermissionListener.onPermissionDenied();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/java/com/maxwell/speechrecognition/GoogleImeSpeechRecognition.java:
--------------------------------------------------------------------------------
1 | package com.maxwell.speechrecognition;
2 |
3 | import android.app.Fragment;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.speech.RecognizerIntent;
7 | import android.speech.SpeechRecognizer;
8 | import android.support.annotation.NonNull;
9 | import android.support.annotation.Nullable;
10 | import android.util.Log;
11 |
12 | import java.util.ArrayList;
13 |
14 | import static android.app.Activity.RESULT_OK;
15 |
16 | /**
17 | * Created by Maxwell on 15-Jan-18.
18 | */
19 |
20 | public class GoogleImeSpeechRecognition extends Fragment {
21 |
22 | private SpeechRecognitionListener speechRecognitionListener;
23 | private final int REQUEST_CODE = 123;
24 | private Intent recognizerIntent;
25 | private String voicePrompt;
26 |
27 | @Override
28 | public void onCreate(@Nullable Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 | setRetainInstance(true);
31 |
32 | initialize();
33 | }
34 |
35 | void initialize(){
36 | recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
37 | recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
38 | recognizerIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, SpeechRecognition.MAX_RESULT_COUNT);
39 | }
40 |
41 | void setSpeechRecognitionListener(@NonNull SpeechRecognitionListener speechRecognitionListener){
42 | this.speechRecognitionListener = speechRecognitionListener;
43 | }
44 |
45 | void setVoicePrompt(String voicePrompt){
46 | this.voicePrompt = voicePrompt;
47 | }
48 |
49 | void startGoogleIme(){
50 | if(recognizerIntent == null) initialize();
51 | recognizerIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, voicePrompt);
52 |
53 | startActivityForResult(recognizerIntent, REQUEST_CODE);
54 | }
55 |
56 | @Override
57 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
58 | super.onActivityResult(requestCode, resultCode, data);
59 |
60 | if(requestCode == REQUEST_CODE && resultCode == RESULT_OK){
61 |
62 | /**
63 | * The matched text with the highest confidence score will be in position 0
64 | */
65 | ArrayList matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
66 |
67 | if(matches != null && matches.size() >0){
68 | String sentence = matches.get(0);
69 | speechRecognitionListener.getOnSpeechRecognitionListener()
70 | .OnSpeechRecognitionFinalResult(sentence);
71 |
72 | return;
73 | }
74 | }
75 |
76 | speechRecognitionListener.onError(SpeechRecognizer.ERROR_NO_MATCH);
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/com/maxwell/speechrecognition/SpeechRecognitionListener.java:
--------------------------------------------------------------------------------
1 | package com.maxwell.speechrecognition;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.speech.RecognitionListener;
6 | import android.speech.SpeechRecognizer;
7 | import android.util.Log;
8 |
9 | import java.util.ArrayList;
10 |
11 | /**
12 | * Created by Maxwell on 14-Jan-18.
13 | */
14 |
15 | final class SpeechRecognitionListener implements RecognitionListener {
16 |
17 | private OnSpeechRecognitionListener onSpeechRecognitionListener;
18 | private Context context;
19 |
20 | SpeechRecognitionListener(OnSpeechRecognitionListener onSpeechRecognizerListener, Context context){
21 | this.onSpeechRecognitionListener = onSpeechRecognizerListener;
22 | this.context = context;
23 | }
24 |
25 | OnSpeechRecognitionListener getOnSpeechRecognitionListener(){
26 | return onSpeechRecognitionListener;
27 | }
28 |
29 | @Override
30 | public void onReadyForSpeech(Bundle bundle) {}
31 |
32 | @Override
33 | public void onBeginningOfSpeech() {}
34 |
35 | @Override
36 | public void onRmsChanged(float v) {}
37 |
38 | @Override
39 | public void onBufferReceived(byte[] bytes) {}
40 |
41 | @Override
42 | public void onEndOfSpeech() {}
43 |
44 | @Override
45 | public void onError(int i) {
46 |
47 | String errorMessage = "";
48 | int errorCode = -1;
49 |
50 | switch (i) {
51 | case SpeechRecognizer.ERROR_AUDIO:
52 | errorCode = SpeechRecognizer.ERROR_AUDIO;
53 | errorMessage = context.getString(R.string.error_audio);
54 | break;
55 |
56 | case SpeechRecognizer.ERROR_CLIENT:
57 | errorCode = SpeechRecognizer.ERROR_CLIENT;
58 | errorMessage = context.getString(R.string.error_client);
59 | break;
60 |
61 | case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS:
62 | errorCode = SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS;
63 | errorMessage = context.getString(R.string.error_permission);
64 | break;
65 |
66 | case SpeechRecognizer.ERROR_NETWORK:
67 | errorCode = SpeechRecognizer.ERROR_NETWORK;
68 | errorMessage = context.getString(R.string.error_network);
69 | break;
70 |
71 | case SpeechRecognizer.ERROR_NETWORK_TIMEOUT:
72 | errorCode = SpeechRecognizer.ERROR_NETWORK_TIMEOUT;
73 | errorMessage = context.getString(R.string.error_network);
74 | break;
75 |
76 | case SpeechRecognizer.ERROR_NO_MATCH:
77 | errorCode = SpeechRecognizer.ERROR_NO_MATCH;
78 | errorMessage = context.getString(R.string.error_no_match);
79 | break;
80 |
81 | case SpeechRecognizer.ERROR_RECOGNIZER_BUSY:
82 | errorCode = SpeechRecognizer.ERROR_RECOGNIZER_BUSY;
83 | errorMessage = context.getString(R.string.error_recognizer_busy);
84 | break;
85 |
86 | case SpeechRecognizer.ERROR_SERVER:
87 | errorCode = SpeechRecognizer.ERROR_SERVER;
88 | errorMessage = context.getString(R.string.error_server);
89 | break;
90 |
91 | case SpeechRecognizer.ERROR_SPEECH_TIMEOUT:
92 | errorCode = SpeechRecognizer.ERROR_SPEECH_TIMEOUT;
93 | errorMessage = context.getString(R.string.error_no_input);
94 | break;
95 |
96 | default:
97 | errorMessage = context.getString(R.string.error_undefined);
98 | break;
99 | }
100 |
101 | onSpeechRecognitionListener.OnSpeechRecognitionError(errorCode, errorMessage);
102 | }
103 |
104 | @Override
105 | public void onResults(Bundle bundle) {
106 |
107 | //sentence with highest confidence score is in position 0
108 | ArrayList matches = bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
109 |
110 | if(matches != null && matches.size() > 0){
111 | String sentence = matches.get(0);
112 |
113 | Log.i(SpeechRecognitionListener.class.getSimpleName(), sentence);
114 | onSpeechRecognitionListener.OnSpeechRecognitionFinalResult(sentence);
115 |
116 | }else onError(SpeechRecognizer.ERROR_NO_MATCH);
117 | }
118 |
119 | @Override
120 | public void onPartialResults(Bundle bundle) {
121 | //sentence with highest confidence score is in position 0
122 | ArrayList matches = bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
123 |
124 | if(matches != null && matches.size() > 0){
125 | String word = matches.get(0);
126 |
127 | Log.i(SpeechRecognitionListener.class.getSimpleName(), word);
128 | onSpeechRecognitionListener.OnSpeechRecognitionCurrentResult(word);
129 |
130 | }else onError(SpeechRecognizer.ERROR_NO_MATCH);
131 | }
132 |
133 | @Override
134 | public void onEvent(int i, Bundle bundle) {}
135 | }
136 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |
4 | ## Android Speech Recognition
5 | This library lets you perform continuous voice recognition in your android app with options to either use Google Voice Ime in a Dialog or perform the recognition in-app. It also provides you with an option to enforce ONLY **offline speech recognition**.
6 |
7 | ## Installation
8 | **Gradle**
9 |
10 | Add the Jitpack repository to your root build.gradle file
11 | ```java
12 | allprojects {
13 | repositories {
14 | ...
15 | maven { url 'https://jitpack.io' }
16 | }
17 | }
18 | ```
19 | Add the dependency to your app's build.gradle file
20 | ```java
21 | dependencies {
22 | compile 'com.github.maxwellobi:android-speech-recognition:v1.0.0-beta.1'
23 | }
24 | ```
25 | **Maven**
26 |
27 | Add the repository to your pom.xml file
28 | ```xml
29 |
30 |
31 | jitpack.io
32 | https://jitpack.io
33 |
34 |
35 | ```
36 | Add the dependency
37 | ```xml
38 |
39 | com.github.maxwellobi
40 | android-speech-recognition
41 | v1.0.0-beta.1
42 |
43 | ```
44 | ## Usage
45 |
46 | To use `SpeechRecognition` library, initialize it, set a listener for handling callbacks, then start listening.
47 | ```java
48 | @Override
49 | protected void onCreate(Bundle savedInstanceState) {
50 | super.onCreate(savedInstanceState);
51 | setContentView(R.layout.activity_main);
52 |
53 | SpeechRecognition speechRecognition = new SpeechRecognition(this);
54 | speechRecognition.setSpeechRecognitionPermissionListener(this);
55 | speechRecognition.setSpeechRecognitionListener(this);
56 |
57 | Button speakButton = findViewById(R.id.button);
58 | speakButton.setOnClickListener(new View.OnClickListener(){
59 | @Override
60 | public void onClick(View view) {
61 | speechRecognition.startSpeechRecognition();
62 | }
63 | });
64 | }
65 | ```
66 | ### **Handling Permissions**
67 | By default, `SpeechRecognition` handles the request to grant RECORD_AUDIO permission internally and provides a callback via `OnSpeechRecognitionPermissionListener` interface. There is no need to request this permission in your manifest.
68 |
69 | ```java
70 | @Override
71 | public void onPermissionGranted() {
72 | //RECORD_AUDIO permission was granted
73 | }
74 | @Override
75 | public void onPermissionDenied() {
76 | //RECORD_AUDIO permission was denied
77 | }
78 | ```
79 | **Note:** use `SpeechRecognition.handleAudioPermissions(false)` to disable this behavior. If this is set but the permission was not granted, SpeechRecognition will throw a `SecurityException`
80 |
81 | **Note:** Runtime permission request is available from API level 23 (Marshmallow). Lower API levels will request permissions on install, thus no callback will be triggered.
82 |
83 | ### Callbacks/Listeners
84 | To receive the speech recognition result and other event notification, you need to implement the `OnSpeechRecognitionListener`
85 | ```java
86 | @Override
87 | public void OnSpeechRecognitionStarted() {}
88 |
89 | @Override
90 | public void OnSpeechRecognitionStopped() {}
91 |
92 | @Override
93 | public void OnSpeechRecognitionFinalResult(String s) {
94 | //triggered when SpeechRecognition is done listening.
95 | //it returns the translated text from the voice input
96 | }
97 | @Override
98 | public void OnSpeechRecognitionCurrentResult(String s) {
99 | //this is called multiple times when SpeechRecognition is
100 | //still listening. It returns each recognized word when the user is still speaking
101 | }
102 | @Override
103 | public void OnSpeechRecognitionError(int i, String s) {}
104 | ```
105 |
106 | **Note** `OnSpeechRecognitionCurrentResult` will NOT be called if your are using the `GoogleVoiceIme` dialog.
107 |
108 | ### Options
109 |
110 | | Method | Default | Description |
111 | |-----------|---------|---------------|
112 | | `setContext(Context)` | Null | Use this to change `SpeechRecognition` current context|
113 | |`setPreferredLanguage(String)` |- | Not yet implemented |
114 | |`handleAudioPermissions(boolean)` | true | set false to handle audio permissions yourself. If `false`, then no need to `setSpeechRecognitionPermissionListener()` |
115 | | `useOnlyOfflineRecognition(boolean)` | false | set true to force android to use its Offline Recognition Engine. By default, android uses either or both online and offline. `false` is recommended. |
116 | | `isSpeechRecognitionAvailable()` | - | returns true or false whether the device supports speech recognition or not |
117 | | `useGoogleImeRecognition(boolean, String)` | false | whether to use GoogleVoiceIme Dialog or not. If true, set a `prompt` to display on the dialog or null to use default. |
118 | | `startSpeechRecognition()` | - | start listening for voice input |
119 | | `stopSpeechRecognition()` | - | dispose resources |
120 |
121 | ### Errors
122 | See [SpeechRecognizer class](https://developer.android.com/reference/android/speech/SpeechRecognizer.html) for error definitions.
123 |
124 |
125 | ## License
126 |
127 | Copyright (c) 2018 Maxwell Obi
128 |
129 | Permission is hereby granted, free of charge, to any person obtaining a copy
130 | of this software and associated documentation files (the "Software"), to deal
131 | in the Software without restriction, including without limitation the rights
132 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
133 | copies of the Software, and to permit persons to whom the Software is
134 | furnished to do so, subject to the following conditions:
135 |
136 | The above copyright notice and this permission notice shall be included in all
137 | copies or substantial portions of the Software.
138 |
--------------------------------------------------------------------------------
/app/src/main/java/com/maxwell/speechrecognition/SpeechRecognition.java:
--------------------------------------------------------------------------------
1 | package com.maxwell.speechrecognition;
2 |
3 | import android.app.Activity;
4 | import android.app.Fragment;
5 | import android.app.FragmentManager;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.os.Build;
9 | import android.speech.RecognizerIntent;
10 | import android.speech.SpeechRecognizer;
11 | import android.support.annotation.NonNull;
12 | import android.support.annotation.Nullable;
13 | import android.util.Log;
14 |
15 | /**
16 | * Created by Maxwell on 13-Jan-18.
17 | */
18 |
19 | public class SpeechRecognition {
20 |
21 | static final int MAX_RESULT_COUNT = 3;
22 |
23 | private Context context;
24 | private SpeechRecognizer speechRecognizer;
25 | private Intent recognizerIntent;
26 |
27 | private OnSpeechRecognitionListener onSpeechRecognitionListener;
28 | private SpeechRecognitionPermissions speechRecognitionPermissions;
29 | private OnSpeechRecognitionPermissionListener onSpeechRecognitionPermissionListener;
30 | private GoogleImeSpeechRecognition googleImeSpeechRecognition;
31 |
32 | private boolean enableOnlyOfflineRecognition = false;
33 | private boolean handlePermissions = true;
34 | private boolean useGoogleIme = false;
35 | private String googleImePrompt = "Speech Recognition";
36 |
37 | /**
38 | * Initialize the SpeechRecognition class with the
39 | * application context instance requesting SpeechRecognition.
40 | * It is recommended you initialize this class in your Constructor
41 | * or in onCreate of your Activity.
42 | *
43 | * @param context the application context (cannot be null)
44 | * @see Context
45 | */
46 | public SpeechRecognition(Context context){
47 | this.context = context;
48 | initializeSpeechRecognitionParameters();
49 | }
50 |
51 | /**
52 | * Sets the application context instance requesting SpeechRecognition
53 | *
54 | * @param context the application context (cannot be null)
55 | * @see Context
56 | */
57 | public void setContext(@NonNull Context context){
58 | this.context = context;
59 | initializeSpeechRecognitionParameters();
60 | }
61 |
62 | /**
63 | * Sets the {@link OnSpeechRecognitionListener} that will receive the callbacks
64 | * for handling the SpeechRecognition responses or Errors.
65 | *
66 | * @param onSpeechRecognitionListener the listener that will receive the callbacks.
67 | * @see OnSpeechRecognitionListener
68 | */
69 | public void setSpeechRecognitionListener(@NonNull OnSpeechRecognitionListener onSpeechRecognitionListener){
70 | this.onSpeechRecognitionListener = onSpeechRecognitionListener;
71 | }
72 |
73 | /**
74 | * Sets the {@link OnSpeechRecognitionPermissionListener} that will receive the permission request callback.
75 | * This listener handles the onPermissionGranted and onPermissionDenied callbacks.
76 | * You must set this if {@link SpeechRecognition} is handling the permission request for you.
77 | *
78 | * @param onSpeechRecognitionPermissionListener the listener that will receive the permission callbacks.
79 | * @throws UnsupportedOperationException
80 | * @see OnSpeechRecognitionPermissionListener
81 | * @see #handleAudioPermissions(boolean)
82 | */
83 | public void setSpeechRecognitionPermissionListener(@NonNull OnSpeechRecognitionPermissionListener onSpeechRecognitionPermissionListener){
84 |
85 | if(!handlePermissions) throw new UnsupportedOperationException(context.getString(R.string.set_permission_listener_exception_text));
86 | this.onSpeechRecognitionPermissionListener = onSpeechRecognitionPermissionListener;
87 | }
88 |
89 | public void setPreferredLanguage(){
90 | throw new UnsupportedOperationException();
91 | }
92 |
93 | /**
94 | * By default, {@link SpeechRecognition} requests for Audio permissions and returns the result
95 | * through {@link OnSpeechRecognitionPermissionListener} which is implemented in your Activity/Context.
96 | * You can decide to handle Audio permissions yourself by setting handleAudioPermissions to false.
97 | *
98 | * @param handlePermissions true or false whether to handle audio permissions yourself or not.
99 | * @see OnSpeechRecognitionPermissionListener
100 | * @see #setContext(Context)
101 | */
102 | public void handleAudioPermissions(boolean handlePermissions){
103 | this.handlePermissions = handlePermissions;
104 | }
105 |
106 | /**
107 | * Sets {@link SpeechRecognition} to use only it's offline recognition engine
108 | * This is disabled by default - meaning that either internet or offline recognition
109 | * engines may be used at anytime. It is highly recommended that this is set to false
110 | *
111 | * @param onlyOfflineRecognition true or false whether to use only offline recognition or not (false by default)
112 | * @since API level 23
113 | */
114 | public void useOnlyOfflineRecognition(boolean onlyOfflineRecognition){
115 | this.enableOnlyOfflineRecognition = onlyOfflineRecognition;
116 | }
117 |
118 | /**
119 | * Checks if speech recognition is supported on the device.
120 | * If you try to use {@link SpeechRecognition} when your device does not support it,
121 | * {@link IllegalStateException} will be thrown
122 | */
123 | public boolean isSpeechRecognitionAvailable(){
124 | return SpeechRecognitionUtilities.isSpeechRecognitionEnabled(context);
125 | }
126 |
127 | /**
128 | * This allows {@link SpeechRecognition} to use Google Voice Ime.
129 | * Note: This prevents you from doing Continuous Recognition
130 | * You will be able to get the final text result only after you are done talking.
131 | *
132 | * @param useGoogleIme true or false whether to use GoogleVoiceIme or not (false by default)
133 | * @param prompt the text prompt to display on the GoogleVoiceIme dialog.
134 | * pass Null to use the default prompt.
135 | */
136 | public void useGoogleImeRecognition(boolean useGoogleIme, @Nullable String prompt){
137 |
138 | if(prompt != null)
139 | this.googleImePrompt = prompt;
140 |
141 | this.useGoogleIme = useGoogleIme;
142 | }
143 |
144 | public void startSpeechRecognition(){
145 | /*
146 | * Set the SpeechRecognizerListener and SpeechRecognitionPermissionListener here
147 | * so that a later call to setSpeechRecognitionListener() or setSpeechRecognitionPermissionListener()
148 | * can still affect SpeechRecognition when you start listening
149 | */
150 |
151 | checkProperties();
152 | SpeechRecognitionListener speechRecognitionListener = new SpeechRecognitionListener(
153 | this.onSpeechRecognitionListener, context);
154 |
155 | if(!speechRecognitionPermissions.isPermissionGiven(context)){
156 |
157 | if(!handlePermissions)
158 | throw new SecurityException(context.getString(R.string.security_exception_text));
159 |
160 | speechRecognitionPermissions.setSpeechRecognitionPermissionListener(this.onSpeechRecognitionPermissionListener);
161 | speechRecognitionPermissions.requestPermissions();
162 |
163 | }else{
164 |
165 | /**
166 | * Trigger the OnSpeechRecognitionStarted() callback to notify client that
167 | * SpeechRecognition has started listening.
168 | * NOTE: do this here and not in {@link SpeechRecognitionListener} so that
169 | * GoogleIme can still notify via same Listener
170 | */
171 | onSpeechRecognitionListener.OnSpeechRecognitionStarted();
172 | if(useGoogleIme){
173 |
174 | googleImeSpeechRecognition.setVoicePrompt(googleImePrompt);
175 | googleImeSpeechRecognition.setSpeechRecognitionListener(speechRecognitionListener);
176 | googleImeSpeechRecognition.startGoogleIme();
177 | return;
178 | }
179 |
180 | speechRecognizer.setRecognitionListener(speechRecognitionListener);
181 | speechRecognizer.startListening(recognizerIntent);
182 | }
183 | }
184 |
185 | public void stopSpeechRecognition(){
186 |
187 | onSpeechRecognitionListener.OnSpeechRecognitionStopped();
188 | speechRecognizer.stopListening();
189 |
190 | if(speechRecognizer != null)
191 | speechRecognizer.destroy();
192 |
193 | //remove the fragments
194 | ((Activity)context).getFragmentManager().beginTransaction().remove(speechRecognitionPermissions).commit();
195 | ((Activity)context).getFragmentManager().beginTransaction().remove(googleImeSpeechRecognition).commit();
196 |
197 | }
198 |
199 | private void initializeGoogleVoiceImeParameters(){
200 |
201 | googleImeSpeechRecognition = new GoogleImeSpeechRecognition();
202 | ((Activity) context).getFragmentManager()
203 | .beginTransaction()
204 | .add(googleImeSpeechRecognition, SpeechRecognition.class.getSimpleName())
205 | .commit();
206 | }
207 |
208 | private void initializeSpeechRecognitionParameters(){
209 |
210 | if(!isSpeechRecognitionAvailable())
211 | throw new IllegalStateException(context.getString(R.string.speech_not_enabled_exception_text));
212 |
213 | /*
214 | * Initialize the SpeechRecognitionPermissions and googleIme here
215 | * for lazy loading the fragments
216 | */
217 | initializeGoogleVoiceImeParameters();
218 | speechRecognitionPermissions = new SpeechRecognitionPermissions();
219 | ((Activity) context).getFragmentManager()
220 | .beginTransaction()
221 | .add(speechRecognitionPermissions, SpeechRecognition.class.getSimpleName())
222 | .commit();
223 |
224 | /*
225 | *Initialize the SpeechRecognizer and set listener with onSpeechRecognizerListener implemented by client
226 | */
227 | speechRecognizer = SpeechRecognizer.createSpeechRecognizer(context);
228 |
229 | /*
230 | *Initialize the Speech recognition intent with default Language
231 | */
232 | recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
233 | recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
234 | recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, context.getPackageName());
235 | recognizerIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, MAX_RESULT_COUNT);
236 | recognizerIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
237 |
238 | /*
239 | * Only offline recognition works from API level 23
240 | */
241 | if(enableOnlyOfflineRecognition){
242 | if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
243 | recognizerIntent.putExtra(RecognizerIntent.EXTRA_PREFER_OFFLINE, true);
244 | }
245 |
246 | //TODO: Set preferred Speech recognition Language
247 | }
248 |
249 |
250 | private void checkProperties(){
251 | if(onSpeechRecognitionListener == null)
252 | throw new NullPointerException(context.getString(R.string.speech_listener_null_exception_text));
253 |
254 | if(handlePermissions){
255 | if(onSpeechRecognitionPermissionListener == null)
256 | throw new NullPointerException(context.getString(R.string.permission_listener_null_exception_text));
257 | }
258 |
259 | if(speechRecognitionPermissions == null)
260 | throw new NullPointerException();
261 |
262 | if(speechRecognizer == null)
263 | throw new NullPointerException();
264 | }
265 |
266 | }
267 |
--------------------------------------------------------------------------------