├── .gitignore ├── LICENSE.txt ├── Readme.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── willblaschko │ │ └── android │ │ └── alexavoicelibrary │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── intros │ │ │ └── joke.raw │ ├── java │ │ └── com │ │ │ └── willblaschko │ │ │ └── android │ │ │ └── alexavoicelibrary │ │ │ ├── AlexaApplication.java │ │ │ ├── BaseActivity.java │ │ │ ├── LoginWebViewActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── actions │ │ │ ├── ActionsFragment.java │ │ │ ├── BaseListenerFragment.java │ │ │ ├── DisplayCodeFragment.java │ │ │ ├── SendAudioActionFragment.java │ │ │ ├── SendPrerecordedActionFragment.java │ │ │ ├── SendTextActionFragment.java │ │ │ └── adapter │ │ │ │ └── ActionFragmentAdapter.java │ │ │ ├── global │ │ │ └── Constants.java │ │ │ └── utility │ │ │ └── SigningKey.java │ └── res │ │ ├── drawable-hdpi-v11 │ │ ├── ic_stat_gear.png │ │ ├── ic_stat_microphone.png │ │ ├── ic_stat_pause.png │ │ └── ic_stat_search.png │ │ ├── drawable-hdpi │ │ └── ic_action_paste.png │ │ ├── drawable-mdpi-v11 │ │ ├── ic_stat_gear.png │ │ ├── ic_stat_microphone.png │ │ ├── ic_stat_pause.png │ │ └── ic_stat_search.png │ │ ├── drawable-mdpi │ │ └── ic_action_paste.png │ │ ├── drawable-xhdpi-v11 │ │ ├── ic_stat_gear.png │ │ ├── ic_stat_microphone.png │ │ ├── ic_stat_pause.png │ │ └── ic_stat_search.png │ │ ├── drawable-xhdpi │ │ └── ic_action_paste.png │ │ ├── drawable-xxhdpi-v11 │ │ ├── ic_stat_gear.png │ │ ├── ic_stat_microphone.png │ │ ├── ic_stat_pause.png │ │ └── ic_stat_search.png │ │ ├── drawable-xxhdpi │ │ └── ic_action_paste.png │ │ ├── drawable-xxxhdpi-v11 │ │ ├── ic_stat_gear.png │ │ ├── ic_stat_microphone.png │ │ ├── ic_stat_pause.png │ │ └── ic_stat_search.png │ │ ├── drawable │ │ ├── background_edittext.xml │ │ ├── background_item_action.xml │ │ └── button_search.xml │ │ ├── layout │ │ ├── activity_login.xml │ │ ├── activity_main.xml │ │ ├── activity_voice_launch.xml │ │ ├── fragment_action_audio.xml │ │ ├── fragment_action_prerecorded.xml │ │ ├── fragment_action_type.xml │ │ ├── fragment_actions.xml │ │ ├── fragment_display_code.xml │ │ └── item_action_fragment.xml │ │ ├── menu │ │ └── code_menu.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── raw │ │ ├── code_audio.txt │ │ ├── code_base.txt │ │ ├── code_prerecorded.txt │ │ └── code_text.txt │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── willblaschko │ └── android │ └── alexavoicelibrary │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── libs ├── AlexaAndroid │ ├── .gitignore │ ├── LICENSE.txt │ ├── build.gradle │ ├── gradle.properties │ ├── libs │ │ ├── commons-fileupload-1.3.1.jar │ │ └── login-with-amazon-sdk.jar │ ├── project.properties │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── willblaschko │ │ │ └── android │ │ │ └── recorderview │ │ │ └── ApplicationTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ │ └── shhh.mp3 │ │ ├── java │ │ │ └── com │ │ │ │ └── willblaschko │ │ │ │ └── android │ │ │ │ └── alexa │ │ │ │ ├── AlexaManager.java │ │ │ │ ├── AuthorizationManager.java │ │ │ │ ├── TokenManager.java │ │ │ │ ├── VoiceHelper.java │ │ │ │ ├── audioplayer │ │ │ │ └── AlexaAudioPlayer.java │ │ │ │ ├── callbacks │ │ │ │ ├── AsyncCallback.java │ │ │ │ ├── AuthorizationCallback.java │ │ │ │ ├── ImplAsyncCallback.java │ │ │ │ └── ImplAuthorizationCallback.java │ │ │ │ ├── connection │ │ │ │ ├── ClientUtil.java │ │ │ │ └── Tls12SocketFactory.java │ │ │ │ ├── data │ │ │ │ ├── Directive.java │ │ │ │ └── Event.java │ │ │ │ ├── interfaces │ │ │ │ ├── AvsAudioException.java │ │ │ │ ├── AvsException.java │ │ │ │ ├── AvsItem.java │ │ │ │ ├── AvsResponse.java │ │ │ │ ├── GenericSendEvent.java │ │ │ │ ├── SendEvent.java │ │ │ │ ├── alerts │ │ │ │ │ ├── AvsDeleteAlertItem.java │ │ │ │ │ └── AvsSetAlertItem.java │ │ │ │ ├── audioplayer │ │ │ │ │ ├── AvsPlayAudioItem.java │ │ │ │ │ ├── AvsPlayContentItem.java │ │ │ │ │ └── AvsPlayRemoteItem.java │ │ │ │ ├── errors │ │ │ │ │ └── AvsResponseException.java │ │ │ │ ├── playbackcontrol │ │ │ │ │ ├── AvsMediaNextCommandItem.java │ │ │ │ │ ├── AvsMediaPauseCommandItem.java │ │ │ │ │ ├── AvsMediaPlayCommandItem.java │ │ │ │ │ ├── AvsMediaPreviousCommandItem.java │ │ │ │ │ ├── AvsReplaceAllItem.java │ │ │ │ │ ├── AvsReplaceEnqueuedItem.java │ │ │ │ │ └── AvsStopItem.java │ │ │ │ ├── response │ │ │ │ │ └── ResponseParser.java │ │ │ │ ├── speaker │ │ │ │ │ ├── AvsAdjustVolumeItem.java │ │ │ │ │ ├── AvsSetMuteItem.java │ │ │ │ │ └── AvsSetVolumeItem.java │ │ │ │ ├── speechrecognizer │ │ │ │ │ ├── AvsExpectSpeechItem.java │ │ │ │ │ ├── AvsListenItem.java │ │ │ │ │ ├── AvsStopCaptureItem.java │ │ │ │ │ ├── SpeechSendAudio.java │ │ │ │ │ ├── SpeechSendEvent.java │ │ │ │ │ ├── SpeechSendText.java │ │ │ │ │ └── SpeechSendVoice.java │ │ │ │ ├── speechsynthesizer │ │ │ │ │ └── AvsSpeakItem.java │ │ │ │ └── system │ │ │ │ │ └── AvsSetEndpointItem.java │ │ │ │ ├── notifications │ │ │ │ └── NotificationBuilder.java │ │ │ │ ├── requestbody │ │ │ │ └── DataRequestBody.java │ │ │ │ ├── service │ │ │ │ ├── BootReceiver.java │ │ │ │ └── DownChannelService.java │ │ │ │ ├── system │ │ │ │ └── AndroidSystemHandler.java │ │ │ │ └── utility │ │ │ │ ├── SigningKey.java │ │ │ │ └── Util.java │ │ └── res │ │ │ └── values │ │ │ └── strings.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── willblaschko │ │ └── android │ │ └── recorderview │ │ └── ExampleUnitTest.java ├── RecorderLevelView │ ├── .gitignore │ ├── RecorderLevelView │ │ └── src │ │ │ ├── androidTest │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── willblaschko │ │ │ │ └── android │ │ │ │ └── recorderview │ │ │ │ └── ApplicationTest.java │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── willblaschko │ │ │ │ │ └── android │ │ │ │ │ └── recorderview │ │ │ │ │ └── RecorderView.java │ │ │ └── res │ │ │ │ ├── drawable-nodpi │ │ │ │ └── microphone.png │ │ │ │ ├── layout │ │ │ │ └── test.xml │ │ │ │ └── values │ │ │ │ ├── colors.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── willblaschko │ │ │ └── android │ │ │ └── recorderview │ │ │ └── ExampleUnitTest.java │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── willblaschko │ │ │ └── android │ │ │ └── recorderview │ │ │ └── ApplicationTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── willblaschko │ │ │ │ └── android │ │ │ │ └── recorderview │ │ │ │ └── RecorderView.java │ │ └── res │ │ │ ├── drawable-nodpi │ │ │ └── microphone.png │ │ │ ├── layout │ │ │ └── test.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── willblaschko │ │ └── android │ │ └── recorderview │ │ └── ExampleUnitTest.java └── speechutils-master │ ├── AndroidManifest.xml │ ├── LICENSE │ ├── README.md │ ├── app │ ├── build.gradle │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── ee │ │ │ └── ioc │ │ │ └── phon │ │ │ └── android │ │ │ └── speechutils │ │ │ └── editor │ │ │ └── InputConnectionCommandEditorTest.java │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── ee │ │ │ └── ioc │ │ │ └── phon │ │ │ └── android │ │ │ └── speechutils │ │ │ ├── AbstractAudioRecorder.java │ │ │ ├── AudioCue.java │ │ │ ├── AudioPauser.java │ │ │ ├── AudioRecorder.java │ │ │ ├── EncodedAudioRecorder.java │ │ │ ├── Extras.java │ │ │ ├── Log.java │ │ │ ├── MediaFormatFactory.java │ │ │ ├── RawAudioRecorder.java │ │ │ ├── RecognitionServiceManager.java │ │ │ ├── SpeechRecord.java │ │ │ ├── TtsLocaleMapper.java │ │ │ ├── TtsProvider.java │ │ │ ├── editor │ │ │ ├── Command.java │ │ │ ├── CommandEditor.java │ │ │ ├── CommandEditorManager.java │ │ │ ├── Constants.java │ │ │ ├── InputConnectionCommandEditor.java │ │ │ └── UtteranceRewriter.java │ │ │ ├── utils │ │ │ ├── AudioUtils.java │ │ │ └── PreferenceUtils.java │ │ │ └── view │ │ │ └── MicButton.java │ │ └── res │ │ ├── anim │ │ └── fade_inout_inf.xml │ │ ├── drawable │ │ ├── button_mic.xml │ │ ├── button_mic_recording_0.xml │ │ ├── button_mic_recording_1.xml │ │ ├── button_mic_recording_2.xml │ │ ├── button_mic_recording_3.xml │ │ ├── button_mic_transcribing.xml │ │ ├── button_mic_waiting.xml │ │ └── ic_voice_search_api_material.xml │ │ ├── raw │ │ ├── error.wav │ │ ├── explore_begin.ogg │ │ └── explore_end.ogg │ │ └── values │ │ └── colors.xml │ ├── build.gradle │ ├── res │ ├── anim │ │ └── fade_inout_inf.xml │ ├── drawable │ │ ├── button_mic.xml │ │ ├── button_mic_recording_0.xml │ │ ├── button_mic_recording_1.xml │ │ ├── button_mic_recording_2.xml │ │ ├── button_mic_recording_3.xml │ │ ├── button_mic_transcribing.xml │ │ ├── button_mic_waiting.xml │ │ └── ic_voice_search_api_material.xml │ ├── raw │ │ ├── error.wav │ │ ├── explore_begin.ogg │ │ └── explore_end.ogg │ └── values │ │ └── colors.xml │ ├── settings.gradle │ └── src │ └── ee │ └── ioc │ └── phon │ └── android │ └── speechutils │ ├── AbstractAudioRecorder.java │ ├── AudioCue.java │ ├── AudioPauser.java │ ├── AudioRecorder.java │ ├── EncodedAudioRecorder.java │ ├── Extras.java │ ├── Log.java │ ├── MediaFormatFactory.java │ ├── RawAudioRecorder.java │ ├── RecognitionServiceManager.java │ ├── SpeechRecord.java │ ├── TtsLocaleMapper.java │ ├── TtsProvider.java │ ├── utils │ ├── AudioUtils.java │ └── PreferenceUtils.java │ └── view │ └── MicButton.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | #built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | 18 | # Windows thumbnail db 19 | Thumbs.db 20 | 21 | # OSX files 22 | .DS_Store 23 | 24 | # Eclipse project files 25 | .classpath 26 | .project 27 | 28 | # Android Studio 29 | *.iml 30 | .idea 31 | #.idea/workspace.xml - remove # and delete .idea if it better suit your needs. 32 | .gradle 33 | build/ 34 | captures/ 35 | javadoc/ 36 | 37 | #NDK 38 | obj/ -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | #built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | 18 | # Windows thumbnail db 19 | Thumbs.db 20 | 21 | # OSX files 22 | .DS_Store 23 | 24 | # Eclipse project files 25 | .classpath 26 | .project 27 | 28 | # Android Studio 29 | *.iml 30 | .idea 31 | #.idea/workspace.xml - remove # and delete .idea if it better suit your needs. 32 | .gradle 33 | build/ 34 | captures/ 35 | 36 | #NDK 37 | obj/ -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | 4 | if (file('signing.gradle').exists()) { 5 | apply from: 'signing.gradle' 6 | }else{ 7 | throw new TaskExecutionException(null, new Exception("Unable to find signing.gradle, please replace Android buildTypes > signing configs with your own configuration.")); 8 | } 9 | 10 | android { 11 | compileSdkVersion 24 12 | buildToolsVersion '25.0.0' 13 | 14 | defaultConfig { 15 | applicationId "com.willblaschko.android.alexavoicelibrary" 16 | minSdkVersion 21 17 | 18 | targetSdkVersion 24 19 | versionCode 5 20 | versionName "2.1.1" 21 | multiDexEnabled true; 22 | } 23 | 24 | 25 | buildTypes { 26 | debug{ 27 | versionNameSuffix " Debug" 28 | minifyEnabled false 29 | shrinkResources false 30 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 31 | signingConfig signingConfigs.releaseConfig 32 | } 33 | release { 34 | minifyEnabled false 35 | shrinkResources false 36 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 37 | signingConfig signingConfigs.releaseConfig 38 | } 39 | } 40 | 41 | packagingOptions { 42 | exclude 'META-INF/LICENSE.txt' 43 | exclude 'META-INF/NOTICE.txt' 44 | exclude 'META-INF/DEPENDENCIES' 45 | exclude 'META-INF/NOTICE' 46 | exclude 'META-INF/LICENSE' 47 | } 48 | } 49 | 50 | dependencies { 51 | compile fileTree(dir: 'libs', include: ['*.jar']) 52 | testCompile 'junit:junit:4.12' 53 | compile 'com.android.support:appcompat-v7:24.2.1' 54 | compile 'com.android.support:recyclerview-v7:24.2.1' 55 | compile 'com.android.support:multidex:1.0.1' 56 | 57 | compile 'com.squareup.okhttp3:okhttp:3.2.0' 58 | compile project(path: ':libs:AlexaAndroid') 59 | compile project(path: ':libs:RecorderLevelView') 60 | compile project(path: ':libs:speechutils-master') 61 | 62 | } 63 | 64 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\AndroidSDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | 20 | -keepclassmembers class * implements javax.net.ssl.SSLSocketFactory { 21 | private javax.net.ssl.SSLSocketFactory delegate; 22 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/willblaschko/android/alexavoicelibrary/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexavoicelibrary; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 7 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /app/src/main/assets/intros/joke.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/assets/intros/joke.raw -------------------------------------------------------------------------------- /app/src/main/java/com/willblaschko/android/alexavoicelibrary/AlexaApplication.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexavoicelibrary; 2 | 3 | import android.app.Application; 4 | import android.util.Log; 5 | 6 | import com.willblaschko.android.alexavoicelibrary.utility.SigningKey; 7 | 8 | /** 9 | * An application to handle all our initialization for the Alexa library before we 10 | * launch our VoiceLaunchActivity 11 | */ 12 | public class AlexaApplication extends Application { 13 | 14 | //Our Amazon application product ID, this is passed to the server when we authenticate 15 | private static final String PRODUCT_ID = "interactive_conversation"; 16 | 17 | 18 | //Our Application instance if we need to reference it directly 19 | private static AlexaApplication mInstance; 20 | 21 | @Override 22 | public void onCreate() { 23 | super.onCreate(); 24 | mInstance = this; 25 | 26 | //if we run in DEBUG mode, we can get our signing key in the LogCat 27 | if(BuildConfig.DEBUG){ 28 | Log.i("AlexaApplication", SigningKey.getCertificateMD5Fingerprint(this)); 29 | } 30 | } 31 | 32 | /** 33 | * Return a reference to our mInstance instance 34 | * @return our current application instance, created in onCreate() 35 | */ 36 | public static AlexaApplication getInstance(){ 37 | return mInstance; 38 | } 39 | 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/willblaschko/android/alexavoicelibrary/LoginWebViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexavoicelibrary; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.os.Bundle; 7 | import android.util.Log; 8 | import android.webkit.WebView; 9 | import android.webkit.WebViewClient; 10 | 11 | /** 12 | * @author will on 3/6/2016. 13 | */ 14 | public class LoginWebViewActivity extends Activity { 15 | 16 | private static final String TAG = "LoginWebViewActivity"; 17 | 18 | WebView mWebView; 19 | 20 | private static final int RESULT_LOGIN = 1; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_login); 26 | 27 | mWebView = (WebView) findViewById(R.id.webview); 28 | 29 | mWebView.setWebViewClient(mWebViewClient); 30 | 31 | // Get the intent that started this activity 32 | Intent intent = getIntent(); 33 | Uri data = intent.getData(); 34 | 35 | if(data != null){ 36 | mWebView.loadUrl(data.toString()); 37 | }else{ 38 | finish(); 39 | } 40 | } 41 | 42 | @Override 43 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 44 | super.onActivityResult(requestCode, resultCode, data); 45 | if(requestCode == RESULT_LOGIN){ 46 | LoginWebViewActivity.this.finish(); 47 | } 48 | } 49 | 50 | WebViewClient mWebViewClient = new WebViewClient(){ 51 | @Override 52 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 53 | if(BuildConfig.DEBUG){ 54 | Log.i(TAG, url); 55 | } 56 | if(url.startsWith("http") || url.startsWith("https")){ 57 | return super.shouldOverrideUrlLoading(view, url); 58 | } 59 | 60 | Intent i = new Intent(Intent.ACTION_VIEW); 61 | i.setData(Uri.parse(url)); 62 | startActivityForResult(i, RESULT_LOGIN); 63 | 64 | return true; 65 | } 66 | 67 | 68 | }; 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/willblaschko/android/alexavoicelibrary/actions/ActionsFragment.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexavoicelibrary.actions; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | 12 | import com.willblaschko.android.alexavoicelibrary.R; 13 | import com.willblaschko.android.alexavoicelibrary.actions.adapter.ActionFragmentAdapter; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | /** 19 | * @author will on 5/30/2016. 20 | */ 21 | 22 | public class ActionsFragment extends BaseListenerFragment { 23 | 24 | 25 | @Override 26 | public void startListening() { 27 | 28 | } 29 | 30 | @Override 31 | protected String getTitle() { 32 | return getString(R.string.app_name); 33 | } 34 | 35 | @Override 36 | protected int getRawCode() { 37 | return R.raw.code_base; 38 | } 39 | 40 | @Nullable 41 | @Override 42 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 43 | return inflater.inflate(R.layout.fragment_actions, container, false); 44 | } 45 | 46 | @Override 47 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 48 | super.onViewCreated(view, savedInstanceState); 49 | 50 | RecyclerView recycler = (RecyclerView) view.findViewById(R.id.recycler); 51 | ActionFragmentAdapter adapter = new ActionFragmentAdapter(getItems()); 52 | recycler.setAdapter(adapter); 53 | recycler.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false)); 54 | } 55 | 56 | private List getItems(){ 57 | List items = new ArrayList<>(); 58 | 59 | items.add(new ActionFragmentAdapter.ActionFragmentItem(getString(R.string.fragment_action_send_audio), 60 | R.drawable.ic_stat_microphone, 61 | new View.OnClickListener() { 62 | @Override 63 | public void onClick(View v) { 64 | loadFragment(new SendAudioActionFragment()); 65 | } 66 | })); 67 | 68 | items.add(new ActionFragmentAdapter.ActionFragmentItem(getString(R.string.fragment_action_send_prerecorded), 69 | android.R.drawable.ic_menu_compass, 70 | new View.OnClickListener() { 71 | @Override 72 | public void onClick(View v) { 73 | loadFragment(new SendPrerecordedActionFragment()); 74 | } 75 | })); 76 | items.add(new ActionFragmentAdapter.ActionFragmentItem(getString(R.string.fragment_action_send_text), 77 | android.R.drawable.ic_menu_edit, 78 | new View.OnClickListener() { 79 | @Override 80 | public void onClick(View v) { 81 | loadFragment(new SendTextActionFragment()); 82 | } 83 | })); 84 | 85 | return items; 86 | } 87 | 88 | 89 | public interface ActionFragmentInterface{ 90 | void loadFragment(Fragment fragment, boolean addToBackstack); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/willblaschko/android/alexavoicelibrary/actions/BaseListenerFragment.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexavoicelibrary.actions; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.annotation.RawRes; 6 | import android.support.v4.app.Fragment; 7 | import android.view.Menu; 8 | import android.view.MenuInflater; 9 | import android.view.MenuItem; 10 | 11 | import com.willblaschko.android.alexa.AlexaManager; 12 | import com.willblaschko.android.alexa.callbacks.AsyncCallback; 13 | import com.willblaschko.android.alexa.interfaces.AvsResponse; 14 | import com.willblaschko.android.alexavoicelibrary.R; 15 | 16 | import static com.willblaschko.android.alexavoicelibrary.global.Constants.PRODUCT_ID; 17 | 18 | /** 19 | * @author will on 5/30/2016. 20 | */ 21 | 22 | public abstract class BaseListenerFragment extends Fragment { 23 | 24 | protected AlexaManager alexaManager; 25 | 26 | @Override 27 | public void onCreate(@Nullable Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | 30 | //get our AlexaManager instance for convenience 31 | alexaManager = AlexaManager.getInstance(getActivity(), PRODUCT_ID); 32 | 33 | setHasOptionsMenu(true); 34 | } 35 | 36 | @Override 37 | public void onResume() { 38 | super.onResume(); 39 | if(getActivity() != null) { 40 | getActivity().setTitle(getTitle()); 41 | } 42 | } 43 | 44 | protected AsyncCallback getRequestCallback(){ 45 | if(getActivity() != null && getActivity() instanceof AvsListenerInterface){ 46 | return ((AvsListenerInterface) getActivity()).getRequestCallback(); 47 | } 48 | return null; 49 | } 50 | 51 | @Override 52 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 53 | super.onCreateOptionsMenu(menu, inflater); 54 | inflater.inflate(R.menu.code_menu, menu); 55 | 56 | } 57 | 58 | @Override 59 | public boolean onOptionsItemSelected(MenuItem item) { 60 | switch (item.getItemId()){ 61 | case R.id.view_code: 62 | DisplayCodeFragment fragment = DisplayCodeFragment.getInstance(getTitle(), getRawCode()); 63 | loadFragment(fragment); 64 | return true; 65 | } 66 | return super.onOptionsItemSelected(item); 67 | } 68 | 69 | public abstract void startListening(); 70 | protected abstract String getTitle(); 71 | @RawRes 72 | protected abstract int getRawCode(); 73 | 74 | public interface AvsListenerInterface{ 75 | AsyncCallback getRequestCallback(); 76 | } 77 | 78 | protected void loadFragment(Fragment fragment){ 79 | if(getActivity() != null && getActivity() instanceof ActionsFragment.ActionFragmentInterface){ 80 | ((ActionsFragment.ActionFragmentInterface) getActivity()).loadFragment(fragment, true); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/willblaschko/android/alexavoicelibrary/actions/DisplayCodeFragment.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexavoicelibrary.actions; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.annotation.RawRes; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | import com.willblaschko.android.alexavoicelibrary.R; 13 | 14 | import java.io.BufferedReader; 15 | import java.io.IOException; 16 | import java.io.InputStream; 17 | import java.io.InputStreamReader; 18 | 19 | /** 20 | * @author will on 5/30/2016. 21 | */ 22 | 23 | public class DisplayCodeFragment extends Fragment { 24 | 25 | private final static String ARG_TITLE = "title"; 26 | private final static String ARG_RAW_CODE = "raw_code"; 27 | 28 | String title; 29 | int rawCode; 30 | 31 | public static DisplayCodeFragment getInstance(String title, @RawRes int rawCode){ 32 | Bundle b = new Bundle(); 33 | b.putString(ARG_TITLE, title); 34 | b.putInt(ARG_RAW_CODE, rawCode); 35 | DisplayCodeFragment fragment = new DisplayCodeFragment(); 36 | fragment.setArguments(b); 37 | return fragment; 38 | } 39 | 40 | public DisplayCodeFragment(){ 41 | 42 | } 43 | 44 | @Override 45 | public void onCreate(@Nullable Bundle savedInstanceState) { 46 | super.onCreate(savedInstanceState); 47 | if(getArguments() == null){ 48 | return; 49 | } 50 | title = getArguments().getString(ARG_TITLE); 51 | rawCode = getArguments().getInt(ARG_RAW_CODE); 52 | } 53 | 54 | @Override 55 | public void onResume() { 56 | super.onResume(); 57 | if(getActivity() != null) { 58 | getActivity().setTitle(title); 59 | } 60 | } 61 | 62 | @Nullable 63 | @Override 64 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 65 | return inflater.inflate(R.layout.fragment_display_code, container, false); 66 | } 67 | 68 | @Override 69 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 70 | super.onViewCreated(view, savedInstanceState); 71 | 72 | TextView text = (TextView) view.findViewById(R.id.code); 73 | 74 | StringBuilder builder = new StringBuilder(); 75 | 76 | InputStream in = getResources().openRawResource(rawCode); 77 | try { 78 | BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 79 | String line = reader.readLine(); 80 | while (line != null) { 81 | builder.append(line).append("\r\n"); 82 | line = reader.readLine(); 83 | } 84 | } catch (IOException e) { 85 | e.printStackTrace(); 86 | } 87 | text.setText(builder.toString()); 88 | 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /app/src/main/java/com/willblaschko/android/alexavoicelibrary/actions/SendPrerecordedActionFragment.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexavoicelibrary.actions; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.willblaschko.android.alexavoicelibrary.R; 10 | 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | 14 | /** 15 | * @author will on 5/30/2016. 16 | */ 17 | 18 | public class SendPrerecordedActionFragment extends BaseListenerFragment { 19 | 20 | View button; 21 | 22 | @Nullable 23 | @Override 24 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 25 | return inflater.inflate(R.layout.fragment_action_prerecorded, container, false); 26 | } 27 | 28 | @Override 29 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 30 | super.onViewCreated(view, savedInstanceState); 31 | 32 | button = view.findViewById(R.id.button); 33 | 34 | button.setOnClickListener(new View.OnClickListener() { 35 | @Override 36 | public void onClick(View v) { 37 | search(); 38 | } 39 | }); 40 | } 41 | 42 | private void search(){ 43 | try { 44 | InputStream is = getActivity().getAssets().open("intros/joke.raw"); 45 | byte[] fileBytes=new byte[is.available()]; 46 | is.read(fileBytes); 47 | is.close(); 48 | alexaManager.sendAudioRequest(fileBytes, getRequestCallback()); 49 | } catch (IOException e) { 50 | e.printStackTrace(); 51 | } 52 | 53 | } 54 | 55 | @Override 56 | public void startListening() { 57 | 58 | } 59 | 60 | @Override 61 | protected String getTitle() { 62 | return getString(R.string.fragment_action_send_prerecorded); 63 | } 64 | 65 | @Override 66 | protected int getRawCode() { 67 | return R.raw.code_prerecorded; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/willblaschko/android/alexavoicelibrary/actions/SendTextActionFragment.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexavoicelibrary.actions; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.KeyEvent; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.EditText; 10 | 11 | import com.willblaschko.android.alexavoicelibrary.R; 12 | 13 | /** 14 | * @author will on 5/30/2016. 15 | */ 16 | 17 | public class SendTextActionFragment extends BaseListenerFragment { 18 | 19 | EditText search; 20 | View button; 21 | 22 | @Nullable 23 | @Override 24 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 25 | return inflater.inflate(R.layout.fragment_action_type, container, false); 26 | } 27 | 28 | @Override 29 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 30 | super.onViewCreated(view, savedInstanceState); 31 | 32 | search = (EditText) view.findViewById(R.id.search); 33 | button = view.findViewById(R.id.button); 34 | 35 | search.setOnKeyListener(new View.OnKeyListener() { 36 | public boolean onKey(View v, int keyCode, KeyEvent event) { 37 | // If the event is a key-down event on the "enter" button 38 | if ((event.getAction() == KeyEvent.ACTION_DOWN) && 39 | (keyCode == KeyEvent.KEYCODE_ENTER)) { 40 | // Perform action on key press 41 | search(); 42 | return true; 43 | } 44 | return false; 45 | } 46 | }); 47 | 48 | button.setOnClickListener(new View.OnClickListener() { 49 | @Override 50 | public void onClick(View v) { 51 | search(); 52 | } 53 | }); 54 | } 55 | 56 | private void search(){ 57 | String text = search.getText().toString(); 58 | alexaManager.sendTextRequest(text, getRequestCallback()); 59 | } 60 | 61 | @Override 62 | public void startListening() { 63 | search.setText(""); 64 | search.requestFocus(); 65 | } 66 | 67 | @Override 68 | protected String getTitle() { 69 | return getString(R.string.fragment_action_send_text); 70 | } 71 | 72 | @Override 73 | protected int getRawCode() { 74 | return R.raw.code_text; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/willblaschko/android/alexavoicelibrary/actions/adapter/ActionFragmentAdapter.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexavoicelibrary.actions.adapter; 2 | 3 | import android.support.annotation.DrawableRes; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import com.willblaschko.android.alexavoicelibrary.R; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * @author will on 5/30/2016. 18 | */ 19 | 20 | public class ActionFragmentAdapter extends RecyclerView.Adapter{ 21 | 22 | List items = new ArrayList<>(); 23 | 24 | public ActionFragmentAdapter(List items){ 25 | this.items = items; 26 | } 27 | 28 | @Override 29 | public ActionFragmentViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 30 | LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 31 | View view = inflater.inflate(R.layout.item_action_fragment, parent, false); 32 | return new ActionFragmentViewHolder(view); 33 | } 34 | 35 | @Override 36 | public void onBindViewHolder(ActionFragmentViewHolder holder, int position) { 37 | ActionFragmentItem item = items.get(position); 38 | holder.title.setText(item.getTitle()); 39 | holder.icon.setImageResource(item.getIconResource()); 40 | holder.itemView.setOnClickListener(item.getClickListener()); 41 | } 42 | 43 | @Override 44 | public int getItemCount() { 45 | return items.size(); 46 | } 47 | 48 | public static class ActionFragmentViewHolder extends RecyclerView.ViewHolder{ 49 | 50 | TextView title; 51 | ImageView icon; 52 | 53 | public ActionFragmentViewHolder(View itemView) { 54 | super(itemView); 55 | title = (TextView) itemView.findViewById(R.id.title); 56 | icon = (ImageView) itemView.findViewById(R.id.icon); 57 | } 58 | } 59 | 60 | public static class ActionFragmentItem{ 61 | String title; 62 | int iconResource; 63 | View.OnClickListener clickListener; 64 | public ActionFragmentItem(String title, @DrawableRes int iconResource, View.OnClickListener clickListener){ 65 | this.title = title; 66 | this.iconResource = iconResource; 67 | this.clickListener = clickListener; 68 | } 69 | 70 | public String getTitle() { 71 | return title; 72 | } 73 | 74 | public int getIconResource() { 75 | return iconResource; 76 | } 77 | 78 | public View.OnClickListener getClickListener() { 79 | return clickListener; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/willblaschko/android/alexavoicelibrary/global/Constants.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexavoicelibrary.global; 2 | 3 | /** 4 | * @author will on 5/30/2016. 5 | */ 6 | 7 | public class Constants { 8 | public static final String PRODUCT_ID = "interactive_conversation"; 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/willblaschko/android/alexavoicelibrary/utility/SigningKey.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexavoicelibrary.utility; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.content.pm.Signature; 7 | 8 | import java.io.ByteArrayInputStream; 9 | import java.io.InputStream; 10 | import java.security.MessageDigest; 11 | import java.security.NoSuchAlgorithmException; 12 | import java.security.cert.CertificateEncodingException; 13 | import java.security.cert.CertificateException; 14 | import java.security.cert.CertificateFactory; 15 | import java.security.cert.X509Certificate; 16 | 17 | /** 18 | * Utility functions to get the application signing key versus running the keytool in java 19 | */ 20 | public class SigningKey { 21 | 22 | /** 23 | * Get the MD5 fingerprint required for application authentication on the server to set up security profiles 24 | * @param context any Context from the running application 25 | * @return the string equivalent of the MD5 fingerprint 26 | */ 27 | public static String getCertificateMD5Fingerprint(Context context) { 28 | PackageManager pm = context.getPackageManager(); 29 | String packageName = context.getPackageName(); 30 | int flags = PackageManager.GET_SIGNATURES; 31 | PackageInfo packageInfo = null; 32 | try { 33 | packageInfo = pm.getPackageInfo(packageName, flags); 34 | } catch (PackageManager.NameNotFoundException e) { 35 | e.printStackTrace(); 36 | } 37 | Signature[] signatures = packageInfo.signatures; 38 | byte[] cert = signatures[0].toByteArray(); 39 | InputStream input = new ByteArrayInputStream(cert); 40 | CertificateFactory cf = null; 41 | try { 42 | cf = CertificateFactory.getInstance("X509"); 43 | } catch (CertificateException e) { 44 | e.printStackTrace(); 45 | } 46 | X509Certificate c = null; 47 | try { 48 | c = (X509Certificate) cf.generateCertificate(input); 49 | } catch (CertificateException e) { 50 | e.printStackTrace(); 51 | } 52 | String hexString = null; 53 | try { 54 | MessageDigest md = MessageDigest.getInstance("MD5"); 55 | byte[] publicKey = md.digest(c.getEncoded()); 56 | hexString = byte2HexFormatted(publicKey); 57 | } catch (NoSuchAlgorithmException e1) { 58 | e1.printStackTrace(); 59 | } catch (CertificateEncodingException e) { 60 | e.printStackTrace(); 61 | } 62 | return hexString; 63 | } 64 | 65 | /** 66 | * Convert the resulting byte array into a string for submission 67 | * @param arr the byte array supplied by getCertificateMD5Fingerprint 68 | * @return the string equivalent 69 | */ 70 | public static String byte2HexFormatted(byte[] arr) { 71 | StringBuilder str = new StringBuilder(arr.length * 2); 72 | for (int i = 0; i < arr.length; i++) { 73 | String h = Integer.toHexString(arr[i]); 74 | int l = h.length(); 75 | if (l == 1) h = "0" + h; 76 | if (l > 2) h = h.substring(l - 2, l); 77 | str.append(h.toUpperCase()); 78 | if (i < (arr.length - 1)) str.append(':'); 79 | } 80 | return str.toString(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi-v11/ic_stat_gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-hdpi-v11/ic_stat_gear.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi-v11/ic_stat_microphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-hdpi-v11/ic_stat_microphone.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi-v11/ic_stat_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-hdpi-v11/ic_stat_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi-v11/ic_stat_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-hdpi-v11/ic_stat_search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-hdpi/ic_action_paste.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi-v11/ic_stat_gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-mdpi-v11/ic_stat_gear.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi-v11/ic_stat_microphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-mdpi-v11/ic_stat_microphone.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi-v11/ic_stat_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-mdpi-v11/ic_stat_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi-v11/ic_stat_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-mdpi-v11/ic_stat_search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-mdpi/ic_action_paste.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi-v11/ic_stat_gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-xhdpi-v11/ic_stat_gear.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi-v11/ic_stat_microphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-xhdpi-v11/ic_stat_microphone.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi-v11/ic_stat_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-xhdpi-v11/ic_stat_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi-v11/ic_stat_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-xhdpi-v11/ic_stat_search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-xhdpi/ic_action_paste.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi-v11/ic_stat_gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-xxhdpi-v11/ic_stat_gear.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi-v11/ic_stat_microphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-xxhdpi-v11/ic_stat_microphone.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi-v11/ic_stat_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-xxhdpi-v11/ic_stat_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi-v11/ic_stat_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-xxhdpi-v11/ic_stat_search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-xxhdpi/ic_action_paste.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi-v11/ic_stat_gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-xxxhdpi-v11/ic_stat_gear.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi-v11/ic_stat_microphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-xxxhdpi-v11/ic_stat_microphone.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi-v11/ic_stat_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-xxxhdpi-v11/ic_stat_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi-v11/ic_stat_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/drawable-xxxhdpi-v11/ic_stat_search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_edittext.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 33 | 34 | 35 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_item_action.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/button_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 | 12 | 13 | 26 | 27 | 38 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_voice_launch.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_action_audio.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 16 | 20 | 21 | 22 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_action_prerecorded.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 16 | 17 | 25 | 26 | 27 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_action_type.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 16 | 28 | 29 | 30 | 38 | 39 | 40 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_actions.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_display_code.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_action_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 14 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/menu/code_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/raw/code_audio.txt: -------------------------------------------------------------------------------- 1 | private final static int MY_PERMISSIONS_REQUEST_RECORD_AUDIO = 1; 2 | private static final int AUDIO_RATE = 16000; 3 | private RawAudioRecorder recorder; 4 | private RecorderView recorderView; 5 | 6 | @Override 7 | public void onResume() { 8 | super.onResume(); 9 | 10 | //request API-23 permission for RECORD_AUDIO 11 | if (ContextCompat.checkSelfPermission(getActivity(), 12 | Manifest.permission.RECORD_AUDIO) 13 | != PackageManager.PERMISSION_GRANTED) { 14 | if (!ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), 15 | Manifest.permission.RECORD_AUDIO)) { 16 | ActivityCompat.requestPermissions(getActivity(), 17 | new String[]{Manifest.permission.RECORD_AUDIO}, 18 | MY_PERMISSIONS_REQUEST_RECORD_AUDIO); 19 | } 20 | } 21 | } 22 | 23 | //recieve RECORD_AUDIO permissions request 24 | @Override 25 | public void onRequestPermissionsResult(int requestCode, 26 | @NonNull String permissions[], 27 | @NonNull int[] grantResults) { 28 | switch (requestCode) { 29 | case MY_PERMISSIONS_REQUEST_RECORD_AUDIO: { 30 | // If request is cancelled, the result arrays are empty. 31 | if (!(grantResults.length > 0 32 | && grantResults[0] == PackageManager.PERMISSION_GRANTED)){ 33 | getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit(); 34 | } 35 | } 36 | 37 | } 38 | } 39 | 40 | @Override 41 | public void onStop() { 42 | super.onStop(); 43 | //tear down our recorder on stop 44 | if(recorder != null){ 45 | recorder.stop(); 46 | recorder.release(); 47 | recorder = null; 48 | } 49 | } 50 | 51 | @Override 52 | public void startListening() { 53 | if(recorder == null){ 54 | recorder = new RawAudioRecorder(AUDIO_RATE); 55 | } 56 | recorder.start(); 57 | alexaManager.sendAudioRequest(requestBody, getRequestCallback()); 58 | } 59 | 60 | //our streaming data requestBody 61 | private DataRequestBody requestBody = new DataRequestBody() { 62 | @Override 63 | public void writeTo(BufferedSink sink) throws IOException { 64 | //while our recorder is not null and it is still recording, keep writing to POST data 65 | while (recorder != null && !recorder.isPausing()) { 66 | if(recorder != null) { 67 | final float rmsdb = recorder.getRmsdb(); 68 | if(recorderView != null) { 69 | recorderView.post(new Runnable() { 70 | @Override 71 | public void run() { 72 | recorderView.setRmsdbLevel(rmsdb); 73 | } 74 | }); 75 | } 76 | if(sink != null && recorder != null) { 77 | sink.write(recorder.consumeRecording()); 78 | } 79 | } 80 | 81 | //sleep and do it all over again 82 | try { 83 | Thread.sleep(25); 84 | } catch (InterruptedException e) { 85 | e.printStackTrace(); 86 | } 87 | } 88 | stopListening(); 89 | } 90 | 91 | }; 92 | 93 | //tear down our recorder 94 | private void stopListening(){ 95 | if(recorder != null) { 96 | recorder.stop(); 97 | recorder.release(); 98 | recorder = null; 99 | } 100 | } -------------------------------------------------------------------------------- /app/src/main/res/raw/code_prerecorded.txt: -------------------------------------------------------------------------------- 1 | //send prerecorded audio to Alexa, parse the callback in requestCallback 2 | try { 3 | //open asset file 4 | InputStream is = getActivity().getAssets().open("intros/joke.raw"); 5 | byte[] fileBytes=new byte[is.available()]; 6 | is.read(fileBytes); 7 | is.close(); 8 | alexaManager.sendAudioRequest(fileBytes, getRequestCallback()); 9 | } catch (IOException e) { 10 | e.printStackTrace(); 11 | } -------------------------------------------------------------------------------- /app/src/main/res/raw/code_text.txt: -------------------------------------------------------------------------------- 1 | //send a text request to Alexa, parse the callback in requestCallback 2 | alexaManager.sendTextRequest(text, requestCallback); -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #00877A 6 | #ffffff 7 | #aaffffff 8 | #000000 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | 4dp 7 | 2dp 8 | 8dp 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Alexa Voice Library 3 | 4 | 5 | LISTENING… 6 | PROCESSING… 7 | SPEAKING… 8 | Send Text 9 | Send Audio 10 | Send Prerecorded Audio 11 | Send Text will process a string, passing it through the Text To Speech functionality of Android before sending the rendered text to the Alexa server. This is treated just like human speech, but because of the issues of the extra layer, the success rate is not as high as sending raw audio. Additionally this process takes longer due to the extra layer.\n\n\n Click the menu option to view sample code. 12 | Press the the button to send request.\n\n\nSending prerecorded audio will be the fastest way to connect to the Alexa servers, but it\'s also the least flexible. It takes a raw audio file and uploads it directly without any other user interaction. This example plays the recorded value: "Tell me a joke."\n\n\n Click the menu option to view sample code. 13 | Press the microphone to start recording. Recording will end either when pressed again or end of speech detected.\n\n\nSending audio can be very efficient if using the DataRequestBody option, since it can write to the POST while the audio is still being recorded, giving the impression of a very fast response. This can also be used to prepend or append audio to a recorded stream, if you wanted to limit the control to a single skill: "Open Hey Dad and ask for a joke about…" followed by the joke type.\n\n\n Click the menu option to view sample code. 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/test/java/com/willblaschko/android/alexavoicelibrary/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexavoicelibrary; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.3.0' 9 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6' 10 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' 11 | classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0' // version plugin support 12 | // NOTE: Do not place your application dependencies here; they belong 13 | // in the individual module build.gradle files 14 | } 15 | } 16 | 17 | if (file('buildLocation.gradle').exists()) { 18 | apply from: 'buildLocation.gradle' 19 | } 20 | 21 | allprojects { 22 | repositories { 23 | jcenter() 24 | } 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /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 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | 14 | org.gradle.jvmargs=-Xmx3072m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 15 | 16 | # When configured, Gradle will run in incubating parallel mode. 17 | # This option should only be used with decoupled projects. More details, visit 18 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 19 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Sep 19 13:27:34 PDT 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/.gitignore: -------------------------------------------------------------------------------- 1 | #built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | 18 | # Windows thumbnail db 19 | Thumbs.db 20 | 21 | # OSX files 22 | .DS_Store 23 | 24 | # Eclipse project files 25 | .classpath 26 | .project 27 | 28 | # Android Studio 29 | *.iml 30 | .idea 31 | #.idea/workspace.xml - remove # and delete .idea if it better suit your needs. 32 | .gradle 33 | build/ 34 | captures/ 35 | 36 | #NDK 37 | obj/ -------------------------------------------------------------------------------- /libs/AlexaAndroid/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | jcenter() 5 | } 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:2.3.0' 8 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.1' 9 | } 10 | } 11 | 12 | apply plugin: 'com.android.library' 13 | apply plugin: 'com.jfrog.bintray' 14 | 15 | def versionMajor = 2 16 | def versionMinor = 4 17 | def versionPatch = 2 18 | def versionMajorMinorPatch = "${versionMajor}.${versionMinor}.${versionPatch}" 19 | 20 | 21 | //gradlew bintrayUpload -xjavadoc 22 | ext { 23 | bintrayRepo = 'maven' 24 | bintrayName = 'AlexaAndroid' 25 | 26 | publishedGroupId = 'com.willblaschko.android.alexa' 27 | libraryName = 'AlexaAndroid' 28 | artifact = 'AlexaAndroid' 29 | 30 | libraryDescription = 'A library to abstract access to the Amazon Alexa service for Android applications.' 31 | 32 | siteUrl = 'https://github.com/willblaschko/AlexaAndroid' 33 | gitUrl = 'https://github.com/willblaschko/AlexaAndroid.git' 34 | 35 | libraryVersion = versionMajorMinorPatch 36 | 37 | 38 | developerId = 'willblaschko' 39 | developerName = 'Will Blaschko' 40 | developerEmail = 'will.blaschko@gmail.com' 41 | 42 | licenseName = 'GPL 2.0' 43 | licenseUrl = 'https://github.com/willblaschko/AlexaAndroid/blob/master/LICENSE.txt' 44 | allLicenses = ["GPL-2.0"] 45 | } 46 | 47 | dependencies { 48 | compile fileTree(dir: 'libs', include: ['*.jar']) 49 | compile 'com.intellij:annotations:+@jar' 50 | compile 'com.google.code.gson:gson:2.7' 51 | compile group: 'commons-io', name: 'commons-io', version: '2.5' 52 | compile 'com.squareup.okhttp3:okhttp:3.6.0' 53 | compile 'org.greenrobot:eventbus:3.0.0' 54 | // https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 55 | compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.0' 56 | compile 'com.google.android.gms:play-services-base:9.6.1' 57 | testCompile 'junit:junit:4.12' 58 | } 59 | 60 | android { 61 | compileSdkVersion 24 62 | buildToolsVersion '25.0.0' 63 | defaultConfig { 64 | minSdkVersion 21 65 | targetSdkVersion 24 66 | versionName versionMajorMinorPatch 67 | } 68 | 69 | 70 | lintOptions { 71 | abortOnError false 72 | } 73 | 74 | packagingOptions { 75 | exclude 'META-INF/LICENSE.txt' 76 | exclude 'META-INF/NOTICE.txt' 77 | exclude 'META-INF/DEPENDENCIES' 78 | exclude 'META-INF/NOTICE' 79 | exclude 'META-INF/LICENSE' 80 | } 81 | } 82 | 83 | tasks.withType(Javadoc) { 84 | options.addStringOption('Xdoclint:none', '-quiet') 85 | options.addStringOption('encoding', 'UTF-8') 86 | options.addStringOption('charSet', 'UTF-8') 87 | } 88 | 89 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle' 90 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle' 91 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Alexa Voice Implementation Library -------------------------------------------------------------------------------- /libs/AlexaAndroid/libs/commons-fileupload-1.3.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/libs/AlexaAndroid/libs/commons-fileupload-1.3.1.jar -------------------------------------------------------------------------------- /libs/AlexaAndroid/libs/login-with-amazon-sdk.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/libs/AlexaAndroid/libs/login-with-amazon-sdk.jar -------------------------------------------------------------------------------- /libs/AlexaAndroid/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-17 15 | android.library=true 16 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/androidTest/java/com/willblaschko/android/recorderview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.recorderview; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/assets/shhh.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/libs/AlexaAndroid/src/main/assets/shhh.mp3 -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/callbacks/AsyncCallback.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.callbacks; 2 | 3 | /** 4 | * A generic callback to handle four states of asynchronous operations 5 | */ 6 | public interface AsyncCallback{ 7 | void start(); 8 | void success(D result); 9 | void failure(E error); 10 | void complete(); 11 | } 12 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/callbacks/AuthorizationCallback.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.callbacks; 2 | 3 | /** 4 | * A callback to handle three states of Amazon authorization 5 | */ 6 | public interface AuthorizationCallback { 7 | void onCancel(); 8 | void onSuccess(); 9 | void onError(Exception error); 10 | } 11 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/callbacks/ImplAsyncCallback.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.callbacks; 2 | 3 | /** 4 | * Implemented version of {@link AsyncCallback} generic 5 | */ 6 | public class ImplAsyncCallback implements AsyncCallback { 7 | @Override 8 | public void start() { 9 | 10 | } 11 | 12 | @Override 13 | public void success(D result) { 14 | 15 | } 16 | 17 | @Override 18 | public void failure(E error) { 19 | 20 | } 21 | 22 | @Override 23 | public void complete() { 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/callbacks/ImplAuthorizationCallback.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.callbacks; 2 | 3 | /** 4 | * Implemented version of {@link AuthorizationCallback} 5 | */ 6 | public class ImplAuthorizationCallback implements AuthorizationCallback { 7 | 8 | @Override 9 | public void onCancel() { 10 | 11 | } 12 | 13 | @Override 14 | public void onSuccess() { 15 | 16 | } 17 | 18 | @Override 19 | public void onError(Exception error) { 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/connection/ClientUtil.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.connection; 2 | 3 | import android.os.Build; 4 | import android.util.Log; 5 | 6 | import java.security.KeyStore; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | import javax.net.ssl.SSLContext; 13 | import javax.net.ssl.TrustManager; 14 | import javax.net.ssl.TrustManagerFactory; 15 | import javax.net.ssl.X509TrustManager; 16 | 17 | import okhttp3.CipherSuite; 18 | import okhttp3.ConnectionPool; 19 | import okhttp3.ConnectionSpec; 20 | import okhttp3.OkHttpClient; 21 | import okhttp3.TlsVersion; 22 | 23 | /** 24 | * Create a singleton OkHttp client that, hopefully, will someday be able to make sure all connections are valid according to AVS's strict 25 | * security policy--this will hopefully fix the Connection Reset By Peer issue. 26 | * 27 | * Created by willb_000 on 6/26/2016. 28 | */ 29 | public class ClientUtil { 30 | 31 | private static OkHttpClient mClient; 32 | private static final long CONNECTION_POOL_TIMEOUT_MILLISECONDS = 60 * 60 * 1000; 33 | 34 | public static OkHttpClient getTLS12OkHttpClient(){ 35 | if(mClient == null) { 36 | 37 | ConnectionPool connectionPool = new ConnectionPool(5, 38 | CONNECTION_POOL_TIMEOUT_MILLISECONDS, TimeUnit.MILLISECONDS); 39 | OkHttpClient.Builder client = new OkHttpClient.Builder().connectTimeout(0, TimeUnit.MILLISECONDS) // 0 => no timeout. 40 | .readTimeout(0, TimeUnit.MILLISECONDS) 41 | .connectionPool(connectionPool); 42 | 43 | if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT < 22) { 44 | try { 45 | 46 | TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 47 | trustManagerFactory.init((KeyStore) null); 48 | TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); 49 | if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { 50 | throw new IllegalStateException("Unexpected default trust managers:" 51 | + Arrays.toString(trustManagers)); 52 | } 53 | 54 | X509TrustManager trustManager = (X509TrustManager) trustManagers[0]; 55 | 56 | SSLContext sc = SSLContext.getInstance("TLSv1.2"); 57 | sc.init(null, null, null); 58 | 59 | String[] enabled = sc.getSocketFactory().getDefaultCipherSuites(); 60 | String[] supported = sc.getSocketFactory().getSupportedCipherSuites(); 61 | 62 | client.sslSocketFactory(new Tls12SocketFactory(sc.getSocketFactory()), trustManager); 63 | 64 | ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 65 | .tlsVersions(TlsVersion.TLS_1_2) 66 | .cipherSuites(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 67 | CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) 68 | .build(); 69 | 70 | List specs = new ArrayList<>(); 71 | specs.add(cs); 72 | 73 | client.connectionSpecs(specs); 74 | } catch (Exception exc) { 75 | Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc); 76 | } 77 | } 78 | 79 | mClient = client.build(); 80 | } 81 | return mClient; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/connection/Tls12SocketFactory.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.connection; 2 | 3 | import java.io.IOException; 4 | import java.net.InetAddress; 5 | import java.net.Socket; 6 | import java.net.UnknownHostException; 7 | 8 | import javax.net.ssl.SSLSocket; 9 | import javax.net.ssl.SSLSocketFactory; 10 | 11 | /** 12 | * Created by willb_000 on 6/26/2016. 13 | */ 14 | 15 | 16 | /** 17 | * Enables TLS v1.2 when creating SSLSockets. 18 | * @link https://github.com/square/okhttp/issues/2372 19 | *

