This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository say-my-texts. See http://git.chorem.org/say-my-texts.git commit b0d04c9b2ed0f82a32fa5da4d66037e8f4ded26a Author: Kevin Morin <morin@codelutin.com> Date: Sat Jun 21 13:18:34 2014 +0200 fixes #1038 --- res/values-fr/strings.xml | 3 + res/values/strings.xml | 3 + .../android/saymytexts/SayMyTextService.java | 91 +++++++++++--------- .../chorem/android/saymytexts/SayMyTextsUtils.java | 99 ++++++++++++++++++++++ 4 files changed, 157 insertions(+), 39 deletions(-) diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 2aaa3d3..ed45a9d 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -31,6 +31,9 @@ <string name="texttospeech_init_error">Erreur lors de l\'initialisation de la synthèse vocale.</string> <string name="texttospeech_not_installed">L\'application a besoin d\'un moteur de synthèse vocale. Veuillez en installer un. </string> + <string name="konami_code">haut haut bas bas gauche droite gauche droite b a</string> + <string name="fs_song_url">https://www.gnu.org/music/free-software-song.fr.html</string> + <!--ACRA--> <string name="crash_toast_text">Erreur innatendue, préparation du rapport de bug</string> <string name="crash_dialog_title">Say My Texts a planté</string> diff --git a/res/values/strings.xml b/res/values/strings.xml index c2b6d84..35898d2 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -31,6 +31,9 @@ <string name="texttospeech_init_error">Error during text to speech initialization.</string> <string name="texttospeech_not_installed">The application needs a text to speech engine to work. Please install one.</string> + <string name="konami_code">up up down down left right left right b a</string> + <string name="fs_song_url">https://www.gnu.org/music/free-software-song.html</string> + <!--ACRA--> <string name="crash_toast_text">Ooooops ! the application crashed, but a report has been sent to my developer to help fix the issue !</string> <string name="crash_dialog_title">say My Texts has crashed</string> diff --git a/src/org/chorem/android/saymytexts/SayMyTextService.java b/src/org/chorem/android/saymytexts/SayMyTextService.java index a190072..3f1ed86 100644 --- a/src/org/chorem/android/saymytexts/SayMyTextService.java +++ b/src/org/chorem/android/saymytexts/SayMyTextService.java @@ -32,6 +32,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.media.AudioManager; +import android.net.Uri; import android.os.IBinder; import android.preference.PreferenceManager; import android.speech.tts.TextToSpeech; @@ -387,54 +388,66 @@ public class SayMyTextService extends Service implements TextToSpeech.OnInitList // disable the reading of the nexts sms while reading the current one setCanSpeak(false); - textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() { - @Override - public void onStart(String utteranceId) { - } + String message = sms.getMessage(); + if (message.trim().toLowerCase().equals(getString(R.string.konami_code))) { - @Override - public void onError(String utteranceId) { - Log.e(TAG, "Error speaking: " + utteranceId); - } + SayMyTextsUtils.playFSSong(); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(getString(R.string.fs_song_url))); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + setCanSpeak(true); - @Override - public void onDone(String utteranceId) { - Log.d(TAG, "done"); - setCanSpeak(true); - } - }); + } else { + textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() { + @Override + public void onStart(String utteranceId) { + } - HashMap<String, String> params = new HashMap<>(); - params.put(TextToSpeech.Engine.KEY_PARAM_STREAM, String.valueOf(AudioManager.STREAM_VOICE_CALL)); + @Override + public void onError(String utteranceId) { + Log.e(TAG, "Error speaking: " + utteranceId); + } - if (heisendroidModeEnabled) { - textToSpeech.setLanguage(Locale.US); - textToSpeech.setSpeechRate(0.3f); - textToSpeech.setPitch(0.1f); - textToSpeech.speak("Say my text.", TextToSpeech.QUEUE_ADD, params); - } + @Override + public void onDone(String utteranceId) { + Log.d(TAG, "done"); + setCanSpeak(true); + } + }); - if (!interactionEnabled && !heisendroidModeEnabled) { - params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, OTHER_UTTERANCE_ID); - } - textToSpeech.setLanguage(Locale.getDefault()); - textToSpeech.setSpeechRate(1f); - textToSpeech.setPitch(1f); - String text = getString(R.string.sms_received, sms.getSenderName(), sms.getMessage()); - textToSpeech.speak(text, TextToSpeech.QUEUE_ADD, params); + HashMap<String, String> params = new HashMap<>(); + params.put(TextToSpeech.Engine.KEY_PARAM_STREAM, String.valueOf(AudioManager.STREAM_VOICE_CALL)); - if (heisendroidModeEnabled) { - if (interactionEnabled) { + if (heisendroidModeEnabled) { + textToSpeech.setLanguage(Locale.US); + textToSpeech.setSpeechRate(0.3f); + textToSpeech.setPitch(0.1f); + textToSpeech.speak("Say my text.", TextToSpeech.QUEUE_ADD, params); + } + + if (!interactionEnabled && !heisendroidModeEnabled) { params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, OTHER_UTTERANCE_ID); } - textToSpeech.setLanguage(Locale.US); - textToSpeech.setSpeechRate(0.3f); - textToSpeech.setPitch(0.1f); - textToSpeech.speak("You're goddamn right.", TextToSpeech.QUEUE_ADD, params); - } + textToSpeech.setLanguage(Locale.getDefault()); + textToSpeech.setSpeechRate(1f); + textToSpeech.setPitch(1f); + String text = getString(R.string.sms_received, sms.getSenderName(), message); + textToSpeech.speak(text, TextToSpeech.QUEUE_ADD, params); - if (interactionEnabled) { - askForActionAfterReading(sms, btConnected, 1); + if (heisendroidModeEnabled) { + if (interactionEnabled) { + params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, OTHER_UTTERANCE_ID); + } + textToSpeech.setLanguage(Locale.US); + textToSpeech.setSpeechRate(0.3f); + textToSpeech.setPitch(0.1f); + textToSpeech.speak("You're goddamn right.", TextToSpeech.QUEUE_ADD, params); + } + + if (interactionEnabled) { + askForActionAfterReading(sms, btConnected, 1); + } } } diff --git a/src/org/chorem/android/saymytexts/SayMyTextsUtils.java b/src/org/chorem/android/saymytexts/SayMyTextsUtils.java index fa9aeb3..c7c3c27 100644 --- a/src/org/chorem/android/saymytexts/SayMyTextsUtils.java +++ b/src/org/chorem/android/saymytexts/SayMyTextsUtils.java @@ -28,8 +28,12 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.media.AudioFormat; +import android.media.AudioManager; +import android.media.AudioTrack; import android.speech.RecognizerIntent; +import java.util.ArrayList; import java.util.List; /** @@ -45,4 +49,99 @@ public class SayMyTextsUtils { return activities.size() > 0; } + + public static final double QUAVER_DURATION = 0.25; + public static final double BLACK_DURATION = 0.5; + public static final double POINTED_BLACK_DURATION = 0.75; + + public static final int SAMPLE_RATE = 8000; + + public static final double G_FREQUENCY = 396; // hz + public static final double A_FREQUENCY = 440; // hz + public static final double B_FREQUENCY = 495; // hz + public static final double C_FREQUENCY = 528; // hz + public static final double D_FREQUENCY = 594; // hz + + private static final List<Byte> FS_SONG_NOTES = new ArrayList<>(); + + public static void playFSSong() { + if (FS_SONG_NOTES.isEmpty()) { + initFSSong(); + } + playSound(); + } + + private static void initFSSong() { + List<Double> tones = new ArrayList<>(); + + genTone(tones, D_FREQUENCY, BLACK_DURATION); + genTone(tones, C_FREQUENCY, QUAVER_DURATION); + genTone(tones, B_FREQUENCY, BLACK_DURATION); + genTone(tones, A_FREQUENCY, BLACK_DURATION); + genTone(tones, B_FREQUENCY, BLACK_DURATION); + genTone(tones, C_FREQUENCY, QUAVER_DURATION); + genTone(tones, B_FREQUENCY, BLACK_DURATION); + genTone(tones, A_FREQUENCY, BLACK_DURATION); + genTone(tones, G_FREQUENCY, BLACK_DURATION); + genTone(tones, G_FREQUENCY, POINTED_BLACK_DURATION); + genTone(tones, A_FREQUENCY, POINTED_BLACK_DURATION); + genTone(tones, B_FREQUENCY, QUAVER_DURATION); + genTone(tones, C_FREQUENCY, POINTED_BLACK_DURATION); + genTone(tones, B_FREQUENCY, BLACK_DURATION); + genTone(tones, B_FREQUENCY, QUAVER_DURATION); + genTone(tones, D_FREQUENCY, BLACK_DURATION); + + finalizeSample(tones); + } + + private static void genTone(List<Double> tones, double freqOfTone, double duration){ + // fill out the array + int numSample = (int) (duration * SAMPLE_RATE); + for (int i = 0; i < numSample; ++i) { + tones.add(Math.sin(2 * Math.PI * (tones.size()) / (SAMPLE_RATE / freqOfTone))); + } + + } + + private static void finalizeSample(List<Double> tones) { + // convert to 16 bit pcm sound array + // assumes the sample buffer is normalised. + int idx = 0; + for (final double dVal : tones) { + // scale to maximum amplitude + final short val = (short) ((dVal * 32767)); + // in 16 bit wav PCM, first byte is the low order byte + FS_SONG_NOTES.add((byte) (val & 0x00ff)); + FS_SONG_NOTES.add((byte) ((val & 0xff00) >>> 8)); + + } + } + + private static void playSound(){ + int size = FS_SONG_NOTES.size(); + final AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, + SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO, + AudioFormat.ENCODING_PCM_16BIT, size, + AudioTrack.MODE_STATIC); + + byte[] bytes = new byte[size]; + for (int i = 0 ; i < size ; i++) { + bytes[i] = FS_SONG_NOTES.get(i); + } + audioTrack.write(bytes, 0, size); + audioTrack.setPlaybackPositionUpdateListener(new AudioTrack.OnPlaybackPositionUpdateListener() { + @Override + public void onMarkerReached(AudioTrack track) { + } + + @Override + public void onPeriodicNotification(AudioTrack track) { + if (track.getPlayState() == AudioTrack.PLAYSTATE_STOPPED) { + audioTrack.release(); + } + } + }); + audioTrack.play(); + } + } -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.