we are trying to implement a simple quiz which should be controlled by VoiceRecognition. We have to Activities one QuestionActivity and one AnswerActivity. In the QuestionActivity the question is read by TextToSpeech and afterwards the user can answer to the VoiceRecognition Activity. Then the AnswerActivity is started by startActivityForResult(...) which also uses a VoiceRecognition to make it possible for the user to navigate back to the next Question. However, if the user returns to his second Question, the VoiceRecognizer wouldnt work because of an unknown error. See the sample code below:
public class QuestionActivity extends Activity implements OnClickListener, OnInitListener, OnUtteranceCompletedListener {
private static final int VOICE_RECOGNITION_REQUEST_CODE = 1234;
private TxtToSpeech toSpeech = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
toSpeech = new TxtToSpeech(this);
setContentView(R.layout.main);
// Get display items for later interaction
Button speakButton = (Button) findViewById(R.id.btn_speak);
// Check to see if a recognition activity is present
PackageManager pm = getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(
new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
if (activities.size() != 0) {
speakButton.setOnClickListener(this);
} else {
speakButton.setEnabled(false);
speakButton.setText("Recognizer not present");
}
}
public void onClick(View v) {
if (v.getId() == R.id.btn_speak) {
startVoiceRecognitionActivity();
}
}
private void startVoiceRecognitionActivity() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Speech recognition demo");
intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == VOICE_RECOGNITION_REQUEST_CODE && resultCode == RESULT_OK) {
//---Code to restart
//Without this code the recognizer wont work!
Intent i = getIntent();
finish();
startActivity(i);
//-----------------
Intent intent = new Intent(this, SubActivity.class);
startActivityForResult(intent , 2222);
}
else if( requestCode == 2222 )
{
saySomething();
}
super.onActivityResult(requestCode, resultCode, data);
}
void saySomething()
{
toSpeech.playVoice(new String[] {"My Question"}, true); //true == start Recognition afterwards
}
#Override
public void onInit(int status) {
toSpeech.mTts.setLanguage(Locale.US);
toSpeech.mTts.setOnUtteranceCompletedListener(this);
saySomething();
}
#Override
public void onUtteranceCompleted(String utteranceId) {
startVoiceRecognitionActivity();
}
public class AnswerActivity extends Activity implements OnInitListener, OnUtteranceCompletedListener{
public final static int VOICE_RECOGNITION_REQUEST_CODE = 4321;
private TxtToSpeech toSpeech = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
toSpeech = new TxtToSpeech(this);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
setResult(RESULT_OK);
finish();
super.onActivityResult(requestCode, resultCode, data);
}
#Override
public void onUtteranceCompleted(String utteranceId) {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Speech recognition demo");
startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE);
}
#Override
public void onInit(int status) {
toSpeech.mTts.setOnUtteranceCompletedListener(this);
toSpeech.mTts.setLanguage(Locale.US);
toSpeech.playVoice(new String[] {"correct answer"}, true); //again start recognition after voice
}
}
public class TxtToSpeech {
public TextToSpeech mTts = null;
public Context ctxt = null;
public boolean recordAnswer = false;
public TxtToSpeech(Context context){
mTts = new TextToSpeech(context, (OnInitListener)context);
ctxt = context;
}
public void playVoice(String[] sentences, boolean answer){
final HashMap<String, String> utteranceMap = new HashMap<String,String>();
utteranceMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "1");
recordAnswer = answer;
StringBuilder builder = new StringBuilder();
for( String s:sentences)
{
builder.append(s);
builder.append(",");
}
final String text = builder.toString();
if( recordAnswer )
mTts.speak(text, TextToSpeech.QUEUE_ADD, utteranceMap);
else
mTts.speak(text, TextToSpeech.QUEUE_ADD, null);
}
}
do I always have to restart the whole QuestionActivity in order to have a running VoiceRecognition? During the game the user only cycles between the Question- and the AnswerActivity is there a nicer way than just finish()-ing the Activities?
Please describe the error you get.
In general, restarting an activity should be a normal part of any Android activity since the user switches all the time. Also, if two activities are awkward, maybe you can get by with just a single one.
Related
I'm using ShotWatch to capture screenshots events.
The included example only works while inside the aplication, but I want to capture the event and launch an Activity. My code seems to ignore the service.
The mainfest has all the services/activity defined.
MainActivity:
public class MainActivity extends AppCompatActivity {
private ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.imageView = findViewById(R.id.imageView);
// run-time permissions
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
// You can directly ask for the permission.
// The registered ActivityResultCallback gets the result of this request.
Toast.makeText(this, ":(", Toast.LENGTH_LONG).show();
ActivityCompat.requestPermissions(MainActivity.this, new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}, 0);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
// You can use the API that requires the permission.
Toast.makeText(this, "OK", Toast.LENGTH_LONG).show();
startService(new Intent(MainActivity.this, ScreenshotCaptureService.class));
}
}
}
ScreenshotCaptureService:
public class ScreenshotCaptureService extends Service implements ShotWatch.Listener {
private ShotWatch shotWatch;
#Override
public void onCreate() {
super.onCreate();
this.shotWatch = new ShotWatch(getContentResolver(), this);
this.shotWatch.register();
}
#Override
public void onDestroy() {
super.onDestroy();
this.shotWatch.unregister();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
#Override
public void onScreenShotTaken(ScreenshotData data) {
Intent intent = new Intent(this, AddActivity.class);
intent.putExtra(AddActivity.CAPTURE_PATH, data.getPath());
startService(intent);
}
}
AddActivity:
public class AddActivity extends AppCompatActivity {
public static final String CAPTURE_PATH = "ADD_CAPTURE_PATH";
private ImageButton imageButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add);
Uri captura = Uri.fromFile(new File(getIntent().getStringExtra(AddActivity.CAPTURE_PATH)));
this.imageButton = findViewById(R.id.imageButton);
this.imageButton.setImageURI(captura);
this.imageButton.setOnClickListener((View v)->{
// ...
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK) return;
switch (requestCode) {
// ...
}
}
}
Fixed.
I was using 'startService' instead of 'startActivity' inside onScreenShotTaken, on ScreenshotCaptureService.
I have a FragmentActivity that is starting another activity for result. When the called activity finishes, onActivityResult is not called. Does it make a difference that I am using a AppCompatActivity activity (which extends from FragmentActivity)? The documentation says that results will be returned to the calling fragment, and in this case it's not a fragment, it's an activity. Here is the code, very simple:
MainActivity:
public class SMSEmailActivityNew extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setup activity....
Intent i = new Intent(this, EulaActivity.class);
i.putExtra(Globals.keyFileName,Globals.FILE_EULA );
startActivityForResult(i,RESULT_OK);
}
//this method is never called
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//dowork .....
}
}
Called activity:
EulaActivity extends AppCompatActivity implements OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//set up activity ....
}
public void onClick(View v) {
Intent result = new Intent();
if (bPermissionGranted) {
setResult(Activity.RESULT_OK, result);
// Determine if EULA was accepted this time
getSharedPreferences().edit().putBoolean(Globals.KEY_EULA_ACCEPTED, true).apply();
} else {
setResult(Activity.RESULT_CANCELED, result);
}
finish();
}
}
According to documentation you need to pass requestId bigger or equal thant 0. In your case RESULT_OK is -1. Also RESULT_OK acts like result code, not like request code and startActivityForResult needs a request code.
Something like this startActivityForResult(intent, 0);
Also finish EulaActivity using finishActivity(yourPreviousRequestCode);, in this case 0.
Try this solution:-
MainActivity.java
//Define variable
public static int REQUEST_CODE = 233;
public class SMSEmailActivityNew extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setup activity....
Intent i = new Intent(this, EulaActivity.class);
i.putExtra(Globals.keyFileName,Globals.FILE_EULA );
startActivityForResult(i, REQUEST_CODE); //Change here
}
//this method is never called
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE) {
if(resultCode == RESULT_OK) {
if(data != null && data.hasExtra("MESSAGE")) {
String resStr = data.getStringExtra("MESSAGE");
Toast.makeText(MainActivity.this, resStr, Toast.LENGTH_SHORT).show();
}
}else if(resultCode == RESULT_CANCELED)
Toast.makeText(MainActivity.this, "Canceled", Toast.LENGTH_SHORT).show();
}
}
}
EulaActivity.java
EulaActivity extends AppCompatActivity implements OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//set up activity ....
}
public void onClick(View v) {
Intent result = new Intent();
result.putExtra("MESSAGE","Eula Accepted Set");
if (bPermissionGranted) {
setResult(Activity.RESULT_OK, result);
// Determine if EULA was accepted this time
getSharedPreferences().edit().putBoolean(Globals.KEY_EULA_ACCEPTED, true).apply();
} else {
setResult(Activity.RESULT_CANCELED, result);
}
finish();
}
}
If anyone could explain me why I am getting this error, and how to rectify it.
This is the second activity
public class Result_activity extends Activity {
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.result_activity);
Bundle extras = getIntent().getExtras();
String inputString = extras.getString("yourkey");
TextView view = (TextView) findViewById(R.id.textView1);
view.setText(inputString);
}
#Override
public void finish() {
Intent intent = new Intent();
EditText editText= (EditText) findViewById(R.id.result_value);
String string = editText.getText().toString();
intent.putExtra("returnkey", string);
setResult(RESULT_OK, intent);
super.finish();
}
}
This is my main Activity
public class MainActivity extends ActionBarActivity {
// constant to determine which sub-activity returns
private static final int REQUEST_CODE = 10;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View view) {
EditText text = (EditText) findViewById(R.id.editText1);
String string = text.getText().toString();
Intent i = new Intent(this, Result_activity.class);
i.putExtra("yourkey", string);
startActivityForResult(i, REQUEST_CODE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE) {
if (data.hasExtra("returnkey")) {
String result = data.getExtras().getString("returnkey");
if (result != null && result.length() > 0) {
Toast.makeText(this, result, Toast.LENGTH_SHORT).show();
}
}
}
}
}
Intent intent = new Intent();
does not specify any action or class.
In your main activity you specified an intent with a class which is the correct way :
Intent i = new Intent(this, Result_activity.class);
I've read many answers on the same question but still I do not understand why my code doesn't work properly. I have a problem with (as I think) exchanging data between two activities.
I have 2 activities - the first contains ListView and an Add button.
When user presses Add new activity starts with the form to fill. When user completes the form he/she presses OK and my first activity starts again (it really does) and it should contain new item (but it doesn't).
This is my first activity:
public class DatabaseActivity extends Activity implements OnClickListener {
ArrayList<Student> students;
StudentDatabaseAdapter adapter;
ListView lvStudentList;
ImageButton imgBtnAdd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.database);
students = new ArrayList<Student>();
fillArrayList();
adapter = new StudentDatabaseAdapter(this, students);
lvStudentList = (ListView)findViewById(R.id.lvStudentsList);
lvStudentList.setAdapter(adapter);
imgBtnAdd = (ImageButton)findViewById(R.id.imagBtnAddStudent);
imgBtnAdd.setOnClickListener(this);
}
public void fillArrayList() {
//code here
}
#Override
public void onClick(View v) {
Intent intent;
intent = new Intent(this, WizardActivity.class);
startActivity(intent);
}
public void addStudent(Student student) {
students.add(student);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if(resultCode==RESULT_OK)
{
if(requestCode==2)
{
if (intent == null) {return;}
Student newStudent = new Student(intent.getStringExtra("name"), intent.getStringExtra("surname"),
intent.getStringExtra("last_name"), Integer.parseInt(intent.getStringExtra("year_of_birth")), R.drawable.default_ava);
addStudent(newStudent);
adapter.notifyDataSetChanged();
}
}
}
}
And that's my second activity:
public class WizardActivity extends Activity implements OnClickListener {
EditText etName, etSurname, etLastName, etYearOfBirth;
ImageButton imgBtnOK;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.wizard);
etName = (EditText)findViewById(R.id.etName);
//initializing other edit texts
imgBtnOK = (ImageButton)findViewById(R.id.imgBtnOK);
imgBtnOK.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Intent intent = new Intent(this, DatabaseActivity.class);
intent.putExtra("name", etName.getText().toString());
intent.putExtra("surname", etSurname.getText().toString());
intent.putExtra("last_name", etLastName.getText().toString());
intent.putExtra("year_of_birth", etYearOfBirth.getText().toString());
setResult(RESULT_OK, intent);
startActivityForResult(intent, 2);
}
}
There is nothing wrong with your notifyDataSetChanged(). You seem to be missing the way a secondary activity communicates results back to its caller activity.
DatabaseActivity.onClick() should call startActivityForResult() instead of startActivity().
WizardActivity.onClick() should just call finish() after setResult() (remove the startActivityForResult() call, it doesn't make sense there). Also notice that the intent you provide to setResult() can be an empty intent, i.e. Intent intent = new Intent();
After the secondary activity finishes, DatabaseActivity will be back to foreground and the result will be processed by DatabaseActivity.onActivityResult().
I think you haven't to start new activity in WizardActivity
try this :
WizardActivity
......
#Override
public void onClick(View v) {
Intent intent = new Intent(this, DatabaseActivity.class);
intent.putExtra("name", etName.getText().toString());
intent.putExtra("surname", etSurname.getText().toString());
intent.putExtra("last_name", etLastName.getText().toString());
intent.putExtra("year_of_birth", etYearOfBirth.getText().toString());
setResult(RESULT_OK, intent);
finish();
}
and in
DatabaseActivity
add if you want
#Override
protected void onResume (){
......
adapter.notifyDataSetChanged();
}
I use activity to call Google speech recognition Activity. My question it that, can we listen keyevent in main activity when Google Speech Reg Activity already popuped??
any ideas? Though, i know that main activity will be onPause when Google Activity popuped.
here is my android code
public class TestSpeechReg extends Activity {
private TextView txtText;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button startButton = new Button(this);
startButton.setText("Start TestSpeechReg");
startButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startSpeechReg(TestSpeechReg.this);
}
});
txtText = new TextView(this);
txtText.setText("###################");
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(startButton);
layout.addView(txtText);
setContentView(layout);
}
// voice recognition
public static final int REQUESTCODE_SPEECHRECOGNITION = 0x1000;
private void startSpeechReg(Activity context) {
Log.i("TestSpeechReg", "openSpeechRecognition");
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
context.startActivityForResult(intent, REQUESTCODE_SPEECHRECOGNITION);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUESTCODE_SPEECHRECOGNITION: {
if (resultCode == RESULT_OK && null != data) {
ArrayList<String> text = data
.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
txtText.setText(text.get(0));
}
break;
}
}
}
}
If you want to control the UI (e.g. listen to key presses) then interact with the speech recognizer via the SpeechRecognizer-class (requires API level 8), which does not start a new activity. Your current code starts a new activity, i.e. your UI is stopped (i.e. not just onPause, but also onStop is called, I think).