20 | * For some reason, android supports TLS v1.2 from API 16, but enables it by 21 | * default only from API 20. 22 | * @link https://developer.android.com/reference/javax/net/ssl/SSLSocket.html 23 | * @see SSLSocketFactory 24 | */ 25 | public class Tls12SocketFactory extends SSLSocketFactory { 26 | 27 | private static final String[] TLS_V12_ONLY = {"TLSv1.2"}; 28 | 29 | final SSLSocketFactory delegate; 30 | 31 | public Tls12SocketFactory(SSLSocketFactory base) { 32 | this.delegate = base; 33 | } 34 | 35 | @Override 36 | public String[] getDefaultCipherSuites() { 37 | return delegate.getDefaultCipherSuites(); 38 | } 39 | 40 | @Override 41 | public String[] getSupportedCipherSuites() { 42 | return delegate.getSupportedCipherSuites(); 43 | } 44 | 45 | @Override 46 | public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { 47 | return patch(delegate.createSocket(s, host, port, autoClose)); 48 | } 49 | 50 | @Override 51 | public Socket createSocket(String host, int port) throws IOException, UnknownHostException { 52 | return patch(delegate.createSocket(host, port)); 53 | } 54 | 55 | @Override 56 | public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { 57 | return patch(delegate.createSocket(host, port, localHost, localPort)); 58 | } 59 | 60 | @Override 61 | public Socket createSocket(InetAddress host, int port) throws IOException { 62 | return patch(delegate.createSocket(host, port)); 63 | } 64 | 65 | @Override 66 | public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { 67 | return patch(delegate.createSocket(address, port, localAddress, localPort)); 68 | } 69 | 70 | private Socket patch(Socket s) { 71 | if (s instanceof SSLSocket) { 72 | ((SSLSocket) s).setEnabledProtocols(TLS_V12_ONLY); 73 | } 74 | return s; 75 | } 76 | } -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/AvsAudioException.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces; 2 | 3 | public class AvsAudioException extends Exception { 4 | 5 | public AvsAudioException() { 6 | } 7 | 8 | public AvsAudioException(String message) { 9 | super(message); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/AvsException.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces; 2 | 3 | /** 4 | * Custom exception type to wrap exceptions thrown by the Alexa server. 5 | */ 6 | public class AvsException extends Exception { 7 | 8 | public AvsException() { 9 | } 10 | 11 | public AvsException(String message) { 12 | super(message); 13 | } 14 | 15 | public AvsException(Throwable cause) { 16 | super(cause); 17 | } 18 | 19 | public AvsException(String message, Throwable cause) { 20 | super(message, cause); 21 | } 22 | 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/AvsItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces; 2 | 3 | /** 4 | * @author wblaschko on 8/13/15. 5 | */ 6 | public abstract class AvsItem { 7 | String token; 8 | public AvsItem(String token){ 9 | this.token = token; 10 | } 11 | 12 | public String getToken() { 13 | return token; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/AvsResponse.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * Wrapper for the list of {@link AvsItem} {@link com.willblaschko.android.alexa.data.Directive}s returned from a post/get sent to the 7 | * Alexa server. In the future this will contain other metadata associated with the returned response. 8 | */ 9 | public class AvsResponse extends ArrayList { 10 | 11 | public AvsResponse() { 12 | 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/GenericSendEvent.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces; 2 | 3 | import android.util.Log; 4 | 5 | import com.willblaschko.android.alexa.callbacks.AsyncCallback; 6 | 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import java.io.IOException; 10 | 11 | import okhttp3.Call; 12 | 13 | /** 14 | * @author will on 5/21/2016. 15 | */ 16 | public class GenericSendEvent extends SendEvent{ 17 | 18 | public static final String TAG = "GenericSendEvent"; 19 | 20 | String event; 21 | 22 | public GenericSendEvent(String url, String accessToken, String event, 23 | final AsyncCallback callback){ 24 | this.event = event; 25 | 26 | if (callback != null){ 27 | callback.start(); 28 | } 29 | try { 30 | prepareConnection(url, accessToken); 31 | if (callback != null) { 32 | callback.success(completePost()); 33 | callback.complete(); 34 | } else { 35 | completePost(); 36 | } 37 | Log.i(TAG, "Event sent"); 38 | } catch (IOException | AvsException e) { 39 | onError(callback, e); 40 | } 41 | 42 | } 43 | 44 | @NotNull 45 | @Override 46 | public String getEvent() { 47 | return event; 48 | } 49 | 50 | 51 | public void onError(final AsyncCallback callback, Exception e) { 52 | if (callback != null) { 53 | callback.failure(e); 54 | callback.complete(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/alerts/AvsDeleteAlertItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.alerts; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | public class AvsDeleteAlertItem extends AvsItem { 6 | public AvsDeleteAlertItem(String token) { 7 | super(token); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/alerts/AvsSetAlertItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.alerts; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | import java.text.ParseException; 6 | import java.text.SimpleDateFormat; 7 | import java.util.Date; 8 | import java.util.Locale; 9 | 10 | /** 11 | * An AVS Item to handle setting alerts on the device 12 | * 13 | * {@link com.willblaschko.android.alexa.data.Directive} response item type parsed so we can properly 14 | * deal with the incoming commands from the Alexa server. 15 | */ 16 | public class AvsSetAlertItem extends AvsItem { 17 | private String type; 18 | private String scheduledTime; 19 | 20 | public static final String TIMER = "TIMER"; 21 | public static final String ALARM = "ALARM"; 22 | 23 | /** 24 | * Create a new AVSItem directive for an alert 25 | * 26 | * @param token the alert identifier 27 | * @param type the alert type 28 | * @param scheduledTime the alert time 29 | */ 30 | public AvsSetAlertItem(String token, String type, String scheduledTime){ 31 | super(token); 32 | this.type = type; 33 | this.scheduledTime = scheduledTime; 34 | } 35 | 36 | public String getScheduledTime() { 37 | return scheduledTime; 38 | } 39 | 40 | public void setScheduledTime(String scheduledTime) { 41 | this.scheduledTime = scheduledTime; 42 | } 43 | 44 | public long getScheduledTimeMillis() throws ParseException { 45 | return getDate().getTime(); 46 | } 47 | 48 | public int getHour() throws ParseException { 49 | return getDate().getHours(); 50 | } 51 | public int getMinutes() throws ParseException { 52 | return getDate().getMinutes(); 53 | } 54 | 55 | private Date getDate() throws ParseException { 56 | return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US).parse(scheduledTime); 57 | } 58 | 59 | public String getType() { 60 | return type; 61 | } 62 | 63 | public void setType(String type) { 64 | this.type = type; 65 | } 66 | 67 | public boolean isTimer() { 68 | return type.equals(TIMER); 69 | } 70 | 71 | public boolean isAlarm() { 72 | return type.equals(ALARM); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/audioplayer/AvsPlayAudioItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.audioplayer; 2 | 3 | import com.willblaschko.android.alexa.interfaces.speechsynthesizer.AvsSpeakItem; 4 | 5 | import java.io.ByteArrayInputStream; 6 | import java.io.IOException; 7 | 8 | /** 9 | * Directive to play a local, returned audio item 10 | * 11 | * See: {@link AvsSpeakItem} 12 | * 13 | * {@link com.willblaschko.android.alexa.data.Directive} response item type parsed so we can properly 14 | * deal with the incoming commands from the Alexa server. 15 | * 16 | * @author will on 5/21/2016. 17 | */ 18 | public class AvsPlayAudioItem extends AvsSpeakItem { 19 | public AvsPlayAudioItem(String token, String cid, ByteArrayInputStream audio) throws IOException { 20 | super(token, cid, audio); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/audioplayer/AvsPlayContentItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.audioplayer; 2 | 3 | import android.net.Uri; 4 | 5 | import com.willblaschko.android.alexa.interfaces.AvsItem; 6 | 7 | /** 8 | * Directive to play a local content item, this is not generated from the Alexa servers, this is for local 9 | * use only. 10 | * 11 | * {@link com.willblaschko.android.alexa.data.Directive} response item type parsed so we can properly 12 | * deal with the incoming commands from the Alexa server. 13 | * 14 | * @author will on 5/21/2016. 15 | */ 16 | public class AvsPlayContentItem extends AvsItem { 17 | private Uri mUri; 18 | 19 | /** 20 | * Create a new local play item 21 | * @param uri the local URI 22 | */ 23 | public AvsPlayContentItem(String token, Uri uri){ 24 | super(token); 25 | mUri = uri; 26 | } 27 | public Uri getUri(){ 28 | return mUri; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/audioplayer/AvsPlayRemoteItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.audioplayer; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | /** 6 | * Directive to play a remote URL item 7 | * 8 | * {@link com.willblaschko.android.alexa.data.Directive} response item type parsed so we can properly 9 | * deal with the incoming commands from the Alexa server. 10 | * 11 | * @author will on 5/21/2016. 12 | */ 13 | public class AvsPlayRemoteItem extends AvsItem { 14 | private String mUrl; 15 | private String mStreamId; 16 | private long mStartOffset; 17 | 18 | public AvsPlayRemoteItem(String token, String url, long startOffset) { 19 | super(token); 20 | mUrl = url; 21 | mStartOffset = (startOffset < 0) ? 0 : startOffset; 22 | } 23 | public String getUrl() { 24 | return mUrl; 25 | } 26 | 27 | public long getStartOffset() { 28 | return mStartOffset; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/errors/AvsResponseException.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.errors; 2 | 3 | import com.willblaschko.android.alexa.data.Directive; 4 | import com.willblaschko.android.alexa.interfaces.AvsItem; 5 | 6 | /** 7 | * Created by will on 6/26/2016. 8 | */ 9 | 10 | public class AvsResponseException extends AvsItem { 11 | Directive directive; 12 | public AvsResponseException(Directive directive) { 13 | super(null); 14 | this.directive = directive; 15 | } 16 | 17 | public Directive getDirective() { 18 | return directive; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/playbackcontrol/AvsMediaNextCommandItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.playbackcontrol; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | /** 6 | * {@link com.willblaschko.android.alexa.data.Directive} to send a previous command to any app playing media 7 | * 8 | * This directive doesn't seem applicable to mobile applications 9 | * 10 | * @author will on 5/31/2016. 11 | */ 12 | 13 | public class AvsMediaNextCommandItem extends AvsItem { 14 | public AvsMediaNextCommandItem(String token) { 15 | super(token); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/playbackcontrol/AvsMediaPauseCommandItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.playbackcontrol; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | /** 6 | * {@link com.willblaschko.android.alexa.data.Directive} to send a pause command to any app playing media 7 | * 8 | * This directive doesn't seem applicable to mobile applications 9 | * 10 | * @author will on 5/31/2016. 11 | */ 12 | 13 | public class AvsMediaPauseCommandItem extends AvsItem { 14 | public AvsMediaPauseCommandItem(String token) { 15 | super(token); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/playbackcontrol/AvsMediaPlayCommandItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.playbackcontrol; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | /** 6 | * {@link com.willblaschko.android.alexa.data.Directive} to send a play command to any app playing media 7 | * 8 | * This directive doesn't seem applicable to mobile applications 9 | * 10 | * @author will on 5/31/2016. 11 | */ 12 | 13 | public class AvsMediaPlayCommandItem extends AvsItem { 14 | public AvsMediaPlayCommandItem(String token) { 15 | super(token); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/playbackcontrol/AvsMediaPreviousCommandItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.playbackcontrol; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | /** 6 | * {@link com.willblaschko.android.alexa.data.Directive} to send a previous command to any app playing media 7 | * 8 | * This directive doesn't seem applicable to mobile applications 9 | * 10 | * @author will on 5/31/2016. 11 | */ 12 | 13 | public class AvsMediaPreviousCommandItem extends AvsItem { 14 | public AvsMediaPreviousCommandItem(String token) { 15 | super(token); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/playbackcontrol/AvsReplaceAllItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.playbackcontrol; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | /** 6 | * Directive to replace all the items in the queue plus the currently playing item 7 | * 8 | * {@link com.willblaschko.android.alexa.data.Directive} response item type parsed so we can properly 9 | * deal with the incoming commands from the Alexa server. 10 | * 11 | * @author will on 5/21/2016. 12 | */ 13 | public class AvsReplaceAllItem extends AvsItem { 14 | public AvsReplaceAllItem(String token) { 15 | super(token); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/playbackcontrol/AvsReplaceEnqueuedItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.playbackcontrol; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | /** 6 | * Directive to replace all items in the queue, but leave the playing item 7 | * 8 | * {@link com.willblaschko.android.alexa.data.Directive} response item type parsed so we can properly 9 | * deal with the incoming commands from the Alexa server. 10 | * 11 | * @author will on 5/21/2016. 12 | */ 13 | public class AvsReplaceEnqueuedItem extends AvsItem { 14 | public AvsReplaceEnqueuedItem(String token) { 15 | super(token); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/playbackcontrol/AvsStopItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.playbackcontrol; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | /** 6 | * Directive to stop device playback 7 | * 8 | * {@link com.willblaschko.android.alexa.data.Directive} response item type parsed so we can properly 9 | * deal with the incoming commands from the Alexa server. 10 | * 11 | * @author will on 5/21/2016. 12 | */ 13 | public class AvsStopItem extends AvsItem { 14 | public AvsStopItem(String token) { 15 | super(token); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/speaker/AvsAdjustVolumeItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.speaker; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | /** 6 | * Directive to adjust the device volume 7 | * 8 | * {@link com.willblaschko.android.alexa.data.Directive} response item type parsed so we can properly 9 | * deal with the incoming commands from the Alexa server. 10 | * 11 | * @author will on 5/21/2016. 12 | */ 13 | public class AvsAdjustVolumeItem extends AvsItem{ 14 | private long adjustment; 15 | 16 | /** 17 | * Create a new AdjustVolume {@link com.willblaschko.android.alexa.data.Directive} 18 | * @param adjustment the direction and amount of adjustment (1, -1). 19 | */ 20 | public AvsAdjustVolumeItem(String token, long adjustment){ 21 | super(token); 22 | this.adjustment = adjustment; 23 | } 24 | 25 | public long getAdjustment() { 26 | return adjustment; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/speaker/AvsSetMuteItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.speaker; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | /** 6 | * Directive to set the device mute state 7 | * 8 | * {@link com.willblaschko.android.alexa.data.Directive} response item type parsed so we can properly 9 | * deal with the incoming commands from the Alexa server. 10 | * 11 | * @author will on 5/21/2016. 12 | */ 13 | public class AvsSetMuteItem extends AvsItem{ 14 | boolean mute; 15 | 16 | /** 17 | * Create a new AdjustVolume {@link com.willblaschko.android.alexa.data.Directive} 18 | * @param mute whether the device should be mute upon parsing the directive. 19 | */ 20 | public AvsSetMuteItem(String token, boolean mute){ 21 | super(token); 22 | this.mute = mute; 23 | } 24 | 25 | public boolean isMute() { 26 | return mute; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/speaker/AvsSetVolumeItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.speaker; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | /** 6 | * Directive to set the device volume 7 | * 8 | * {@link com.willblaschko.android.alexa.data.Directive} response item type parsed so we can properly 9 | * deal with the incoming commands from the Alexa server. 10 | * 11 | * @author will on 5/21/2016. 12 | */ 13 | public class AvsSetVolumeItem extends AvsItem{ 14 | long volume; 15 | 16 | /** 17 | * Create a new AdjustVolume {@link com.willblaschko.android.alexa.data.Directive} 18 | * @param volume the requested volume, 0-100 scale (requested as 1-10 by the user) 19 | */ 20 | public AvsSetVolumeItem(String token, long volume){ 21 | super(token); 22 | this.volume = volume; 23 | } 24 | 25 | /** 26 | * Get the {@link com.willblaschko.android.alexa.data.Directive}'s requested volume 27 | * @return the requested volume, 0-100 scale (requested as 1-10 by the user), this 28 | * value needs to be adjusted to the local device's min/max 29 | */ 30 | public long getVolume() { 31 | return volume; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/speechrecognizer/AvsExpectSpeechItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.speechrecognizer; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | /** 6 | * {@link com.willblaschko.android.alexa.data.Directive} to prompt the user for a speech input 7 | * 8 | * {@link com.willblaschko.android.alexa.data.Directive} response item type parsed so we can properly 9 | * deal with the incoming commands from the Alexa server. 10 | * 11 | * @author will on 5/21/2016. 12 | */ 13 | public class AvsExpectSpeechItem extends AvsItem { 14 | long timeoutInMiliseconds; 15 | 16 | public AvsExpectSpeechItem(){ 17 | this(null, 2000); 18 | } 19 | 20 | public AvsExpectSpeechItem(String token, long timeoutInMiliseconds){ 21 | super(token); 22 | this.timeoutInMiliseconds = timeoutInMiliseconds; 23 | } 24 | 25 | public long getTimeoutInMiliseconds() { 26 | return timeoutInMiliseconds; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/speechrecognizer/AvsListenItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.speechrecognizer; 2 | 3 | /** 4 | * Directive to prompt the user for a speech input 5 | * 6 | * See: {@link AvsExpectSpeechItem} 7 | * 8 | * {@link com.willblaschko.android.alexa.data.Directive} response item type parsed so we can properly 9 | * deal with the incoming commands from the Alexa server. 10 | * 11 | * @deprecated Check for {@link AvsExpectSpeechItem} instead 12 | * 13 | * @author will on 5/21/2016. 14 | */ 15 | 16 | @Deprecated 17 | public class AvsListenItem extends AvsExpectSpeechItem { 18 | public AvsListenItem(){ 19 | this(null, 2000); 20 | } 21 | public AvsListenItem(String token, long timeoutInMiliseconds) { 22 | super(token, timeoutInMiliseconds); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/speechrecognizer/AvsStopCaptureItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.speechrecognizer; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | /** 6 | * Created by will on 4/9/2017. 7 | */ 8 | 9 | public class AvsStopCaptureItem extends AvsItem { 10 | public AvsStopCaptureItem(String token) { 11 | super(token); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/speechrecognizer/SpeechSendAudio.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.speechrecognizer; 2 | 3 | import android.util.Log; 4 | 5 | import com.willblaschko.android.alexa.callbacks.AsyncCallback; 6 | import com.willblaschko.android.alexa.interfaces.AvsException; 7 | import com.willblaschko.android.alexa.requestbody.DataRequestBody; 8 | 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.io.IOException; 12 | 13 | import okhttp3.Call; 14 | import okhttp3.RequestBody; 15 | 16 | /** 17 | * A subclass of {@link SpeechSendEvent} that sends a RequestBody to the AVS servers, this request body can either be a byte[] 18 | * straight write, or a threaded write loop based on incoming data (recorded audio). 19 | * 20 | * @author will on 4/17/2016. 21 | */ 22 | public class SpeechSendAudio extends SpeechSendEvent { 23 | 24 | private final static String TAG = "SpeechSendAudio"; 25 | 26 | long start = 0; 27 | DataRequestBody requestBody; 28 | 29 | /** 30 | * Post an audio byte[] to the Alexa Speech Recognizer API 31 | * @param url the URL to which we're sending the AVS post 32 | * @param accessToken our user's access token for the server 33 | * @param requestBody our OkHttp RequestBody for our mulitpart send, this request body can either be a byte[] 34 | * straight write, or a threaded write loop based on incoming data (recorded audio). 35 | * @param callback our event callbacks 36 | * @throws IOException 37 | */ 38 | public void sendAudio(final String url, final String accessToken, @NotNull DataRequestBody requestBody, 39 | final AsyncCallback callback) throws IOException { 40 | this.requestBody = requestBody; 41 | if(callback != null){ 42 | callback.start(); 43 | } 44 | Log.i(TAG, "Starting SpeechSendAudio procedure"); 45 | start = System.currentTimeMillis(); 46 | 47 | //call the parent class's prepareConnection() in order to prepare our URL POST 48 | try { 49 | prepareConnection(url, accessToken); 50 | final Call response = completePost(); 51 | 52 | if (callback != null) { 53 | if (response != null) { 54 | callback.success(response); 55 | } 56 | callback.complete(); 57 | } 58 | 59 | Log.i(TAG, "Audio sent"); 60 | Log.i(TAG, "Audio sending process took: " + (System.currentTimeMillis() - start)); 61 | } catch (IOException|AvsException e) { 62 | onError(callback, e); 63 | } 64 | } 65 | 66 | public void cancelRequest() { 67 | cancelCall(); 68 | } 69 | 70 | public void onError(final AsyncCallback callback, Exception e) { 71 | if(callback != null){ 72 | callback.failure(e); 73 | callback.complete(); 74 | } 75 | } 76 | 77 | @NotNull 78 | @Override 79 | protected RequestBody getRequestBody() { 80 | return requestBody; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/speechrecognizer/SpeechSendEvent.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.speechrecognizer; 2 | 3 | import com.willblaschko.android.alexa.data.Event; 4 | import com.willblaschko.android.alexa.interfaces.SendEvent; 5 | 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import okhttp3.MultipartBody; 9 | import okhttp3.RequestBody; 10 | 11 | /** 12 | * Abstract class to extend {@link SendEvent} to automatically add the RequestBody with the correct type 13 | * and name, as well as the SpeechRecognizer {@link Event} 14 | * 15 | * @author will on 5/21/2016. 16 | */ 17 | public abstract class SpeechSendEvent extends SendEvent { 18 | 19 | @NotNull 20 | @Override 21 | protected String getEvent() { 22 | return Event.getSpeechRecognizerEvent(); 23 | } 24 | 25 | @Override 26 | protected void addFormDataParts(MultipartBody.Builder builder){ 27 | builder.addFormDataPart("audio", "speech.wav", getRequestBody()); 28 | } 29 | 30 | @NotNull 31 | protected abstract RequestBody getRequestBody(); 32 | } 33 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/speechrecognizer/SpeechSendText.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.speechrecognizer; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | import android.util.Log; 6 | 7 | import com.willblaschko.android.alexa.VoiceHelper; 8 | import com.willblaschko.android.alexa.callbacks.AsyncCallback; 9 | import com.willblaschko.android.alexa.interfaces.AvsException; 10 | import com.willblaschko.android.alexa.requestbody.DataRequestBody; 11 | 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.io.IOException; 15 | 16 | import okhttp3.Call; 17 | import okhttp3.RequestBody; 18 | import okio.BufferedSink; 19 | 20 | /** 21 | * A subclass of {@link SpeechSendEvent} that allows an arbitrary text string to be sent to the AVS servers, translated through Google's text to speech engine 22 | * This speech is rendered using the VoiceHelper utility class, and is done on whatever thread this call is running 23 | */ 24 | public class SpeechSendText extends SpeechSendEvent { 25 | 26 | private final static String TAG = "SpeechSendText"; 27 | 28 | long start = 0; 29 | 30 | /** 31 | * Use VoiceHelper utility to create an audio file from arbitrary text using Text-To-Speech to be passed to the AVS servers 32 | * @param context local/application context 33 | * @param url the URL to which we're sending the AVS post 34 | * @param accessToken our user's access token for the server 35 | * @param text the text we want to translate into speech 36 | * @param callback our event callbacks 37 | * @throws IOException 38 | */ 39 | public void sendText(final Context context, final String url, final String accessToken, String text, 40 | final AsyncCallback callback) throws IOException { 41 | 42 | if(callback != null){ 43 | callback.start(); 44 | } 45 | 46 | Log.i(TAG, "Starting SpeechSendText procedure"); 47 | start = System.currentTimeMillis(); 48 | 49 | //add a pause to the end to be better understood 50 | if(!TextUtils.isEmpty(text)){ 51 | text = "... " + text + " ..."; 52 | } 53 | 54 | final String input = text; 55 | 56 | 57 | //call the parent class's prepareConnection() in order to prepare our URL POST 58 | prepareConnection(url, accessToken); 59 | 60 | //get our VoiceHelper and use an async callback to get the data and send it off to the AVS server via completePost() 61 | VoiceHelper voiceHelper = VoiceHelper.getInstance(context); 62 | voiceHelper.getSpeechFromText(input, new VoiceHelper.SpeechFromTextCallback() { 63 | @Override 64 | public void onSuccess(final byte[] data){ 65 | 66 | Log.i(TAG, "We have audio"); 67 | 68 | try { 69 | mOutputStream.write(data); 70 | 71 | Log.i(TAG, "Audio sent"); 72 | Log.i(TAG, "Audio creation process took: " + (System.currentTimeMillis() - start)); 73 | if(callback != null) { 74 | callback.success(completePost()); 75 | callback.complete(); 76 | } 77 | 78 | } catch (IOException e) { 79 | onError(e); 80 | } catch (AvsException e) { 81 | onError(e); 82 | } 83 | } 84 | 85 | 86 | @Override 87 | public void onError(Exception e) { 88 | if(callback != null){ 89 | callback.failure(e); 90 | callback.complete(); 91 | } 92 | } 93 | }); 94 | 95 | } 96 | 97 | 98 | @NotNull 99 | @Override 100 | protected RequestBody getRequestBody() { 101 | return new DataRequestBody() { 102 | @Override 103 | public void writeTo(BufferedSink sink) throws IOException { 104 | sink.write(mOutputStream.toByteArray()); 105 | } 106 | }; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/speechsynthesizer/AvsSpeakItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.speechsynthesizer; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | import org.apache.commons.io.IOUtils; 6 | 7 | import java.io.ByteArrayInputStream; 8 | import java.io.IOException; 9 | 10 | /** 11 | * Directive to play a local, returned audio item from the Alexa post/get response 12 | * 13 | * {@link com.willblaschko.android.alexa.data.Directive} response item type parsed so we can properly 14 | * deal with the incoming commands from the Alexa server. 15 | * 16 | * @author will on 5/21/2016. 17 | */ 18 | public class AvsSpeakItem extends AvsItem { 19 | private String mCid; 20 | private byte[] mAudio; 21 | 22 | public AvsSpeakItem(String token, String cid, ByteArrayInputStream audio) throws IOException { 23 | this(token, cid, IOUtils.toByteArray(audio)); 24 | audio.close(); 25 | } 26 | 27 | public AvsSpeakItem(String token, String cid, byte[] audio){ 28 | super(token); 29 | mCid = cid; 30 | mAudio = audio; 31 | } 32 | 33 | public String getCid() { 34 | return mCid; 35 | } 36 | 37 | public byte[] getAudio() { 38 | return mAudio; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/interfaces/system/AvsSetEndpointItem.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.interfaces.system; 2 | 3 | import com.willblaschko.android.alexa.interfaces.AvsItem; 4 | 5 | /** 6 | * Created by will on 4/8/2017. 7 | */ 8 | 9 | public class AvsSetEndpointItem extends AvsItem { 10 | String endpoint; 11 | public AvsSetEndpointItem(String token, String endpoint) { 12 | super(token); 13 | this.endpoint = endpoint; 14 | } 15 | 16 | public String getEndpoint() { 17 | return endpoint; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/requestbody/DataRequestBody.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.requestbody; 2 | 3 | import okhttp3.MediaType; 4 | import okhttp3.RequestBody; 5 | 6 | /** 7 | * An implemented class that automatically fills in the required MediaType for the {@link RequestBody} that is sent 8 | * in the {@link com.willblaschko.android.alexa.interfaces.SendEvent} class. 9 | * 10 | * @author will on 5/28/2016. 11 | */ 12 | public abstract class DataRequestBody extends RequestBody { 13 | @Override 14 | public MediaType contentType() { 15 | return MediaType.parse("application/octet-stream"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/service/BootReceiver.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.service; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.util.Log; 7 | 8 | /** 9 | * @author will on 4/17/2016. 10 | */ 11 | public class BootReceiver extends BroadcastReceiver { 12 | 13 | private static final String TAG = "BootReceiver"; 14 | 15 | @Override 16 | public void onReceive(Context context, Intent intent) { 17 | 18 | //start our service in the background 19 | Intent stickyIntent = new Intent(context, DownChannelService.class); 20 | context.startService(stickyIntent); 21 | Log.i(TAG, "Started down channel service."); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/utility/SigningKey.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.utility; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.content.pm.Signature; 7 | 8 | import java.io.ByteArrayInputStream; 9 | import java.io.InputStream; 10 | import java.security.MessageDigest; 11 | import java.security.NoSuchAlgorithmException; 12 | import java.security.cert.CertificateEncodingException; 13 | import java.security.cert.CertificateException; 14 | import java.security.cert.CertificateFactory; 15 | import java.security.cert.X509Certificate; 16 | 17 | /** 18 | * Utility functions to get the application signing key versus running the keytool in java 19 | */ 20 | public class SigningKey { 21 | 22 | /** 23 | * Get the MD5 fingerprint required for application authentication on the server to set up security profiles 24 | * @param context any Context from the running application 25 | * @return the string equivalent of the MD5 fingerprint 26 | */ 27 | public static String getCertificateMD5Fingerprint(Context context) { 28 | PackageManager pm = context.getPackageManager(); 29 | String packageName = context.getPackageName(); 30 | int flags = PackageManager.GET_SIGNATURES; 31 | PackageInfo packageInfo = null; 32 | try { 33 | packageInfo = pm.getPackageInfo(packageName, flags); 34 | } catch (PackageManager.NameNotFoundException e) { 35 | e.printStackTrace(); 36 | } 37 | Signature[] signatures = packageInfo.signatures; 38 | byte[] cert = signatures[0].toByteArray(); 39 | InputStream input = new ByteArrayInputStream(cert); 40 | CertificateFactory cf = null; 41 | try { 42 | cf = CertificateFactory.getInstance("X509"); 43 | } catch (CertificateException e) { 44 | e.printStackTrace(); 45 | } 46 | X509Certificate c = null; 47 | try { 48 | c = (X509Certificate) cf.generateCertificate(input); 49 | } catch (CertificateException e) { 50 | e.printStackTrace(); 51 | } 52 | String hexString = null; 53 | try { 54 | MessageDigest md = MessageDigest.getInstance("MD5"); 55 | byte[] publicKey = md.digest(c.getEncoded()); 56 | hexString = byte2HexFormatted(publicKey); 57 | } catch (NoSuchAlgorithmException e1) { 58 | e1.printStackTrace(); 59 | } catch (CertificateEncodingException e) { 60 | e.printStackTrace(); 61 | } 62 | return hexString; 63 | } 64 | 65 | /** 66 | * Convert the resulting byte array into a string for submission 67 | * @param arr the byte array supplied by getCertificateMD5Fingerprint 68 | * @return the string equivalent 69 | */ 70 | public static String byte2HexFormatted(byte[] arr) { 71 | StringBuilder str = new StringBuilder(arr.length * 2); 72 | for (int i = 0; i < arr.length; i++) { 73 | String h = Integer.toHexString(arr[i]); 74 | int l = h.length(); 75 | if (l == 1) h = "0" + h; 76 | if (l > 2) h = h.substring(l - 2, l); 77 | str.append(h.toUpperCase()); 78 | if (i < (arr.length - 1)) str.append(':'); 79 | } 80 | return str.toString(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/java/com/willblaschko/android/alexa/utility/Util.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.alexa.utility; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.os.Handler; 6 | import android.os.Looper; 7 | import android.preference.PreferenceManager; 8 | import android.text.TextUtils; 9 | import android.widget.Toast; 10 | 11 | import java.util.UUID; 12 | 13 | /** 14 | * A collection of utility functions. 15 | * 16 | * @author wblaschko on 8/13/15. 17 | */ 18 | public class Util { 19 | private static SharedPreferences mPreferences; 20 | public static final String IDENTIFIER = "identifier"; 21 | 22 | /** 23 | * Show an authorization toast on the main thread to make sure the user sees it 24 | * @param context local context 25 | * @param message the message to show the user 26 | */ 27 | public static void showAuthToast(final Context context, final String message){ 28 | new Handler(Looper.getMainLooper()).post(new Runnable() { 29 | @Override 30 | public void run() { 31 | Toast authToast = Toast.makeText(context, message, Toast.LENGTH_LONG); 32 | authToast.show(); 33 | } 34 | }); 35 | } 36 | 37 | 38 | /** 39 | * Get our default shared preferences 40 | * @param context local/application context 41 | * @return default shared preferences 42 | */ 43 | public static SharedPreferences getPreferences(Context context) { 44 | if (mPreferences == null) { 45 | mPreferences = PreferenceManager.getDefaultSharedPreferences(context); 46 | } 47 | return mPreferences; 48 | } 49 | 50 | public static String getIdentifier(){ 51 | return (mPreferences != null) ? mPreferences.getString(IDENTIFIER, "") : ""; 52 | } 53 | 54 | public static String getUuid(){ 55 | String identifier = getIdentifier(); 56 | String prefix = (TextUtils.isEmpty(identifier)) ? "" : getIdentifier()+"."; 57 | return prefix + UUID.randomUUID().toString(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | https://avs-alexa-na.amazon.com 5 | v20160207 6 | -------------------------------------------------------------------------------- /libs/AlexaAndroid/src/test/java/com/willblaschko/android/recorderview/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.recorderview; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /libs/RecorderLevelView/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/RecorderLevelView/src/androidTest/java/com/willblaschko/android/recorderview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.recorderview; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /libs/RecorderLevelView/RecorderLevelView/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/RecorderLevelView/src/main/java/com/willblaschko/android/recorderview/RecorderView.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.recorderview; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Paint; 7 | import android.graphics.drawable.Drawable; 8 | import android.os.Build; 9 | import android.support.v4.content.ContextCompat; 10 | import android.util.AttributeSet; 11 | import android.view.View; 12 | 13 | /** 14 | * @author willb_000 on 5/5/2016. 15 | */ 16 | public class RecorderView extends View { 17 | 18 | private final static String TAG = "RecorderView"; 19 | 20 | private static final int ROTATION_SPEED = 1; 21 | 22 | public static final int COLOR_INDICATOR_DEFAULT = 0xff3F51B5; 23 | public static final int COLOR_INDICATOR_GONE = 0x00000000; 24 | 25 | private float rmsdbLevel = 0; 26 | private float rotation = 0; 27 | 28 | Paint backgroundPaint; 29 | Paint wavePaint; 30 | 31 | int width = 0; 32 | int height = 0; 33 | int min = 0; 34 | int imageSize; 35 | int waveRotation = 30; 36 | 37 | Drawable microphone; 38 | 39 | public RecorderView(Context context) { 40 | super(context); 41 | init(); 42 | } 43 | 44 | public RecorderView(Context context, AttributeSet attrs) { 45 | super(context, attrs); 46 | init(); 47 | } 48 | 49 | public RecorderView(Context context, AttributeSet attrs, int defStyleAttr) { 50 | super(context, attrs, defStyleAttr); 51 | init(); 52 | } 53 | 54 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 55 | public RecorderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 56 | super(context, attrs, defStyleAttr, defStyleRes); 57 | init(); 58 | } 59 | 60 | @Override 61 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 62 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 63 | 64 | width = MeasureSpec.getSize(widthMeasureSpec); 65 | height = MeasureSpec.getSize(heightMeasureSpec); 66 | min = Math.min(width, height); 67 | 68 | imageSize = (int) (min * .45); 69 | setRmsdbLevel(1); 70 | } 71 | 72 | private void init(){ 73 | backgroundPaint = new Paint(); 74 | backgroundPaint.setColor(0x66000000); 75 | backgroundPaint.setStyle(Paint.Style.FILL); 76 | 77 | wavePaint = new Paint(); 78 | wavePaint.setColor(COLOR_INDICATOR_DEFAULT); 79 | wavePaint.setAntiAlias(true); 80 | wavePaint.setStyle(Paint.Style.FILL); 81 | } 82 | 83 | public void setRmsdbLevel(float level){ 84 | rmsdbLevel = level; 85 | postInvalidate(); 86 | } 87 | 88 | public void setIndicatorColor(int color){ 89 | wavePaint.setColor(color); 90 | postInvalidate(); 91 | } 92 | 93 | @Override 94 | protected void onDraw(Canvas canvas) { 95 | super.onDraw(canvas); 96 | 97 | canvas.drawCircle(width / 2, height / 2, getRadius(), wavePaint); 98 | 99 | if(microphone == null){ 100 | microphone = ContextCompat.getDrawable(getContext(), R.drawable.microphone); 101 | microphone.setFilterBitmap(true); 102 | microphone.setBounds((width - imageSize) / 2, (height - imageSize) / 2, width - ((width - imageSize) / 2), height - ((height - imageSize) / 2)); 103 | } 104 | 105 | microphone.draw(canvas); 106 | 107 | // 108 | // rotation+=ROTATION_SPEED; 109 | // postInvalidateDelayed(100); 110 | } 111 | 112 | private float getRadius(){ 113 | float percent = (float) (rmsdbLevel * Math.log(rmsdbLevel)) * .01f; 114 | percent = Math.min(Math.max(percent, 0f), 1f); 115 | percent = .55f + .45f * percent; 116 | return percent * ((float) min) / 2f; 117 | } 118 | // 119 | // Path wavePath; 120 | // private Path getPath(){ 121 | // 122 | // wavePath = new Path(); 123 | // 124 | // wavePath.moveTo(); 125 | // 126 | // for(int i = 0; i < 360 / waveRotation; i++){ 127 | // 128 | // } 129 | // 130 | // return wavePath; 131 | // } 132 | // 133 | // private void getArcPoint(int degree, float value){ 134 | // 135 | // } 136 | } 137 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/RecorderLevelView/src/main/res/drawable-nodpi/microphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/libs/RecorderLevelView/RecorderLevelView/src/main/res/drawable-nodpi/microphone.png -------------------------------------------------------------------------------- /libs/RecorderLevelView/RecorderLevelView/src/main/res/layout/test.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/RecorderLevelView/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/RecorderLevelView/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | RecorderView 3 | 4 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/RecorderLevelView/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/RecorderLevelView/src/test/java/com/willblaschko/android/recorderview/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.recorderview; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /libs/RecorderLevelView/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion '25.0.0' 6 | 7 | defaultConfig { 8 | minSdkVersion 12 9 | targetSdkVersion 24 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile 'com.android.support:appcompat-v7:24.2.0' 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | testCompile 'junit:junit:4.12' 25 | } 26 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\willb_000\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/src/androidTest/java/com/willblaschko/android/recorderview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.recorderview; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /libs/RecorderLevelView/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/src/main/java/com/willblaschko/android/recorderview/RecorderView.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.recorderview; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Paint; 7 | import android.graphics.drawable.Drawable; 8 | import android.os.Build; 9 | import android.support.v4.content.ContextCompat; 10 | import android.util.AttributeSet; 11 | import android.view.View; 12 | 13 | /** 14 | * @author willb_000 on 5/5/2016. 15 | */ 16 | public class RecorderView extends View { 17 | 18 | private final static String TAG = "RecorderView"; 19 | 20 | private static final int ROTATION_SPEED = 1; 21 | 22 | public static final int COLOR_INDICATOR_DEFAULT = 0xff3F51B5; 23 | public static final int COLOR_INDICATOR_GONE = 0x00000000; 24 | 25 | private float rmsdbLevel = 0; 26 | private float rotation = 0; 27 | 28 | Paint backgroundPaint; 29 | Paint wavePaint; 30 | 31 | int width = 0; 32 | int height = 0; 33 | int min = 0; 34 | int imageSize; 35 | int waveRotation = 30; 36 | 37 | Drawable microphone; 38 | 39 | public RecorderView(Context context) { 40 | super(context); 41 | init(); 42 | } 43 | 44 | public RecorderView(Context context, AttributeSet attrs) { 45 | super(context, attrs); 46 | init(); 47 | } 48 | 49 | public RecorderView(Context context, AttributeSet attrs, int defStyleAttr) { 50 | super(context, attrs, defStyleAttr); 51 | init(); 52 | } 53 | 54 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 55 | public RecorderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 56 | super(context, attrs, defStyleAttr, defStyleRes); 57 | init(); 58 | } 59 | 60 | @Override 61 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 62 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 63 | 64 | width = MeasureSpec.getSize(widthMeasureSpec); 65 | height = MeasureSpec.getSize(heightMeasureSpec); 66 | min = Math.min(width, height); 67 | 68 | imageSize = (int) (min * .45); 69 | setRmsdbLevel(1); 70 | } 71 | 72 | private void init(){ 73 | backgroundPaint = new Paint(); 74 | backgroundPaint.setColor(0x66000000); 75 | backgroundPaint.setStyle(Paint.Style.FILL); 76 | 77 | wavePaint = new Paint(); 78 | wavePaint.setColor(COLOR_INDICATOR_DEFAULT); 79 | wavePaint.setAntiAlias(true); 80 | wavePaint.setStyle(Paint.Style.FILL); 81 | } 82 | 83 | public void setRmsdbLevel(float level){ 84 | rmsdbLevel = level; 85 | postInvalidate(); 86 | } 87 | 88 | public void setIndicatorColor(int color){ 89 | wavePaint.setColor(color); 90 | postInvalidate(); 91 | } 92 | 93 | @Override 94 | protected void onDraw(Canvas canvas) { 95 | super.onDraw(canvas); 96 | 97 | canvas.drawCircle(width / 2, height / 2, getRadius(), wavePaint); 98 | 99 | if(microphone == null){ 100 | microphone = ContextCompat.getDrawable(getContext(), R.drawable.microphone); 101 | microphone.setFilterBitmap(true); 102 | microphone.setBounds((width - imageSize) / 2, (height - imageSize) / 2, width - ((width - imageSize) / 2), height - ((height - imageSize) / 2)); 103 | } 104 | 105 | microphone.draw(canvas); 106 | 107 | // 108 | // rotation+=ROTATION_SPEED; 109 | // postInvalidateDelayed(100); 110 | } 111 | 112 | private float getRadius(){ 113 | float percent = (float) (rmsdbLevel * Math.log(rmsdbLevel)) * .01f; 114 | percent = Math.min(Math.max(percent, 0f), 1f); 115 | percent = .55f + .45f * percent; 116 | return percent * ((float) min) / 2f; 117 | } 118 | // 119 | // Path wavePath; 120 | // private Path getPath(){ 121 | // 122 | // wavePath = new Path(); 123 | // 124 | // wavePath.moveTo(); 125 | // 126 | // for(int i = 0; i < 360 / waveRotation; i++){ 127 | // 128 | // } 129 | // 130 | // return wavePath; 131 | // } 132 | // 133 | // private void getArcPoint(int degree, float value){ 134 | // 135 | // } 136 | } 137 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/src/main/res/drawable-nodpi/microphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/libs/RecorderLevelView/src/main/res/drawable-nodpi/microphone.png -------------------------------------------------------------------------------- /libs/RecorderLevelView/src/main/res/layout/test.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | RecorderView 3 | 4 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /libs/RecorderLevelView/src/test/java/com/willblaschko/android/recorderview/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.willblaschko.android.recorderview; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /libs/speechutils-master/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /libs/speechutils-master/README.md: -------------------------------------------------------------------------------- 1 | Speechutils 2 | =========== 3 | 4 | [![Codacy Badge](https://api.codacy.com/project/badge/grade/bc2e3589e2714093be39f876016b9ada)](https://www.codacy.com/app/kaljurand/speechutils) 5 | 6 | Speechutils is an Android library that helps to implement apps that need to include speech-to-text and text-to-speech functionality. 7 | For example, it provides methods for 8 | 9 | - audio recording and encoding 10 | - aggregating speech-to-text and text-to-speech services 11 | - playing audio cues before/after speech-to-text 12 | - pausing the background audio during speech-to-text 13 | 14 | Used by 15 | ------- 16 | 17 | - https://github.com/Kaljurand/K6nele 18 | - https://github.com/Kaljurand/Arvutaja 19 | -------------------------------------------------------------------------------- /libs/speechutils-master/app/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:2.3.0' 7 | } 8 | } 9 | 10 | repositories { 11 | jcenter() 12 | } 13 | 14 | apply plugin: 'com.android.library' 15 | 16 | dependencies { 17 | // Required -- JUnit 4 framework 18 | testCompile 'junit:junit:4.12' 19 | 20 | androidTestCompile 'com.android.support:support-annotations:24.2.1' 21 | androidTestCompile 'com.android.support.test:runner:0.5' 22 | androidTestCompile 'com.android.support.test:rules:0.5' 23 | // Optional -- Hamcrest library 24 | androidTestCompile 'org.hamcrest:hamcrest-library:1.3' 25 | } 26 | 27 | android { 28 | compileSdkVersion 24 29 | buildToolsVersion '24.0.2' 30 | 31 | defaultConfig { 32 | minSdkVersion 12 33 | targetSdkVersion 24 34 | versionCode 204 35 | versionName '0.2.04' 36 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/androidTest/java/ee/ioc/phon/android/speechutils/editor/InputConnectionCommandEditorTest.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils.editor; 2 | 3 | import android.content.Context; 4 | import android.support.test.runner.AndroidJUnit4; 5 | import android.test.suitebuilder.annotation.SmallTest; 6 | import android.view.inputmethod.EditorInfo; 7 | import android.view.inputmethod.InputConnection; 8 | import android.widget.EditText; 9 | 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | 14 | import static android.support.test.InstrumentationRegistry.getInstrumentation; 15 | import static org.hamcrest.Matchers.is; 16 | import static org.junit.Assert.assertThat; 17 | import static org.junit.Assert.assertNotNull; 18 | 19 | @RunWith(AndroidJUnit4.class) 20 | @SmallTest 21 | public class InputConnectionCommandEditorTest { 22 | 23 | private InputConnectionCommandEditor mEditor; 24 | 25 | @Before 26 | public void before() { 27 | Context context = getInstrumentation().getContext(); 28 | EditText view = new EditText(context); 29 | //view.setText("elas metsas mutionu, keset kuuski noori-vanu"); 30 | EditorInfo editorInfo = new EditorInfo(); 31 | //editorInfo.initialSelStart = 12; 32 | //editorInfo.initialSelEnd = 19; 33 | InputConnection connection = view.onCreateInputConnection(editorInfo); 34 | //InputConnection connection = new BaseInputConnection(view, true); 35 | mEditor = new InputConnectionCommandEditor(); 36 | mEditor.setInputConnection(connection); 37 | } 38 | 39 | @Test 40 | public void test01() { 41 | assertNotNull(mEditor.getInputConnection()); 42 | } 43 | 44 | @Test 45 | public void test02() { 46 | assertThat(mEditor.commitFinalResult("start12345 67890"), is(true)); 47 | assertThat(getTextBeforeCursor(5), is("67890")); 48 | assertThat(mEditor.deleteLeftWord(), is(true)); 49 | assertThat(getTextBeforeCursor(5), is("12345")); 50 | assertThat(mEditor.delete("12345"), is(true)); 51 | assertThat(getTextBeforeCursor(5), is("Start")); 52 | } 53 | 54 | 55 | // TODO: @Test 56 | // Can't create handler inside thread that has not called Looper.prepare() 57 | public void test03() { 58 | assertThat(mEditor.copy(), is(true)); 59 | assertThat(mEditor.paste(), is(true)); 60 | assertThat(mEditor.paste(), is(true)); 61 | } 62 | 63 | @Test 64 | public void test04() { 65 | assertThat(mEditor.commitPartialResult("...123"), is(true)); 66 | assertThat(mEditor.commitPartialResult("...124"), is(true)); 67 | assertThat(mEditor.commitFinalResult("...1245"), is(true)); 68 | assertThat(mEditor.goToCharacterPosition(4), is(true)); 69 | assertThat(getTextBeforeCursor(10), is("...1")); 70 | } 71 | 72 | @Test 73 | public void test05() { 74 | assertThat(mEditor.commitFinalResult("a12345 67890_12345"), is(true)); 75 | assertThat(mEditor.select("12345"), is(true)); 76 | assertThat(getTextBeforeCursor(2), is("0_")); 77 | assertThat(mEditor.deleteLeftWord(), is(true)); 78 | assertThat(getTextBeforeCursor(2), is("0_")); 79 | assertThat(mEditor.deleteLeftWord(), is(true)); 80 | assertThat(getTextBeforeCursor(2), is("45")); 81 | } 82 | 83 | @Test 84 | public void test06() { 85 | assertThat(mEditor.commitFinalResult("a12345 67890_12345"), is(true)); 86 | assertThat(mEditor.replace("12345", "abcdef"), is(true)); 87 | assertThat(mEditor.addSpace(), is(true)); 88 | assertThat(mEditor.replace("12345", "ABC"), is(true)); 89 | assertThat(getTextBeforeCursor(2), is("BC")); 90 | assertThat(mEditor.addNewline(), is(true)); 91 | assertThat(mEditor.addSpace(), is(true)); 92 | assertThat(mEditor.goToCharacterPosition(9), is(true)); 93 | assertThat(getTextBeforeCursor(2), is("67")); 94 | } 95 | 96 | private String getTextBeforeCursor(int n) { 97 | return mEditor.getInputConnection().getTextBeforeCursor(n, 0).toString(); 98 | } 99 | } -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/java/ee/ioc/phon/android/speechutils/AudioCue.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils; 2 | 3 | import android.content.Context; 4 | import android.media.AudioManager; 5 | import android.media.MediaPlayer; 6 | import android.os.SystemClock; 7 | 8 | // TODO: add a method that calls back when audio is finished 9 | public class AudioCue { 10 | 11 | private static final int DELAY_AFTER_START_BEEP = 200; 12 | 13 | private final Context mContext; 14 | private final int mStartSound; 15 | private final int mStopSound; 16 | private final int mErrorSound; 17 | 18 | public AudioCue(Context context) { 19 | mContext = context; 20 | mStartSound = R.raw.explore_begin; 21 | mStopSound = R.raw.explore_end; 22 | mErrorSound = R.raw.error; 23 | } 24 | 25 | public AudioCue(Context context, int startSound, int stopSound, int errorSound) { 26 | mContext = context; 27 | mStartSound = startSound; 28 | mStopSound = stopSound; 29 | mErrorSound = errorSound; 30 | } 31 | 32 | public void playStartSoundAndSleep() { 33 | if (playSound(mStartSound)) { 34 | SystemClock.sleep(DELAY_AFTER_START_BEEP); 35 | } 36 | } 37 | 38 | 39 | public void playStopSound() { 40 | playSound(mStopSound); 41 | } 42 | 43 | 44 | public void playErrorSound() { 45 | playSound(mErrorSound); 46 | } 47 | 48 | 49 | private boolean playSound(int sound) { 50 | MediaPlayer mp = MediaPlayer.create(mContext, sound); 51 | // create can return null, e.g. on Android Wear 52 | if (mp == null) { 53 | return false; 54 | } 55 | mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 56 | mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 57 | @Override 58 | public void onCompletion(MediaPlayer mp) { 59 | mp.release(); 60 | } 61 | }); 62 | mp.start(); 63 | return true; 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/java/ee/ioc/phon/android/speechutils/AudioPauser.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils; 2 | 3 | import android.content.Context; 4 | import android.media.AudioManager; 5 | import android.media.AudioManager.OnAudioFocusChangeListener; 6 | 7 | /** 8 | * Pauses the audio stream by requesting the audio focus and 9 | * muting the music stream. 10 | *

