diff --git a/api/build.gradle b/api/build.gradle index 349835d8e..434f9b7d3 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -37,7 +37,8 @@ dependencies { compile group: 'com.android.support', name: 'support-v4', version: '19.1.+' - compile group: 'org.slf4j', name: 'slf4j-android', version: '1.7.7', transitive: false compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.7' + compile group: 'com.github.tony19', name: 'logback-android-core', version: '1.1.1-2' + compile group: 'com.github.tony19', name: 'logback-android-classic', version: '1.1.1-2' compile group: 'joda-time', name: 'joda-time', version: '2.3', transitive: false } diff --git a/astrid/assets/logback.xml b/astrid/assets/logback.xml new file mode 100644 index 000000000..2446f9fa8 --- /dev/null +++ b/astrid/assets/logback.xml @@ -0,0 +1,18 @@ + + + + + %logger{0} + + + [ %thread ] %msg%n + + + + + + + + diff --git a/astrid/assets/subtasks_horizontal.png b/astrid/assets/subtasks_horizontal.png deleted file mode 100644 index cdb7666b5..000000000 Binary files a/astrid/assets/subtasks_horizontal.png and /dev/null differ diff --git a/astrid/assets/subtasks_vertical.png b/astrid/assets/subtasks_vertical.png deleted file mode 100644 index a2df9f709..000000000 Binary files a/astrid/assets/subtasks_vertical.png and /dev/null differ diff --git a/astrid/src/main/java/com/todoroo/astrid/activity/EditPreferences.java b/astrid/src/main/java/com/todoroo/astrid/activity/EditPreferences.java index f004e10e1..c8f8bd250 100644 --- a/astrid/src/main/java/com/todoroo/astrid/activity/EditPreferences.java +++ b/astrid/src/main/java/com/todoroo/astrid/activity/EditPreferences.java @@ -19,6 +19,7 @@ import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceGroup; import android.preference.PreferenceManager; import android.preference.PreferenceScreen; +import android.speech.tts.TextToSpeech; import android.text.TextUtils; import com.todoroo.andlib.service.ContextManager; @@ -39,9 +40,11 @@ import com.todoroo.astrid.utility.Constants; import com.todoroo.astrid.utility.Flags; import com.todoroo.astrid.utility.TodorooPreferenceActivity; import com.todoroo.astrid.voice.VoiceInputAssistant; -import com.todoroo.astrid.voice.VoiceOutputService; +import com.todoroo.astrid.voice.VoiceOutputAssistant; import com.todoroo.astrid.voice.VoiceRecognizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.tasks.R; import org.tasks.preferences.Preferences; import org.tasks.widget.WidgetHelper; @@ -62,8 +65,10 @@ import javax.inject.Inject; */ public class EditPreferences extends TodorooPreferenceActivity { + private static final Logger log = LoggerFactory.getLogger(EditPreferences.class); private static final int REQUEST_CODE_SYNC = 0; private static final int REQUEST_CODE_FILES_DIR = 2; + private static final int REQUEST_CODE_TTS_CHECK = 2534; public static final int RESULT_CODE_THEME_CHANGED = 1; public static final int RESULT_CODE_PERFORMANCE_PREF_CHANGED = 3; @@ -74,6 +79,7 @@ public class EditPreferences extends TodorooPreferenceActivity { @Inject TaskService taskService; @Inject Preferences preferences; @Inject CalendarAlarmScheduler calendarAlarmScheduler; + @Inject VoiceOutputAssistant voiceOutputAssistant; private VoiceInputAssistant voiceInputAssistant; @@ -359,6 +365,13 @@ public class EditPreferences extends TodorooPreferenceActivity { return false; } + @Override + protected void onDestroy() { + super.onDestroy(); + + voiceOutputAssistant.shutdown(); + } + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_SYNC && resultCode == SyncProviderPreferences.RESULT_CODE_SYNCHRONIZE) { @@ -373,7 +386,17 @@ public class EditPreferences extends TodorooPreferenceActivity { return; } try { - VoiceOutputService.getVoiceOutputInstance().handleActivityResult(requestCode, resultCode); + if (requestCode == REQUEST_CODE_TTS_CHECK) { + if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) { + // success, create the TTS instance + voiceOutputAssistant.initTTS(); + } else { + // missing data, install it + Intent installIntent = new Intent(); + installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA); + startActivity(installIntent); + } + } } catch (VerifyError e) { // unavailable } @@ -427,14 +450,17 @@ public class EditPreferences extends TodorooPreferenceActivity { }); } - private void onVoiceReminderStatusChanged(final Preference preference, boolean newValue) { + private void onVoiceReminderStatusChanged(final Preference preference, boolean enabled) { try { - VoiceOutputService.getVoiceOutputInstance(); - if(newValue) { - VoiceOutputService.getVoiceOutputInstance().checkIsTTSInstalled(); + if(enabled && !voiceOutputAssistant.isTTSInitialized()) { + Intent checkIntent = new Intent(); + checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA); + startActivityForResult(checkIntent, REQUEST_CODE_TTS_CHECK); + } else if (!enabled && voiceOutputAssistant.isTTSInitialized()) { + voiceOutputAssistant.shutdown(); } } catch (VerifyError e) { - // doesn't work :( + log.error(e.getMessage(), e); preference.setEnabled(false); preferences.setBoolean(preference.getKey(), false); } diff --git a/astrid/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.java b/astrid/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.java index 3bbb81451..5c52b4de8 100755 --- a/astrid/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.java +++ b/astrid/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.java @@ -41,6 +41,7 @@ import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.Toast; +import com.todoroo.andlib.service.ContextManager; import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DialogUtilities; @@ -285,8 +286,8 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener { private void instantiateEditNotes() { if (showEditComments) { long idParam = getActivity().getIntent().getLongExtra(TOKEN_ID, -1L); - editNotes = new EditNoteActivity(metadataService, userActivityDao, taskService, this, getView(), - idParam); + editNotes = new EditNoteActivity(preferences, metadataService, userActivityDao, + taskService, this, getView(), idParam); editNotes.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); @@ -541,7 +542,11 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener { voiceNoteAssistant = new VoiceInputAssistant(voiceAddNoteButton, REQUEST_VOICE_RECOG); voiceNoteAssistant.setAppend(); voiceNoteAssistant.setLanguageModel(RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); - voiceNoteAssistant.configureMicrophoneButton(TaskEditFragment.this, prompt); + if (preferences.getBoolean(R.string.p_voiceInputEnabled, true) && VoiceRecognizer.voiceInputAvailable(ContextManager.getContext())) { + voiceNoteAssistant.configureMicrophoneButton(TaskEditFragment.this, prompt); + } else { + voiceNoteAssistant.hideVoiceButton(); + } } loadMoreContainer(); } diff --git a/astrid/src/main/java/com/todoroo/astrid/notes/EditNoteActivity.java b/astrid/src/main/java/com/todoroo/astrid/notes/EditNoteActivity.java index c71d4fb30..c6fe68e86 100644 --- a/astrid/src/main/java/com/todoroo/astrid/notes/EditNoteActivity.java +++ b/astrid/src/main/java/com/todoroo/astrid/notes/EditNoteActivity.java @@ -35,7 +35,6 @@ import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.service.ContextManager; import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.utility.DateUtilities; -import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.actfm.ActFmCameraModule; import com.todoroo.astrid.actfm.ActFmCameraModule.CameraResultCallback; import com.todoroo.astrid.actfm.ActFmCameraModule.ClearImageCallback; @@ -56,6 +55,7 @@ import com.todoroo.astrid.timers.TimerActionControlSet.TimerActionListener; import org.json.JSONObject; import org.tasks.R; +import org.tasks.preferences.Preferences; import java.util.ArrayList; import java.util.Collections; @@ -69,6 +69,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene private Task task; + private final Preferences preferences; private final MetadataService metadataService; private final UserActivityDao userActivityDao; private final TaskService taskService; @@ -98,6 +99,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene } public EditNoteActivity( + Preferences preferences, MetadataService metadataService, UserActivityDao userActivityDao, TaskService taskService, @@ -105,7 +107,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene View parent, long t) { super(fragment.getActivity()); - + this.preferences = preferences; this.metadataService = metadataService; this.userActivityDao = userActivityDao; this.taskService = taskService; @@ -159,7 +161,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene commentButton = commentsBar.findViewById(R.id.commentButton); commentField = (EditText) commentsBar.findViewById(R.id.commentField); - final boolean showTimerShortcut = Preferences.getBoolean(R.string.p_show_timer_shortcut, false); + final boolean showTimerShortcut = preferences.getBoolean(R.string.p_show_timer_shortcut, false); if (showTimerShortcut) { commentField.setOnFocusChangeListener(new OnFocusChangeListener() { diff --git a/astrid/src/main/java/com/todoroo/astrid/reminders/NotificationFragment.java b/astrid/src/main/java/com/todoroo/astrid/reminders/NotificationFragment.java index 59444bf59..3d7528695 100644 --- a/astrid/src/main/java/com/todoroo/astrid/reminders/NotificationFragment.java +++ b/astrid/src/main/java/com/todoroo/astrid/reminders/NotificationFragment.java @@ -12,6 +12,7 @@ import com.todoroo.astrid.activity.TaskListFragment; import com.todoroo.astrid.service.TaskService; import org.tasks.R; +import org.tasks.preferences.Preferences; import javax.inject.Inject; @@ -32,6 +33,7 @@ public class NotificationFragment extends TaskListFragment { // --- implementation @Inject TaskService taskService; + @Inject Preferences preferences; @Override protected void initializeData() { @@ -48,6 +50,6 @@ public class NotificationFragment extends TaskListFragment { String title = extras.getString(Notifications.EXTRAS_TEXT); long taskId = extras.getLong(TOKEN_ID); - new ReminderDialog(taskService, (AstridActivity) getActivity(), taskId, title).show(); + new ReminderDialog(preferences, taskService, (AstridActivity) getActivity(), taskId, title).show(); } } diff --git a/astrid/src/main/java/com/todoroo/astrid/reminders/Notifications.java b/astrid/src/main/java/com/todoroo/astrid/reminders/Notifications.java index 527b3b84f..f2e4b871c 100644 --- a/astrid/src/main/java/com/todoroo/astrid/reminders/Notifications.java +++ b/astrid/src/main/java/com/todoroo/astrid/reminders/Notifications.java @@ -23,7 +23,6 @@ import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao.TaskCriteria; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.utility.Constants; -import com.todoroo.astrid.voice.VoiceOutputService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -91,12 +90,6 @@ public class Notifications extends InjectingBroadcastReceiver { if (!showTaskNotification(id, type, reminder)) { notificationManager.cancel((int) id); } - - try { - VoiceOutputService.getVoiceOutputInstance().onDestroy(); - } catch (VerifyError e) { - // unavailable - } } /** diff --git a/astrid/src/main/java/com/todoroo/astrid/reminders/ReminderDialog.java b/astrid/src/main/java/com/todoroo/astrid/reminders/ReminderDialog.java index 01b43ae11..24589ddcc 100644 --- a/astrid/src/main/java/com/todoroo/astrid/reminders/ReminderDialog.java +++ b/astrid/src/main/java/com/todoroo/astrid/reminders/ReminderDialog.java @@ -18,13 +18,13 @@ import android.widget.TimePicker; import android.widget.Toast; import com.todoroo.andlib.utility.DateUtilities; -import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.activity.AstridActivity; import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.service.TaskService; import org.tasks.R; +import org.tasks.preferences.Preferences; import java.util.Date; @@ -38,9 +38,12 @@ import static org.tasks.date.DateTimeUtils.newDate; */ public class ReminderDialog extends Dialog { - public ReminderDialog(final TaskService taskService, final AstridActivity activity, final long taskId, + private final Preferences preferences; + + public ReminderDialog(Preferences preferences, final TaskService taskService, final AstridActivity activity, final long taskId, String title) { super(activity, R.style.ReminderDialog); + this.preferences = preferences; final SnoozeCallback dialogSnooze = new SnoozeCallback() { @Override @@ -121,7 +124,7 @@ public class ReminderDialog extends Dialog { * Snooze and re-trigger this alarm */ private void snooze(Activity activity, OnTimeSetListener onTimeSet, SnoozeCallback snoozeCallback) { - if(Preferences.getBoolean(R.string.p_rmd_snooze_dialog, false)) { + if(preferences.getBoolean(R.string.p_rmd_snooze_dialog, false)) { Date now = newDate(); now.setHours(now.getHours() + 1); int hour = now.getHours(); diff --git a/astrid/src/main/java/com/todoroo/astrid/reminders/ShowNotificationReceiver.java b/astrid/src/main/java/com/todoroo/astrid/reminders/ShowNotificationReceiver.java index 74da4f4d7..2dbea155e 100644 --- a/astrid/src/main/java/com/todoroo/astrid/reminders/ShowNotificationReceiver.java +++ b/astrid/src/main/java/com/todoroo/astrid/reminders/ShowNotificationReceiver.java @@ -12,7 +12,7 @@ import android.telephony.TelephonyManager; import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.utility.Flags; -import com.todoroo.astrid.voice.VoiceOutputService; +import com.todoroo.astrid.voice.VoiceOutputAssistant; import org.joda.time.DateTime; import org.tasks.R; @@ -40,6 +40,7 @@ public class ShowNotificationReceiver extends InjectingBroadcastReceiver { @Inject NotificationManager notificationManager; @Inject Preferences preferences; + @Inject VoiceOutputAssistant voiceOutputAssistant; @Override public void onReceive(Context context, Intent intent) { @@ -194,7 +195,8 @@ public class ShowNotificationReceiver extends InjectingBroadcastReceiver { } singleThreadVoicePool.submit(new NotificationRunnable(ringTimes, notificationId, notification, voiceReminder, - maxOutVolumeForMultipleRingReminders, audioManager, previousAlarmVolume, text, notificationManager)); + maxOutVolumeForMultipleRingReminders, audioManager, previousAlarmVolume, text, + notificationManager, voiceOutputAssistant)); } private static class NotificationRunnable implements Runnable { @@ -207,11 +209,13 @@ public class ShowNotificationReceiver extends InjectingBroadcastReceiver { private final int previousAlarmVolume; private final String text; private NotificationManager notificationManager; + private final VoiceOutputAssistant voiceOutputAssistant; public NotificationRunnable(int ringTimes, int notificationId, Notification notification, boolean voiceReminder, boolean maxOutVolume, AudioManager audioManager, int previousAlarmVolume, - String text, NotificationManager notificationManager) { + String text, NotificationManager notificationManager, + VoiceOutputAssistant voiceOutputAssistant) { this.ringTimes = ringTimes; this.notificationId = notificationId; this.notification = notification; @@ -221,6 +225,7 @@ public class ShowNotificationReceiver extends InjectingBroadcastReceiver { this.previousAlarmVolume = previousAlarmVolume; this.text = text; this.notificationManager = notificationManager; + this.voiceOutputAssistant = voiceOutputAssistant; } @Override @@ -230,7 +235,7 @@ public class ShowNotificationReceiver extends InjectingBroadcastReceiver { AndroidUtilities.sleepDeep(500); } Flags.set(Flags.REFRESH); // Forces a reload when app launches - if ((voiceReminder || maxOutVolumeForMultipleRingReminders)) { + if (voiceReminder || maxOutVolumeForMultipleRingReminders) { AndroidUtilities.sleepDeep(2000); for (int i = 0; i < 50; i++) { AndroidUtilities.sleepDeep(500); @@ -244,7 +249,7 @@ public class ShowNotificationReceiver extends InjectingBroadcastReceiver { audioManager.setStreamVolume(AudioManager.STREAM_ALARM, previousAlarmVolume, 0); } if (voiceReminder) { - VoiceOutputService.getVoiceOutputInstance().queueSpeak(text); + voiceOutputAssistant.speak(text); } } catch (VerifyError e) { // unavailable diff --git a/astrid/src/main/java/com/todoroo/astrid/ui/QuickAddBar.java b/astrid/src/main/java/com/todoroo/astrid/ui/QuickAddBar.java index 108390d87..7bee45ac5 100644 --- a/astrid/src/main/java/com/todoroo/astrid/ui/QuickAddBar.java +++ b/astrid/src/main/java/com/todoroo/astrid/ui/QuickAddBar.java @@ -385,7 +385,7 @@ public class QuickAddBar extends LinearLayout { return voiceRecognizer; } public void startVoiceRecognition() { - voiceRecognizer.startVoiceRecognition(activity, fragment); + voiceRecognizer.startVoiceRecognition(preferences, activity, fragment); } public void setupRecognizerApi() { diff --git a/astrid/src/main/java/com/todoroo/astrid/voice/Api6VoiceOutputAssistant.java b/astrid/src/main/java/com/todoroo/astrid/voice/Api6VoiceOutputAssistant.java deleted file mode 100644 index 8840204ff..000000000 --- a/astrid/src/main/java/com/todoroo/astrid/voice/Api6VoiceOutputAssistant.java +++ /dev/null @@ -1,139 +0,0 @@ -/** - * - */ -package com.todoroo.astrid.voice; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.media.AudioManager; -import android.speech.tts.TextToSpeech; -import android.speech.tts.TextToSpeech.OnInitListener; -import android.util.Log; - -import com.todoroo.andlib.service.ContextManager; -import com.todoroo.astrid.voice.VoiceOutputService.VoiceOutputAssistant; - -import java.util.HashMap; -import java.util.Locale; - -/** - * @author Arne Jans - * - */ -public class Api6VoiceOutputAssistant implements OnInitListener, VoiceOutputAssistant { - - private static final int MY_DATA_CHECK_CODE = 2534; - private static final String TAG = "Astrid.VoiceOutputAssistant"; - private final Context context; - private TextToSpeech mTts; - private boolean isTTSInitialized; - private boolean retryLastSpeak; - private String lastTextToSpeak; - private static final HashMap ttsParams = new HashMap<>(); - - static { - ttsParams.put(TextToSpeech.Engine.KEY_PARAM_STREAM, - String.valueOf(AudioManager.STREAM_NOTIFICATION)); - } - - Api6VoiceOutputAssistant() { - this.context = ContextManager.getContext().getApplicationContext(); - } - - @Override - public void checkIsTTSInstalled() { - if (!isTTSInitialized && context instanceof Activity) { - Intent checkIntent = new Intent(); - checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA); - ((Activity) context).startActivityForResult(checkIntent, - MY_DATA_CHECK_CODE); - } - } - - @Override - public void handleActivityResult(int requestCode, int resultCode) { - if (requestCode == MY_DATA_CHECK_CODE) { - if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) { - // success, create the TTS instance - initTTS(); - } else { - // missing data, install it - Intent installIntent = new Intent(); - installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA); - context.startActivity(installIntent); - } - } - } - - private void initTTS() { - mTts = new TextToSpeech(context, this); - } - - @Override - public void queueSpeak(String textToSpeak) { - if (mTts != null && isTTSInitialized) { - mTts.speak(textToSpeak, TextToSpeech.QUEUE_ADD, ttsParams); - while (mTts.isSpeaking()) { - try { - Thread.sleep(50); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } else { - retryLastSpeak = true; - this.lastTextToSpeak = textToSpeak; - initTTS(); - } - } - - @Override - public void onInit(int status) { - // status can be either TextToSpeech.SUCCESS or TextToSpeech.ERROR. - if (status == TextToSpeech.SUCCESS && mTts != null) { - // Set preferred language to US english. - // Note that a language may not be available, and the result will indicate this. - int result = mTts.setLanguage(Locale.getDefault()); - // Try this someday for some interesting results. - // int result mTts.setLanguage(Locale.FRANCE); - if (result == TextToSpeech.LANG_MISSING_DATA || - result == TextToSpeech.LANG_NOT_SUPPORTED) { - // Language data is missing or the language is not supported. - Log.e(TAG, "Language is not available."); - } else { - // Check the documentation for other possible result codes. - // For example, the language may be available for the locale, - // but not for the specified country and variant. - - mTts.speak("", 0, null); - - // The TTS engine has been successfully initialized. - isTTSInitialized = true; - // if this request came from queueSpeak, then speak it and reset the memento - if (retryLastSpeak && this.lastTextToSpeak != null) { - this.queueSpeak(this.lastTextToSpeak); - retryLastSpeak = false; - lastTextToSpeak = null; - } - } - } else { - // Initialization failed. - Log.e(TAG, "Could not initialize TextToSpeech."); - } - } - - /** - * Has to be called in onDestroy of the activity that uses this instance of VoiceOutputAssistant. - */ - @Override - public void onDestroy() { - if (mTts != null && isTTSInitialized) { - mTts.shutdown(); - mTts = null; - isTTSInitialized = false; - } - } - -} diff --git a/astrid/src/main/java/com/todoroo/astrid/voice/VoiceInputAssistant.java b/astrid/src/main/java/com/todoroo/astrid/voice/VoiceInputAssistant.java index befe470e0..8a942d59e 100644 --- a/astrid/src/main/java/com/todoroo/astrid/voice/VoiceInputAssistant.java +++ b/astrid/src/main/java/com/todoroo/astrid/voice/VoiceInputAssistant.java @@ -20,7 +20,6 @@ import android.widget.ImageButton; import com.todoroo.andlib.service.ContextManager; import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.DialogUtilities; -import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.utility.Constants; import junit.framework.Assert; @@ -175,17 +174,17 @@ public class VoiceInputAssistant { } public void configureMicrophoneButton(final Fragment fragment, final int prompt) { - if (Preferences.getBoolean(R.string.p_voiceInputEnabled, true) && VoiceRecognizer.voiceInputAvailable(ContextManager.getContext())) { - voiceButton.setVisibility(View.VISIBLE); - voiceButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - startVoiceRecognitionActivity(fragment, prompt); - } - }); - } else { - voiceButton.setVisibility(View.GONE); - } + voiceButton.setVisibility(View.VISIBLE); + voiceButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + startVoiceRecognitionActivity(fragment, prompt); + } + }); + } + + public void hideVoiceButton() { + voiceButton.setVisibility(View.GONE); } public void showVoiceInputMarketSearch(DialogInterface.OnClickListener onFail) { diff --git a/astrid/src/main/java/com/todoroo/astrid/voice/VoiceOutputAssistant.java b/astrid/src/main/java/com/todoroo/astrid/voice/VoiceOutputAssistant.java new file mode 100644 index 000000000..7fe060885 --- /dev/null +++ b/astrid/src/main/java/com/todoroo/astrid/voice/VoiceOutputAssistant.java @@ -0,0 +1,118 @@ +/** + * + */ +package com.todoroo.astrid.voice; + +import android.content.Context; +import android.media.AudioManager; +import android.speech.tts.TextToSpeech; +import android.speech.tts.TextToSpeech.OnInitListener; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.tasks.injection.ForApplication; + +import java.util.HashMap; +import java.util.Locale; +import java.util.UUID; + +import javax.inject.Inject; + +/** + * @author Arne Jans + * + */ +public class VoiceOutputAssistant implements OnInitListener { + + private static final Logger log = LoggerFactory.getLogger(VoiceOutputAssistant.class); + + private final Context context; + + private TextToSpeech mTts; + private boolean isTTSInitialized; + private String lastTextToSpeak; + + @Inject + public VoiceOutputAssistant(@ForApplication Context context) { + this.context = context; + } + + public boolean isTTSInitialized() { + return isTTSInitialized; + } + + public void initTTS() { + if(mTts == null) { + mTts = new TextToSpeech(context, this); + log.debug("Inititalized {}", mTts); + } + } + + public void speak(String textToSpeak) { + if (mTts != null && isTTSInitialized) { + final String id = UUID.randomUUID().toString(); + log.debug("{}: {} ({})", this, textToSpeak, id); + mTts.setOnUtteranceCompletedListener(new TextToSpeech.OnUtteranceCompletedListener() { + @Override + public void onUtteranceCompleted(String utteranceId) { + log.debug("{}: onUtteranceCompleted {}", utteranceId); + if(utteranceId.equals(id)) { + shutdown(); + } + } + }); + mTts.speak(textToSpeak, TextToSpeech.QUEUE_ADD, new HashMap() {{ + put(TextToSpeech.Engine.KEY_PARAM_STREAM, String.valueOf(AudioManager.STREAM_NOTIFICATION)); + put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, id); + }}); + } else { + lastTextToSpeak = textToSpeak; + initTTS(); + } + } + + public void onInit(int status) { + // status can be either TextToSpeech.SUCCESS or TextToSpeech.ERROR. + if (status == TextToSpeech.SUCCESS && mTts != null) { + // Set preferred language to US english. + // Note that a language may not be available, and the result will indicate this. + int result = mTts.setLanguage(Locale.getDefault()); + // Try this someday for some interesting results. + // int result mTts.setLanguage(Locale.FRANCE); + if (result == TextToSpeech.LANG_MISSING_DATA) { + log.error("Language data missing"); + } else if(result == TextToSpeech.LANG_NOT_SUPPORTED) { + log.error("Language not supported"); + } else { + // Check the documentation for other possible result codes. + // For example, the language may be available for the locale, + // but not for the specified country and variant. + + mTts.speak("", 0, null); + + // The TTS engine has been successfully initialized. + isTTSInitialized = true; + // if this request came from speak, then speak it and reset the memento + if (lastTextToSpeak != null) { + speak(lastTextToSpeak); + lastTextToSpeak = null; + } + } + } else { + log.error("Could not initialize TextToSpeech."); + } + } + + public void shutdown() { + if (mTts != null && isTTSInitialized) { + try { + mTts.shutdown(); + log.debug("Shutdown {}", mTts); + mTts = null; + isTTSInitialized = false; + } catch(VerifyError e) { + log.error(e.getMessage(), e); + } + } + } +} diff --git a/astrid/src/main/java/com/todoroo/astrid/voice/VoiceOutputService.java b/astrid/src/main/java/com/todoroo/astrid/voice/VoiceOutputService.java deleted file mode 100644 index 0578a6f67..000000000 --- a/astrid/src/main/java/com/todoroo/astrid/voice/VoiceOutputService.java +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright (c) 2012 Todoroo Inc - * - * See the file "LICENSE" for the full license governing this code. - */ -package com.todoroo.astrid.voice; - - -import com.todoroo.andlib.utility.AndroidUtilities; - - - - -/** - * All API versions-friendly voice input / output. - * @author Tim Su - * - */ -public class VoiceOutputService { - - private static final int MIN_TTS_VERSION = 6; - private static VoiceOutputAssistant outputAssistant; - - // --- voice output - - public interface VoiceOutputAssistant { - public void checkIsTTSInstalled(); - - public void handleActivityResult(int requestCode, int resultCode); - - public void queueSpeak(String textToSpeak); - - public void onDestroy(); - } - - public static class NullVoiceOutputAssistant implements VoiceOutputAssistant { - - @Override - public void checkIsTTSInstalled() { - // - } - - @Override - public void handleActivityResult(int requestCode, int resultCode) { - } - - @Override - public void queueSpeak(String textToSpeak) { - // - } - - @Override - public void onDestroy() { - // - } - - } - - public static VoiceOutputAssistant getVoiceOutputInstance() { - if(AndroidUtilities.getSdkVersion() >= MIN_TTS_VERSION) { - if (outputAssistant == null) { - outputAssistant = new Api6VoiceOutputAssistant(); - } - } else { - if(outputAssistant == null) { - outputAssistant = new NullVoiceOutputAssistant(); - } - } - - return outputAssistant; - } - -} diff --git a/astrid/src/main/java/com/todoroo/astrid/voice/VoiceRecognizer.java b/astrid/src/main/java/com/todoroo/astrid/voice/VoiceRecognizer.java index 1f428daf4..d7eb04bcb 100644 --- a/astrid/src/main/java/com/todoroo/astrid/voice/VoiceRecognizer.java +++ b/astrid/src/main/java/com/todoroo/astrid/voice/VoiceRecognizer.java @@ -16,12 +16,12 @@ import android.support.v4.app.Fragment; import android.widget.EditText; import android.widget.ImageButton; -import com.todoroo.astrid.voice.RecognizerApi.RecognizerApiListener; import com.todoroo.andlib.utility.AndroidUtilities; -import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.utility.Constants; +import com.todoroo.astrid.voice.RecognizerApi.RecognizerApiListener; import org.tasks.R; +import org.tasks.preferences.Preferences; import java.util.List; @@ -77,13 +77,13 @@ public class VoiceRecognizer { return instance; } - public void startVoiceRecognition(Context context, Fragment fragment) { + public void startVoiceRecognition(Preferences preferences, Context context, Fragment fragment) { if (speechRecordingAvailable(context) && recognizerApi != null) { recognizerApi.start(Constants.PACKAGE, context.getString(R.string.audio_speak_now)); } else { int prompt = R.string.voice_edit_title_prompt; - if (Preferences.getBoolean(R.string.p_voiceInputCreatesTask, false)) { + if (preferences.getBoolean(R.string.p_voiceInputCreatesTask, false)) { prompt = R.string.voice_create_prompt; } voiceInputAssistant.startVoiceRecognitionActivity(fragment, prompt); diff --git a/astrid/src/main/java/org/tasks/preferences/ActivityPreferences.java b/astrid/src/main/java/org/tasks/preferences/ActivityPreferences.java index 88d01e3ca..68bcb358b 100644 --- a/astrid/src/main/java/org/tasks/preferences/ActivityPreferences.java +++ b/astrid/src/main/java/org/tasks/preferences/ActivityPreferences.java @@ -46,7 +46,7 @@ public class ActivityPreferences extends Preferences { public int getEditDialogTheme() { boolean ics = AndroidUtilities.getSdkVersion() >= 14; - int themeSetting = com.todoroo.andlib.utility.Preferences.getBoolean(R.string.p_use_dark_theme, false) ? R.style.Tasks : R.style.Tasks_Light; + int themeSetting = getBoolean(R.string.p_use_dark_theme, false) ? R.style.Tasks : R.style.Tasks_Light; int theme; if (themeSetting == R.style.Tasks) { if (ics) {