/* * Copyright 2011 Greg Milette and Adam Stroud * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package root.gast.playground.speech.food; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.List; import root.gast.playground.R; import root.gast.playground.speech.food.command.AddFood; import root.gast.playground.speech.food.command.CancelCommand; import root.gast.playground.speech.food.command.FoodLookup; import root.gast.playground.speech.food.command.RemoveFood; import root.gast.playground.speech.food.db.FtsIndexedFoodDatabase; import root.gast.speech.SpeechRecognizingAndSpeakingActivity; import root.gast.speech.voiceaction.MultiCommandVoiceAction; import root.gast.speech.voiceaction.VoiceAction; import root.gast.speech.voiceaction.VoiceActionCommand; import root.gast.speech.voiceaction.VoiceActionExecutor; import root.gast.speech.voiceaction.WhyNotUnderstoodListener; import android.app.ProgressDialog; import android.content.Intent; import android.os.Bundle; import android.speech.tts.TextToSpeech; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; /** * Uses {@link VoiceAction}s and {@link FtsIndexedFoodDatabase} to implement the food dialogue * @author Greg Milette <<a href="mailto:gregorym@gmail.com">gregorym@gmail.com</a>> */ public class MultiTurnFoodDialogActivity extends SpeechRecognizingAndSpeakingActivity { private static final String TAG = "MultiTurnFoodDialogActivity"; private FtsIndexedFoodDatabase foodDb; private TextView log; private VoiceActionExecutor executor; private VoiceAction lookupVoiceAction; private VoiceAction editVoiceAction; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fooddialogmulti); hookButtons(); initDbs(); initDialog(); } private void hookButtons() { log = (TextView)findViewById(R.id.tv_resultlog); Button edit = (Button)findViewById(R.id.btn_food_edit); edit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { executor.execute(editVoiceAction); } }); Button food = (Button)findViewById(R.id.btn_food_lookup); food.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { executor.execute(lookupVoiceAction); } }); } private void initDialog() { if (executor == null) { executor = new VoiceActionExecutor(this); } editVoiceAction = makeFoodEdit(); lookupVoiceAction = makeFoodLookup(); } /** * make sure the databases have data */ private void initDbs() { foodDb = FtsIndexedFoodDatabase.getInstance(this); if (foodDb.isEmpty()) { Log.d(TAG, "loading foods"); InputStream stream = getResources().openRawResource(R.raw.foods); try { foodDb.loadFrom(stream); } catch (IOException io) { Log.d(TAG, "failed to load db"); } } } @Override public void onSuccessfulInit(TextToSpeech tts) { super.onSuccessfulInit(tts); Log.d(TAG, "activate ui, set tts"); executor.setTts(getTts()); } protected void receiveWhatWasHeard(List<String> heard, float[] confidenceScores) { Log.d(TAG, "received " + heard.size()); clearLog(); for (int i = 0; i < heard.size(); i++) { appendToLog(heard.get(i) + " " + confidenceScores[i]); } executor.handleReceiveWhatWasHeard(heard, confidenceScores); } protected void recognitionFailure() { //don't do anything here Log.d(TAG, "cancelled with button"); } private VoiceAction makeFoodEdit() { FtsIndexedFoodDatabase foodDb = FtsIndexedFoodDatabase .getInstance(MultiTurnFoodDialogActivity.this); // match it with two levels of strictness boolean relaxed = false; VoiceActionCommand cancelCommand = new CancelCommand(this, executor); VoiceActionCommand removeCommand = new RemoveFood(this, executor, foodDb, relaxed); VoiceActionCommand addCommand = new AddFood(this, executor, foodDb, relaxed); relaxed = true; VoiceActionCommand removeCommandRelaxed = new RemoveFood(this, executor, foodDb, relaxed); VoiceActionCommand addCommandRelaxed = new AddFood(this, executor, foodDb, relaxed); VoiceAction voiceAction = new MultiCommandVoiceAction(Arrays.asList(cancelCommand, addCommand, removeCommand, addCommandRelaxed, removeCommandRelaxed)); // don't retry voiceAction.setNotUnderstood(new WhyNotUnderstoodListener(this, executor, false)); final String EDIT_PROMPT = getResources().getString(R.string.food_edit_prompt); // no spoken prompt voiceAction.setPrompt(EDIT_PROMPT); return voiceAction; } private VoiceAction makeFoodLookup() { final String LOOKUP_PROMPT = getResources().getString(R.string.food_lookup_prompt); FtsIndexedFoodDatabase foodDb = FtsIndexedFoodDatabase.getInstance( MultiTurnFoodDialogActivity.this); VoiceActionCommand lookup = new FoodLookup(this, executor, foodDb); VoiceActionCommand cancel = new CancelCommand(this, executor); VoiceAction voiceAction = new MultiCommandVoiceAction(Arrays.asList(cancel, lookup)); voiceAction.setNotUnderstood(new WhyNotUnderstoodListener(this, executor, false)); voiceAction.setPrompt(LOOKUP_PROMPT); return voiceAction; } private void clearLog() { log.setText(""); } private void appendToLog(String appendThis) { String currentLog = log.getText().toString(); currentLog = currentLog + "\n" + appendThis; log.setText(currentLog); } //menu handling public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.food_multi_dialog_menu, menu); return true; } public boolean onOptionsItemSelected (MenuItem item) { if (item.getItemId() == R.id.m_resetdb_param) { final ProgressDialog dialog = ProgressDialog.show(this, "Please wait", "Updating Food Database"); dialog.setIndeterminate(true); Runnable updateDbRunnable = new Runnable() { @Override public void run() { FtsIndexedFoodDatabase.getInstance(MultiTurnFoodDialogActivity.this).clean(MultiTurnFoodDialogActivity.this); //now load initDbs(); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MultiTurnFoodDialogActivity.this, "Reset database", Toast.LENGTH_SHORT).show(); dialog.hide(); } }); } }; Thread updateDbThread = new Thread(updateDbRunnable); updateDbThread.start(); } else if (item.getItemId() == R.id.m_showdb_param) { Intent browseIntent = new Intent(this, FoodBrowser.class); startActivity(browseIntent); } return true; } }