11 | * TODO: Test this is two interleaving instances of AudioPauser, e.g. 12 | * TTS starts playing and calls the AudioPauser, at the same time 13 | * the recognizer starts listening and also calls the AudioPauser. 14 | */ 15 | public class AudioPauser { 16 | 17 | private final boolean mIsMuteStream; 18 | private final AudioManager mAudioManager; 19 | private final OnAudioFocusChangeListener mAfChangeListener; 20 | private int mCurrentVolume = 0; 21 | private boolean isPausing = false; 22 | 23 | public AudioPauser(Context context) { 24 | this(context, true); 25 | } 26 | 27 | 28 | public AudioPauser(Context context, boolean isMuteStream) { 29 | mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 30 | mIsMuteStream = isMuteStream; 31 | 32 | mAfChangeListener = new OnAudioFocusChangeListener() { 33 | public void onAudioFocusChange(int focusChange) { 34 | Log.i("onAudioFocusChange" + focusChange); 35 | } 36 | }; 37 | } 38 | 39 | 40 | /** 41 | * Requests audio focus with the goal of pausing any existing audio player. 42 | * Additionally mutes the music stream, since some audio players might 43 | * ignore the focus request. 44 | * In other words, during the pause no sound will be heard, 45 | * but whether the audio resumes from the same position after the pause 46 | * depends on the audio player. 47 | */ 48 | public void pause() { 49 | if (!isPausing) { 50 | int result = mAudioManager.requestAudioFocus(mAfChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); 51 | if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { 52 | Log.i("AUDIOFOCUS_REQUEST_GRANTED"); 53 | } 54 | 55 | if (mIsMuteStream) { 56 | mCurrentVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 57 | if (mCurrentVolume > 0) { 58 | mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0); 59 | } 60 | } 61 | isPausing = true; 62 | } 63 | } 64 | 65 | 66 | /** 67 | * Abandons audio focus and restores the audio volume. 68 | */ 69 | public void resume() { 70 | if (isPausing) { 71 | mAudioManager.abandonAudioFocus(mAfChangeListener); 72 | if (mIsMuteStream && mCurrentVolume > 0) { 73 | mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, mCurrentVolume, 0); 74 | } 75 | isPausing = false; 76 | } 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/java/ee/ioc/phon/android/speechutils/AudioRecorder.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils; 2 | 3 | import android.media.MediaRecorder; 4 | 5 | public interface AudioRecorder { 6 | int DEFAULT_AUDIO_SOURCE = MediaRecorder.AudioSource.VOICE_RECOGNITION; 7 | int DEFAULT_SAMPLE_RATE = 16000; 8 | short RESOLUTION_IN_BYTES = 2; 9 | // Number of channels (MONO = 1, STEREO = 2) 10 | short CHANNELS = 1; 11 | 12 | String getWsArgs(); 13 | 14 | State getState(); 15 | 16 | byte[] consumeRecordingAndTruncate(); 17 | 18 | byte[] consumeRecording(); 19 | 20 | void start(); 21 | 22 | float getRmsdb(); 23 | 24 | void release(); 25 | 26 | boolean isPausing(); 27 | 28 | enum State { 29 | // recorder is ready, but not yet recording 30 | READY, 31 | 32 | // recorder recording 33 | RECORDING, 34 | 35 | // error occurred, reconstruction needed 36 | ERROR, 37 | 38 | // recorder stopped 39 | STOPPED 40 | } 41 | } -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/java/ee/ioc/phon/android/speechutils/Log.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils; 2 | 3 | import java.util.List; 4 | 5 | public class Log { 6 | 7 | public static final boolean DEBUG = BuildConfig.DEBUG; 8 | 9 | public static final String LOG_TAG = "speechutils"; 10 | 11 | public static void i(String msg) { 12 | if (DEBUG) android.util.Log.i(LOG_TAG, msg); 13 | } 14 | 15 | public static void i(List msgs) { 16 | if (DEBUG) { 17 | for (String msg : msgs) { 18 | if (msg == null) { 19 | msg = ""; 20 | } 21 | android.util.Log.i(LOG_TAG, msg); 22 | } 23 | } 24 | } 25 | 26 | public static void e(String msg) { 27 | if (DEBUG) android.util.Log.e(LOG_TAG, msg); 28 | } 29 | 30 | public static void i(String tag, String msg) { 31 | if (DEBUG) android.util.Log.i(tag, msg); 32 | } 33 | 34 | public static void e(String tag, String msg) { 35 | if (DEBUG) android.util.Log.e(tag, msg); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/java/ee/ioc/phon/android/speechutils/MediaFormatFactory.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils; 2 | 3 | import android.annotation.TargetApi; 4 | import android.media.MediaFormat; 5 | import android.os.Build; 6 | 7 | public class MediaFormatFactory { 8 | 9 | // TODO: add mimes 10 | public enum Type { 11 | AAC, AMR, FLAC 12 | } 13 | 14 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 15 | public static MediaFormat createMediaFormat(Type type, int sampleRate) { 16 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 17 | MediaFormat format = new MediaFormat(); 18 | // TODO: this causes a crash in MediaCodec.configure 19 | //format.setString(MediaFormat.KEY_FRAME_RATE, null); 20 | format.setInteger(MediaFormat.KEY_SAMPLE_RATE, sampleRate); 21 | format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); 22 | if (type == Type.AAC) { 23 | format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm"); 24 | format.setInteger(MediaFormat.KEY_AAC_PROFILE, 2); // TODO: or 39? 25 | format.setInteger(MediaFormat.KEY_BIT_RATE, 64000); 26 | } else if (type == Type.FLAC) { 27 | //format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_FLAC); // API=21 28 | format.setString(MediaFormat.KEY_MIME, "audio/flac"); 29 | format.setInteger(MediaFormat.KEY_BIT_RATE, 64000); 30 | //TODO: use another bit rate, does not seem to have effect always 31 | //format.setInteger(MediaFormat.KEY_BIT_RATE, 128000); 32 | } else { 33 | format.setString(MediaFormat.KEY_MIME, "audio/amr-wb"); 34 | format.setInteger(MediaFormat.KEY_BIT_RATE, 23050); 35 | } 36 | return format; 37 | } 38 | return null; 39 | } 40 | 41 | //final int kAACProfiles[] = { 42 | // 2 /* OMX_AUDIO_AACObjectLC */, 43 | // 5 /* OMX_AUDIO_AACObjectHE */, 44 | // 39 /* OMX_AUDIO_AACObjectELD */ 45 | //}; 46 | 47 | //if (kAACProfiles[k] == 5 && kSampleRates[i] < 22050) { 48 | // // Is this right? HE does not support sample rates < 22050Hz? 49 | // continue; 50 | //} 51 | // final int kSampleRates[] = {8000, 11025, 22050, 44100, 48000}; 52 | // final int kBitRates[] = {64000, 128000}; 53 | } -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/java/ee/ioc/phon/android/speechutils/RawAudioRecorder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2015, Institute of Cybernetics at Tallinn University of Technology 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package ee.ioc.phon.android.speechutils; 18 | 19 | /** 20 | *

Records raw audio using SpeechRecord and stores it into a byte array as

21 | *
    22 | *
  • signed
  • 23 | *
  • 16-bit
  • 24 | *
  • native endian
  • 25 | *
  • mono
  • 26 | *
  • 16kHz (recommended, but a different sample rate can be specified in the constructor)
  • 27 | *
28 | *

29 | *

For example, the corresponding arecord settings are

30 | *

31 | *

32 |  * arecord --file-type raw --format=S16_LE --channels 1 --rate 16000
33 |  * arecord --file-type raw --format=S16_BE --channels 1 --rate 16000 (possibly)
34 |  * 
35 | *

36 | * TODO: maybe use: ByteArrayOutputStream 37 | * 38 | * @author Kaarel Kaljurand 39 | */ 40 | public class RawAudioRecorder extends AbstractAudioRecorder { 41 | 42 | /** 43 | *

Instantiates a new recorder and sets the state to INITIALIZING. 44 | * In case of errors, no exception is thrown, but the state is set to ERROR.

45 | *

46 | *

Android docs say: 44100Hz is currently the only rate that is guaranteed to work on all devices, 47 | * but other rates such as 22050, 16000, and 11025 may work on some devices.

48 | * 49 | * @param audioSource Identifier of the audio source (e.g. microphone) 50 | * @param sampleRate Sample rate (e.g. 16000) 51 | */ 52 | public RawAudioRecorder(int audioSource, int sampleRate) { 53 | super(audioSource, sampleRate); 54 | try { 55 | int bufferSize = getBufferSize(); 56 | int framePeriod = bufferSize / (2 * RESOLUTION_IN_BYTES * CHANNELS); 57 | createRecorder(audioSource, sampleRate, bufferSize); 58 | createBuffer(framePeriod); 59 | setState(State.READY); 60 | } catch (Exception e) { 61 | if (e.getMessage() == null) { 62 | handleError("Unknown error occurred while initializing recorder"); 63 | } else { 64 | handleError(e.getMessage()); 65 | } 66 | } 67 | } 68 | 69 | 70 | public RawAudioRecorder(int sampleRate) { 71 | this(DEFAULT_AUDIO_SOURCE, sampleRate); 72 | } 73 | 74 | 75 | public RawAudioRecorder() { 76 | this(DEFAULT_AUDIO_SOURCE, DEFAULT_SAMPLE_RATE); 77 | } 78 | 79 | public String getWsArgs() { 80 | return "?content-type=audio/x-raw,+layout=(string)interleaved,+rate=(int)" + getSampleRate() + ",+format=(string)S16LE,+channels=(int)1"; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/java/ee/ioc/phon/android/speechutils/SpeechRecord.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils; 2 | 3 | import android.media.AudioFormat; 4 | import android.media.AudioRecord; 5 | import android.media.MediaRecorder; 6 | import android.media.audiofx.AcousticEchoCanceler; 7 | import android.media.audiofx.AutomaticGainControl; 8 | import android.media.audiofx.NoiseSuppressor; 9 | import android.os.Build; 10 | 11 | /** 12 | * The following takes effect only on Jelly Bean and higher. 13 | * 14 | * @author Kaarel Kaljurand 15 | */ 16 | public class SpeechRecord extends AudioRecord { 17 | 18 | public SpeechRecord(int sampleRateInHz, int bufferSizeInBytes) 19 | throws IllegalArgumentException { 20 | 21 | this( 22 | MediaRecorder.AudioSource.VOICE_RECOGNITION, 23 | sampleRateInHz, 24 | AudioFormat.CHANNEL_IN_MONO, 25 | AudioFormat.ENCODING_PCM_16BIT, 26 | bufferSizeInBytes, 27 | false, 28 | false, 29 | false 30 | ); 31 | } 32 | 33 | 34 | public SpeechRecord(int sampleRateInHz, int bufferSizeInBytes, boolean noise, boolean gain, boolean echo) 35 | throws IllegalArgumentException { 36 | 37 | this( 38 | MediaRecorder.AudioSource.VOICE_RECOGNITION, 39 | sampleRateInHz, 40 | AudioFormat.CHANNEL_IN_MONO, 41 | AudioFormat.ENCODING_PCM_16BIT, 42 | bufferSizeInBytes, 43 | noise, 44 | gain, 45 | echo 46 | ); 47 | } 48 | 49 | 50 | // This is a copy of the AudioRecord constructor 51 | public SpeechRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes) 52 | throws IllegalArgumentException { 53 | 54 | this(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, false, false, false); 55 | } 56 | 57 | 58 | public SpeechRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, 59 | boolean noise, boolean gain, boolean echo) 60 | throws IllegalArgumentException { 61 | 62 | super(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes); 63 | 64 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 65 | Log.i("Trying to enhance audio because running on SDK " + Build.VERSION.SDK_INT); 66 | 67 | int audioSessionId = getAudioSessionId(); 68 | 69 | if (noise) { 70 | if (NoiseSuppressor.create(audioSessionId) == null) { 71 | Log.i("NoiseSuppressor: failed"); 72 | } else { 73 | Log.i("NoiseSuppressor: ON"); 74 | } 75 | } else { 76 | Log.i("NoiseSuppressor: OFF"); 77 | } 78 | 79 | if (gain) { 80 | if (AutomaticGainControl.create(audioSessionId) == null) { 81 | Log.i("AutomaticGainControl: failed"); 82 | } else { 83 | Log.i("AutomaticGainControl: ON"); 84 | } 85 | } else { 86 | Log.i("AutomaticGainControl: OFF"); 87 | } 88 | 89 | if (echo) { 90 | if (AcousticEchoCanceler.create(audioSessionId) == null) { 91 | Log.i("AcousticEchoCanceler: failed"); 92 | } else { 93 | Log.i("AcousticEchoCanceler: ON"); 94 | } 95 | } else { 96 | Log.i("AcousticEchoCanceler: OFF"); 97 | } 98 | } 99 | } 100 | 101 | 102 | public static boolean isNoiseSuppressorAvailable() { 103 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 104 | return NoiseSuppressor.isAvailable(); 105 | } 106 | return false; 107 | } 108 | } -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/java/ee/ioc/phon/android/speechutils/TtsLocaleMapper.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Locale; 8 | import java.util.Map; 9 | 10 | public class TtsLocaleMapper { 11 | 12 | private static final List SIMILAR_LOCALES_ET; 13 | 14 | static { 15 | List aListEt = new ArrayList(); 16 | aListEt.add(new Locale("fi-FI")); 17 | aListEt.add(new Locale("es-ES")); 18 | SIMILAR_LOCALES_ET = Collections.unmodifiableList(aListEt); 19 | } 20 | 21 | private static final Map> SIMILAR_LOCALES; 22 | 23 | static { 24 | Map> aMap = new HashMap>(); 25 | aMap.put(new Locale("et-EE"), SIMILAR_LOCALES_ET); 26 | SIMILAR_LOCALES = Collections.unmodifiableMap(aMap); 27 | } 28 | 29 | public static List getSimilarLocales(Locale locale) { 30 | return SIMILAR_LOCALES.get(locale); 31 | } 32 | } -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/java/ee/ioc/phon/android/speechutils/editor/Command.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils.editor; 2 | 3 | import android.text.TextUtils; 4 | import android.util.Pair; 5 | 6 | import java.util.regex.Matcher; 7 | import java.util.regex.Pattern; 8 | 9 | public class Command { 10 | private final static String SEPARATOR = "___"; 11 | private final Pattern mPattern; 12 | private final String mReplacement; 13 | private final String mId; 14 | private final String[] mArgs; 15 | private final String mArgsAsStr; 16 | 17 | /** 18 | * @param pattern regular expression with capturing groups 19 | * @param replacement replacement string for the matched substrings, typically empty in case of commands 20 | * @param id name of the command to execute, null if missing 21 | * @param args arguments of the command 22 | */ 23 | public Command(Pattern pattern, String replacement, String id, String[] args) { 24 | mPattern = pattern; 25 | mReplacement = replacement; 26 | mId = id; 27 | if (args == null) { 28 | mArgs = new String[0]; 29 | } else { 30 | mArgs = args; 31 | } 32 | mArgsAsStr = TextUtils.join(SEPARATOR, mArgs); 33 | } 34 | 35 | public Command(String pattern, String replacement, String id, String[] args) { 36 | this(Pattern.compile(pattern), replacement, id, args); 37 | } 38 | 39 | public String getId() { 40 | return mId; 41 | } 42 | 43 | public Pattern getPattern() { 44 | return mPattern; 45 | } 46 | 47 | public String getReplacement() { 48 | return mReplacement; 49 | } 50 | 51 | public String[] getArgs() { 52 | return mArgs; 53 | } 54 | 55 | private Matcher matcher(CharSequence str) { 56 | return mPattern.matcher(str); 57 | } 58 | 59 | public Pair match(CharSequence str) { 60 | Matcher m = matcher(str); 61 | if (m.matches()) { 62 | String newStr = m.replaceAll(mReplacement); 63 | String[] argsEvaluated = TextUtils.split(m.replaceAll(mArgsAsStr), SEPARATOR); 64 | return new Pair<>(newStr, argsEvaluated); 65 | } 66 | return null; 67 | } 68 | 69 | public String toString() { 70 | return mPattern + "/" + mReplacement + "/" + mId + "(" + mArgs + ")"; 71 | } 72 | } -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/java/ee/ioc/phon/android/speechutils/editor/CommandEditor.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils.editor; 2 | 3 | /** 4 | * TODO: work in progress 5 | */ 6 | public interface CommandEditor { 7 | 8 | boolean commitFinalResult(String str); 9 | 10 | boolean commitPartialResult(String str); 11 | 12 | // Moving between fields 13 | 14 | // Go to the previous field 15 | boolean goToPreviousField(); 16 | 17 | // Go to the next field 18 | boolean goToNextField(); 19 | 20 | // Moving around in the string 21 | 22 | // Go to the character at the given position 23 | boolean goToCharacterPosition(int pos); 24 | 25 | boolean select(String str); 26 | 27 | // Reset selection 28 | boolean reset(); 29 | 30 | // Context menu actions 31 | boolean selectAll(); 32 | 33 | boolean cut(); 34 | 35 | boolean copy(); 36 | 37 | boolean paste(); 38 | 39 | // Editing 40 | 41 | boolean capitalize(String str); 42 | 43 | boolean addSpace(); 44 | 45 | boolean addNewline(); 46 | 47 | boolean deleteLeftWord(); 48 | 49 | boolean delete(String str); 50 | 51 | boolean replace(String str1, String str2); 52 | 53 | /** 54 | * Performs the Search-action, e.g. to launch search on a searchbar. 55 | */ 56 | boolean go(); 57 | } -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/java/ee/ioc/phon/android/speechutils/editor/Constants.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils.editor; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashSet; 5 | import java.util.Set; 6 | 7 | public class Constants { 8 | 9 | public static final Set CHARACTERS_WS = 10 | new HashSet<>(Arrays.asList(new Character[]{' ', '\n', '\t'})); 11 | 12 | // Symbols that should not be preceded by space in a written text. 13 | public static final Set CHARACTERS_PUNCT = 14 | new HashSet<>(Arrays.asList(new Character[]{',', ':', ';', '.', '!', '?'})); 15 | 16 | // Symbols after which the next word should be capitalized. 17 | // We include ) because ;-) often finishes a sentence. 18 | public static final Set CHARACTERS_EOS = 19 | new HashSet<>(Arrays.asList(new Character[]{'.', '!', '?', ')'})); 20 | } -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/java/ee/ioc/phon/android/speechutils/utils/PreferenceUtils.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils.utils; 2 | 3 | import android.content.SharedPreferences; 4 | import android.content.res.Resources; 5 | 6 | import java.util.Arrays; 7 | import java.util.Collections; 8 | import java.util.HashSet; 9 | import java.util.List; 10 | import java.util.Set; 11 | import java.util.UUID; 12 | 13 | public class PreferenceUtils { 14 | 15 | public static String getPrefString(SharedPreferences prefs, Resources res, int key, int defaultValue) { 16 | return prefs.getString(res.getString(key), res.getString(defaultValue)); 17 | } 18 | 19 | public static String getPrefString(SharedPreferences prefs, Resources res, int key) { 20 | return prefs.getString(res.getString(key), null); 21 | } 22 | 23 | public static Set getPrefStringSet(SharedPreferences prefs, Resources res, int key) { 24 | return prefs.getStringSet(res.getString(key), Collections.emptySet()); 25 | } 26 | 27 | public static Set getPrefStringSet(SharedPreferences prefs, Resources res, int key, int defaultValue) { 28 | return prefs.getStringSet(res.getString(key), getStringSetFromStringArray(res, defaultValue)); 29 | } 30 | 31 | public static boolean getPrefBoolean(SharedPreferences prefs, Resources res, int key, int defaultValue) { 32 | return prefs.getBoolean(res.getString(key), res.getBoolean(defaultValue)); 33 | } 34 | 35 | public static int getPrefInt(SharedPreferences prefs, Resources res, int key, int defaultValue) { 36 | return Integer.parseInt(getPrefString(prefs, res, key, defaultValue)); 37 | } 38 | 39 | public static String getUniqueId(SharedPreferences settings) { 40 | String id = settings.getString("id", null); 41 | if (id == null) { 42 | id = UUID.randomUUID().toString(); 43 | SharedPreferences.Editor editor = settings.edit(); 44 | editor.putString("id", id); 45 | editor.apply(); 46 | } 47 | return id; 48 | } 49 | 50 | public static Set getStringSetFromStringArray(Resources res, int key) { 51 | return new HashSet<>(Arrays.asList(res.getStringArray(key))); 52 | } 53 | 54 | public static List getStringListFromStringArray(Resources res, int key) { 55 | return Arrays.asList(res.getStringArray(key)); 56 | } 57 | 58 | public static void putPrefString(SharedPreferences prefs, Resources res, int key, String value) { 59 | SharedPreferences.Editor editor = prefs.edit(); 60 | editor.putString(res.getString(key), value); 61 | editor.apply(); 62 | } 63 | 64 | public static void putPrefStringSet(SharedPreferences prefs, Resources res, int key, Set value) { 65 | SharedPreferences.Editor editor = prefs.edit(); 66 | editor.putStringSet(res.getString(key), value); 67 | editor.apply(); 68 | } 69 | } -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/res/anim/fade_inout_inf.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/res/drawable/button_mic.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 | -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/res/drawable/button_mic_recording_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/res/drawable/button_mic_recording_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/res/drawable/button_mic_recording_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/res/drawable/button_mic_recording_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/res/drawable/button_mic_transcribing.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/res/drawable/button_mic_waiting.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/res/drawable/ic_voice_search_api_material.xml: -------------------------------------------------------------------------------- 1 | 18 | 24 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/res/raw/error.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/libs/speechutils-master/app/src/main/res/raw/error.wav -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/res/raw/explore_begin.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/libs/speechutils-master/app/src/main/res/raw/explore_begin.ogg -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/res/raw/explore_end.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/libs/speechutils-master/app/src/main/res/raw/explore_end.ogg -------------------------------------------------------------------------------- /libs/speechutils-master/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ffffffff 4 | #808080 5 | 6 | 7 | #11404040 8 | #ffcc00 9 | #996600 10 | #996600 11 | #ffcc00 12 | #ffcc00 13 | #ffcc00 14 | #ff4444 15 | #cc0000 16 | #c58be2 17 | #9933cc 18 | #424242 19 | -------------------------------------------------------------------------------- /libs/speechutils-master/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:2.3.0' 7 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.1' 8 | } 9 | } 10 | 11 | apply plugin: 'com.android.library' 12 | 13 | 14 | android { 15 | compileSdkVersion 24 16 | buildToolsVersion '25.0.0' 17 | 18 | defaultConfig { 19 | minSdkVersion 11 20 | targetSdkVersion 24 21 | 22 | } 23 | 24 | sourceSets { 25 | main { 26 | manifest.srcFile 'AndroidManifest.xml' 27 | java.srcDirs = ['src'] 28 | resources.srcDirs = ['src'] 29 | aidl.srcDirs = ['src'] 30 | renderscript.srcDirs = ['src'] 31 | res.srcDirs = ['res'] 32 | assets.srcDirs = ['assets'] 33 | } 34 | 35 | // Move the tests to tests/java, tests/res, etc... 36 | instrumentTest.setRoot('tests') 37 | 38 | // Move the build types to build-types/ 39 | // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ... 40 | // This moves them out of them default location under src//... which would 41 | // conflict with src/ being used by the main source set. 42 | // Adding new build types or product flavors should be accompanied 43 | // by a similar customization. 44 | debug.setRoot('build-types/debug') 45 | release.setRoot('build-types/release') 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /libs/speechutils-master/res/anim/fade_inout_inf.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /libs/speechutils-master/res/drawable/button_mic.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 | -------------------------------------------------------------------------------- /libs/speechutils-master/res/drawable/button_mic_recording_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /libs/speechutils-master/res/drawable/button_mic_recording_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /libs/speechutils-master/res/drawable/button_mic_recording_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /libs/speechutils-master/res/drawable/button_mic_recording_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /libs/speechutils-master/res/drawable/button_mic_transcribing.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /libs/speechutils-master/res/drawable/button_mic_waiting.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /libs/speechutils-master/res/drawable/ic_voice_search_api_material.xml: -------------------------------------------------------------------------------- 1 | 18 | 24 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /libs/speechutils-master/res/raw/error.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/libs/speechutils-master/res/raw/error.wav -------------------------------------------------------------------------------- /libs/speechutils-master/res/raw/explore_begin.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/libs/speechutils-master/res/raw/explore_begin.ogg -------------------------------------------------------------------------------- /libs/speechutils-master/res/raw/explore_end.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willblaschko/AlexaAndroid/88255b64d02f33448a04ab6e715a81012575da9f/libs/speechutils-master/res/raw/explore_end.ogg -------------------------------------------------------------------------------- /libs/speechutils-master/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ffffffff 4 | #808080 5 | 6 | 7 | #11404040 8 | #ffcc00 9 | #996600 10 | #996600 11 | #ffcc00 12 | #ffcc00 13 | #ffcc00 14 | #ff4444 15 | #cc0000 16 | #c58be2 17 | #9933cc 18 | #424242 19 | -------------------------------------------------------------------------------- /libs/speechutils-master/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /libs/speechutils-master/src/ee/ioc/phon/android/speechutils/AudioCue.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils; 2 | 3 | import android.content.Context; 4 | import android.media.AudioManager; 5 | import android.media.MediaPlayer; 6 | import android.os.SystemClock; 7 | 8 | // TODO: add a method that calls back when audio is finished 9 | public class AudioCue { 10 | 11 | private static final int DELAY_AFTER_START_BEEP = 200; 12 | 13 | private final Context mContext; 14 | private final int mStartSound; 15 | private final int mStopSound; 16 | private final int mErrorSound; 17 | 18 | public AudioCue(Context context) { 19 | mContext = context; 20 | mStartSound = R.raw.explore_begin; 21 | mStopSound = R.raw.explore_end; 22 | mErrorSound = R.raw.error; 23 | } 24 | 25 | public AudioCue(Context context, int startSound, int stopSound, int errorSound) { 26 | mContext = context; 27 | mStartSound = startSound; 28 | mStopSound = stopSound; 29 | mErrorSound = errorSound; 30 | } 31 | 32 | public void playStartSoundAndSleep() { 33 | if (playSound(mStartSound)) { 34 | SystemClock.sleep(DELAY_AFTER_START_BEEP); 35 | } 36 | } 37 | 38 | 39 | public void playStopSound() { 40 | playSound(mStopSound); 41 | } 42 | 43 | 44 | public void playErrorSound() { 45 | playSound(mErrorSound); 46 | } 47 | 48 | 49 | private boolean playSound(int sound) { 50 | MediaPlayer mp = MediaPlayer.create(mContext, sound); 51 | // create can return null, e.g. on Android Wear 52 | if (mp == null) { 53 | return false; 54 | } 55 | mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 56 | mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 57 | @Override 58 | public void onCompletion(MediaPlayer mp) { 59 | mp.release(); 60 | } 61 | }); 62 | mp.start(); 63 | return true; 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /libs/speechutils-master/src/ee/ioc/phon/android/speechutils/AudioPauser.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils; 2 | 3 | import android.content.Context; 4 | import android.media.AudioManager; 5 | import android.media.AudioManager.OnAudioFocusChangeListener; 6 | 7 | /** 8 | * Pauses the audio stream by requesting the audio focus and 9 | * muting the music stream. 10 | *

11 | * TODO: Test this is two interleaving instances of AudioPauser, e.g. 12 | * TTS starts playing and calls the AudioPauser, at the same time 13 | * the recognizer starts listening and also calls the AudioPauser. 14 | */ 15 | public class AudioPauser { 16 | 17 | private final boolean mIsMuteStream; 18 | private final AudioManager mAudioManager; 19 | private final OnAudioFocusChangeListener mAfChangeListener; 20 | private int mCurrentVolume = 0; 21 | private boolean isPausing = false; 22 | 23 | public AudioPauser(Context context) { 24 | this(context, true); 25 | } 26 | 27 | 28 | public AudioPauser(Context context, boolean isMuteStream) { 29 | mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 30 | mIsMuteStream = isMuteStream; 31 | 32 | mAfChangeListener = new OnAudioFocusChangeListener() { 33 | public void onAudioFocusChange(int focusChange) { 34 | Log.i("onAudioFocusChange" + focusChange); 35 | } 36 | }; 37 | } 38 | 39 | 40 | /** 41 | * Requests audio focus with the goal of pausing any existing audio player. 42 | * Additionally mutes the music stream, since some audio players might 43 | * ignore the focus request. 44 | * In other words, during the pause no sound will be heard, 45 | * but whether the audio resumes from the same position after the pause 46 | * depends on the audio player. 47 | */ 48 | public void pause() { 49 | if (!isPausing) { 50 | int result = mAudioManager.requestAudioFocus(mAfChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); 51 | if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { 52 | Log.i("AUDIOFOCUS_REQUEST_GRANTED"); 53 | } 54 | 55 | if (mIsMuteStream) { 56 | mCurrentVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 57 | if (mCurrentVolume > 0) { 58 | mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0); 59 | } 60 | } 61 | isPausing = true; 62 | } 63 | } 64 | 65 | 66 | /** 67 | * Abandons audio focus and restores the audio volume. 68 | */ 69 | public void resume() { 70 | if (isPausing) { 71 | mAudioManager.abandonAudioFocus(mAfChangeListener); 72 | if (mIsMuteStream && mCurrentVolume > 0) { 73 | mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, mCurrentVolume, 0); 74 | } 75 | isPausing = false; 76 | } 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /libs/speechutils-master/src/ee/ioc/phon/android/speechutils/AudioRecorder.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils; 2 | 3 | import android.media.MediaRecorder; 4 | 5 | public interface AudioRecorder { 6 | int DEFAULT_AUDIO_SOURCE = MediaRecorder.AudioSource.VOICE_RECOGNITION; 7 | int DEFAULT_SAMPLE_RATE = 16000; 8 | short RESOLUTION_IN_BYTES = 2; 9 | // Number of channels (MONO = 1, STEREO = 2) 10 | short CHANNELS = 1; 11 | 12 | String getWsArgs(); 13 | 14 | State getState(); 15 | 16 | byte[] consumeRecordingAndTruncate(); 17 | 18 | byte[] consumeRecording(); 19 | 20 | void start(); 21 | 22 | float getRmsdb(); 23 | 24 | void release(); 25 | 26 | boolean isPausing(); 27 | 28 | enum State { 29 | // recorder is ready, but not yet recording 30 | READY, 31 | 32 | // recorder recording 33 | RECORDING, 34 | 35 | // error occurred, reconstruction needed 36 | ERROR, 37 | 38 | // recorder stopped 39 | STOPPED 40 | } 41 | } -------------------------------------------------------------------------------- /libs/speechutils-master/src/ee/ioc/phon/android/speechutils/Log.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils; 2 | 3 | import java.util.List; 4 | 5 | public class Log { 6 | 7 | public static final boolean DEBUG = BuildConfig.DEBUG; 8 | 9 | public static final String LOG_TAG = "speechutils"; 10 | 11 | public static void i(String msg) { 12 | if (DEBUG) android.util.Log.i(LOG_TAG, msg); 13 | } 14 | 15 | public static void i(List msgs) { 16 | if (DEBUG) { 17 | for (String msg : msgs) { 18 | if (msg == null) { 19 | msg = ""; 20 | } 21 | android.util.Log.i(LOG_TAG, msg); 22 | } 23 | } 24 | } 25 | 26 | public static void e(String msg) { 27 | if (DEBUG) android.util.Log.e(LOG_TAG, msg); 28 | } 29 | 30 | public static void i(String tag, String msg) { 31 | if (DEBUG) android.util.Log.i(tag, msg); 32 | } 33 | 34 | public static void e(String tag, String msg) { 35 | if (DEBUG) android.util.Log.e(tag, msg); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /libs/speechutils-master/src/ee/ioc/phon/android/speechutils/MediaFormatFactory.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils; 2 | 3 | import android.annotation.TargetApi; 4 | import android.media.MediaFormat; 5 | import android.os.Build; 6 | 7 | public class MediaFormatFactory { 8 | 9 | // TODO: add mimes 10 | public enum Type { 11 | AAC, AMR, FLAC 12 | } 13 | 14 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 15 | public static MediaFormat createMediaFormat(Type type, int sampleRate) { 16 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 17 | MediaFormat format = new MediaFormat(); 18 | // TODO: this causes a crash in MediaCodec.configure 19 | //format.setString(MediaFormat.KEY_FRAME_RATE, null); 20 | format.setInteger(MediaFormat.KEY_SAMPLE_RATE, sampleRate); 21 | format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); 22 | if (type == Type.AAC) { 23 | format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm"); 24 | format.setInteger(MediaFormat.KEY_AAC_PROFILE, 2); // TODO: or 39? 25 | format.setInteger(MediaFormat.KEY_BIT_RATE, 64000); 26 | } else if (type == Type.FLAC) { 27 | //format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_FLAC); // API=21 28 | format.setString(MediaFormat.KEY_MIME, "audio/flac"); 29 | format.setInteger(MediaFormat.KEY_BIT_RATE, 64000); 30 | //TODO: use another bit rate, does not seem to have effect always 31 | //format.setInteger(MediaFormat.KEY_BIT_RATE, 128000); 32 | } else { 33 | format.setString(MediaFormat.KEY_MIME, "audio/amr-wb"); 34 | format.setInteger(MediaFormat.KEY_BIT_RATE, 23050); 35 | } 36 | return format; 37 | } 38 | return null; 39 | } 40 | 41 | //final int kAACProfiles[] = { 42 | // 2 /* OMX_AUDIO_AACObjectLC */, 43 | // 5 /* OMX_AUDIO_AACObjectHE */, 44 | // 39 /* OMX_AUDIO_AACObjectELD */ 45 | //}; 46 | 47 | //if (kAACProfiles[k] == 5 && kSampleRates[i] < 22050) { 48 | // // Is this right? HE does not support sample rates < 22050Hz? 49 | // continue; 50 | //} 51 | // final int kSampleRates[] = {8000, 11025, 22050, 44100, 48000}; 52 | // final int kBitRates[] = {64000, 128000}; 53 | } -------------------------------------------------------------------------------- /libs/speechutils-master/src/ee/ioc/phon/android/speechutils/RawAudioRecorder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2015, Institute of Cybernetics at Tallinn University of Technology 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package ee.ioc.phon.android.speechutils; 18 | 19 | /** 20 | *

Records raw audio using SpeechRecord and stores it into a byte array as

21 | *
    22 | *
  • signed
  • 23 | *
  • 16-bit
  • 24 | *
  • native endian
  • 25 | *
  • mono
  • 26 | *
  • 16kHz (recommended, but a different sample rate can be specified in the constructor)
  • 27 | *
28 | *

29 | *

For example, the corresponding arecord settings are

30 | *

31 | *

32 |  * arecord --file-type raw --format=S16_LE --channels 1 --rate 16000
33 |  * arecord --file-type raw --format=S16_BE --channels 1 --rate 16000 (possibly)
34 |  * 
35 | *

36 | * TODO: maybe use: ByteArrayOutputStream 37 | * 38 | * @author Kaarel Kaljurand 39 | */ 40 | public class RawAudioRecorder extends AbstractAudioRecorder { 41 | 42 | /** 43 | *

Instantiates a new recorder and sets the state to INITIALIZING. 44 | * In case of errors, no exception is thrown, but the state is set to ERROR.

45 | *

46 | *

Android docs say: 44100Hz is currently the only rate that is guaranteed to work on all devices, 47 | * but other rates such as 22050, 16000, and 11025 may work on some devices.

48 | * 49 | * @param audioSource Identifier of the audio source (e.g. microphone) 50 | * @param sampleRate Sample rate (e.g. 16000) 51 | */ 52 | public RawAudioRecorder(int audioSource, int sampleRate) { 53 | super(audioSource, sampleRate); 54 | try { 55 | int bufferSize = getBufferSize(); 56 | int framePeriod = bufferSize / (2 * RESOLUTION_IN_BYTES * CHANNELS); 57 | createRecorder(audioSource, sampleRate, bufferSize); 58 | createBuffer(framePeriod); 59 | setState(State.READY); 60 | } catch (Exception e) { 61 | if (e.getMessage() == null) { 62 | handleError("Unknown error occurred while initializing recorder"); 63 | } else { 64 | handleError(e.getMessage()); 65 | } 66 | } 67 | } 68 | 69 | 70 | public RawAudioRecorder(int sampleRate) { 71 | this(DEFAULT_AUDIO_SOURCE, sampleRate); 72 | } 73 | 74 | 75 | public RawAudioRecorder() { 76 | this(DEFAULT_AUDIO_SOURCE, DEFAULT_SAMPLE_RATE); 77 | } 78 | 79 | public String getWsArgs() { 80 | return "?content-type=audio/x-raw,+layout=(string)interleaved,+rate=(int)" + getSampleRate() + ",+format=(string)S16LE,+channels=(int)1"; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /libs/speechutils-master/src/ee/ioc/phon/android/speechutils/SpeechRecord.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils; 2 | 3 | import android.media.AudioFormat; 4 | import android.media.AudioRecord; 5 | import android.media.MediaRecorder; 6 | import android.media.audiofx.AcousticEchoCanceler; 7 | import android.media.audiofx.AutomaticGainControl; 8 | import android.media.audiofx.NoiseSuppressor; 9 | import android.os.Build; 10 | 11 | /** 12 | * The following takes effect only on Jelly Bean and higher. 13 | * 14 | * @author Kaarel Kaljurand 15 | */ 16 | public class SpeechRecord extends AudioRecord { 17 | 18 | public SpeechRecord(int sampleRateInHz, int bufferSizeInBytes) 19 | throws IllegalArgumentException { 20 | 21 | this( 22 | MediaRecorder.AudioSource.VOICE_RECOGNITION, 23 | sampleRateInHz, 24 | AudioFormat.CHANNEL_IN_MONO, 25 | AudioFormat.ENCODING_PCM_16BIT, 26 | bufferSizeInBytes, 27 | false, 28 | false, 29 | false 30 | ); 31 | } 32 | 33 | 34 | public SpeechRecord(int sampleRateInHz, int bufferSizeInBytes, boolean noise, boolean gain, boolean echo) 35 | throws IllegalArgumentException { 36 | 37 | this( 38 | MediaRecorder.AudioSource.VOICE_RECOGNITION, 39 | sampleRateInHz, 40 | AudioFormat.CHANNEL_IN_MONO, 41 | AudioFormat.ENCODING_PCM_16BIT, 42 | bufferSizeInBytes, 43 | noise, 44 | gain, 45 | echo 46 | ); 47 | } 48 | 49 | 50 | // This is a copy of the AudioRecord constructor 51 | public SpeechRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes) 52 | throws IllegalArgumentException { 53 | 54 | this(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, false, false, false); 55 | } 56 | 57 | 58 | public SpeechRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, 59 | boolean noise, boolean gain, boolean echo) 60 | throws IllegalArgumentException { 61 | 62 | super(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes); 63 | 64 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 65 | Log.i("Trying to enhance audio because running on SDK " + Build.VERSION.SDK_INT); 66 | 67 | int audioSessionId = getAudioSessionId(); 68 | 69 | if (noise) { 70 | if (NoiseSuppressor.create(audioSessionId) == null) { 71 | Log.i("NoiseSuppressor: failed"); 72 | } else { 73 | Log.i("NoiseSuppressor: ON"); 74 | } 75 | } else { 76 | Log.i("NoiseSuppressor: OFF"); 77 | } 78 | 79 | if (gain) { 80 | if (AutomaticGainControl.create(audioSessionId) == null) { 81 | Log.i("AutomaticGainControl: failed"); 82 | } else { 83 | Log.i("AutomaticGainControl: ON"); 84 | } 85 | } else { 86 | Log.i("AutomaticGainControl: OFF"); 87 | } 88 | 89 | if (echo) { 90 | if (AcousticEchoCanceler.create(audioSessionId) == null) { 91 | Log.i("AcousticEchoCanceler: failed"); 92 | } else { 93 | Log.i("AcousticEchoCanceler: ON"); 94 | } 95 | } else { 96 | Log.i("AcousticEchoCanceler: OFF"); 97 | } 98 | } 99 | } 100 | 101 | 102 | public static boolean isNoiseSuppressorAvailable() { 103 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 104 | return NoiseSuppressor.isAvailable(); 105 | } 106 | return false; 107 | } 108 | } -------------------------------------------------------------------------------- /libs/speechutils-master/src/ee/ioc/phon/android/speechutils/TtsLocaleMapper.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Locale; 8 | import java.util.Map; 9 | 10 | public class TtsLocaleMapper { 11 | 12 | private static final List SIMILAR_LOCALES_ET; 13 | 14 | static { 15 | List aListEt = new ArrayList(); 16 | aListEt.add(new Locale("fi-FI")); 17 | aListEt.add(new Locale("es-ES")); 18 | SIMILAR_LOCALES_ET = Collections.unmodifiableList(aListEt); 19 | } 20 | 21 | private static final Map> SIMILAR_LOCALES; 22 | 23 | static { 24 | Map> aMap = new HashMap>(); 25 | aMap.put(new Locale("et-EE"), SIMILAR_LOCALES_ET); 26 | SIMILAR_LOCALES = Collections.unmodifiableMap(aMap); 27 | } 28 | 29 | public static List getSimilarLocales(Locale locale) { 30 | return SIMILAR_LOCALES.get(locale); 31 | } 32 | } -------------------------------------------------------------------------------- /libs/speechutils-master/src/ee/ioc/phon/android/speechutils/utils/PreferenceUtils.java: -------------------------------------------------------------------------------- 1 | package ee.ioc.phon.android.speechutils.utils; 2 | 3 | import android.content.SharedPreferences; 4 | import android.content.res.Resources; 5 | 6 | import java.util.Arrays; 7 | import java.util.Collections; 8 | import java.util.HashSet; 9 | import java.util.List; 10 | import java.util.Set; 11 | import java.util.UUID; 12 | 13 | public class PreferenceUtils { 14 | 15 | public static String getPrefString(SharedPreferences prefs, Resources res, int key, int defaultValue) { 16 | return prefs.getString(res.getString(key), res.getString(defaultValue)); 17 | } 18 | 19 | public static String getPrefString(SharedPreferences prefs, Resources res, int key) { 20 | return prefs.getString(res.getString(key), null); 21 | } 22 | 23 | public static Set getPrefStringSet(SharedPreferences prefs, Resources res, int key) { 24 | return prefs.getStringSet(res.getString(key), Collections.emptySet()); 25 | } 26 | 27 | public static Set getPrefStringSet(SharedPreferences prefs, Resources res, int key, int defaultValue) { 28 | return prefs.getStringSet(res.getString(key), getStringSetFromStringArray(res, defaultValue)); 29 | } 30 | 31 | public static boolean getPrefBoolean(SharedPreferences prefs, Resources res, int key, int defaultValue) { 32 | return prefs.getBoolean(res.getString(key), res.getBoolean(defaultValue)); 33 | } 34 | 35 | public static int getPrefInt(SharedPreferences prefs, Resources res, int key, int defaultValue) { 36 | return Integer.parseInt(getPrefString(prefs, res, key, defaultValue)); 37 | } 38 | 39 | public static String getUniqueId(SharedPreferences settings) { 40 | String id = settings.getString("id", null); 41 | if (id == null) { 42 | id = UUID.randomUUID().toString(); 43 | SharedPreferences.Editor editor = settings.edit(); 44 | editor.putString("id", id); 45 | editor.apply(); 46 | } 47 | return id; 48 | } 49 | 50 | public static Set getStringSetFromStringArray(Resources res, int key) { 51 | return new HashSet<>(Arrays.asList(res.getStringArray(key))); 52 | } 53 | 54 | public static List getStringListFromStringArray(Resources res, int key) { 55 | return Arrays.asList(res.getStringArray(key)); 56 | } 57 | 58 | public static void putPrefString(SharedPreferences prefs, Resources res, int key, String value) { 59 | SharedPreferences.Editor editor = prefs.edit(); 60 | editor.putString(res.getString(key), value); 61 | editor.apply(); 62 | } 63 | 64 | public static void putPrefStringSet(SharedPreferences prefs, Resources res, int key, Set value) { 65 | SharedPreferences.Editor editor = prefs.edit(); 66 | editor.putStringSet(res.getString(key), value); 67 | editor.apply(); 68 | } 69 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', 2 | ':libs:AlexaAndroid', 3 | ':libs:RecorderLevelView', 4 | ':libs:speechutils-master' 5 | --------------------------------------------------------------------------------