onActivityResult never called for speech Intent on Google Glass - android

I have a menu Activity with several options. One of them is to post to a news feed using Glass's speech-to-text. I looked at https://developers.google.com/glass/develop/gdk/input/voice#starting_the_speech_recognition_activity
and have it all implemented, but the onActivityResult method apparently never gets called.
On the Glass device, I'm able to select "New Post" in the menu and the voice capture comes up. I can speak to it and it'll convert my speech to text on the screen. But after I accept it (by tapping or waiting a few seconds), it just exits and takes me back to the home screen. I need to be able to get the speech text String in onActivityResult and call another method (displayPostMenu) to show another menu to process the text but I can't do that if onActivityResult is never called.
I've looked at several similar issues but none of the solutions have worked/were applicable... I don't think I can setResult() on RecognizerIntent.ACTION_RECOGNIZE_SPEECH since it's Google's? Any help would be greatly appreciated!
Some pieces of my code:
private final int SPEECH_REQUEST = 1;
//Code to make this Activity work and the menu open...
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.view_feed:
//Stuff
return true;
case R.id.new_post:
Log.i("MainMenu", "Selected new_post");
displaySpeechRecognizer();
Log.i("MainMenu", "Ran displaySpeechRecog under new_post selection");
return true;
case R.id.stop:
Activity parent = getParent();
Log.i("MainMenu", "Closing activity; parent: " + parent + "; " + hashCode());
if (parent != null && parent.getApplication() == getApplication()) {
finish();
} else {
MainMenu.close();
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void onOptionsMenuClosed(Menu menu) {
// Nothing else to do, closing the Activity.
finish();
}
public void displaySpeechRecognizer() {
Log.i("MainMenu", "Entered displaySpeechRecognizer");
Intent speechIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
startActivityForResult(speechIntent, SPEECH_REQUEST);
Log.i("MainMenu", "Finished displaySpeechRecognizer. startActivityForResult called.");
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.i("MainMenu", "onActivityResult entered from MainMenu");
switch (requestCode) {
case SPEECH_REQUEST:
Log.i("MainMenu", "onActivityResult enters SPEECH_REQUEST case");
if (resultCode == RESULT_OK) {
Log.i("MainMenu", "onActivityResult enters RESULT_OK for voice cap");
List<String> results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
String spokenText = results.get(0);
Log.i("MainMenu", "SpokenText:" + spokenText);
holdText = spokenText;
if (holdText != "") {
displayPostMenu();
}
}
super.onActivityResult(requestCode, resultCode, data);
}

You say this is a "menu activity", so does that mean that it's attached to a live card?
If so, are you overriding onOptionsMenuClosed and calling finish inside it?
If you are, the menu activity will finish and destroy itself before the speech activity returns, so there will be no place for the result to go back to.
One approach to fix this would be to use a flag to indicate whether you should defer the call to finish when the menu is closed, and make that call conditionally inside onOptionsMenuClosed based on that flag. Then, set that flag in your displaySpeechRecognizer method and wait until the end of your onActivityResult processing to call finish instead.
Something like this should work (written without testing, may contain typos):
private boolean shouldFinishOnMenuClose;
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// By default, finish the activity when the menu is closed.
shouldFinishOnMenuClose = true;
// ... the rest of your code
}
private void displaySpeechRecognizer() {
// Clear the flag so that the activity isn't finished when the menu is
// closed because it will close when the speech recognizer appears and
// there won't be an activity to send the result back to.
shouldFinishOnMenuClose = false;
// ... the rest of your code
}
#Override
public void onOptionsMenuClosed(Menu menu) {
super.onOptionsMenuClosed();
if (shouldFinishOnMenuClose) {
finish();
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == SPEECH_REQUEST) {
if (resultCode == RESULT_OK) {
// process the speech
}
// *Now* it's safe to finish the activity. Note that we do this
// whether the resultCode is OK or something else (so the menu
// activity goes away even if the user swipes down to cancel
// the speech recognizer).
finish();
}
}

Related

Why Activity does not provide onActivityResult(...) callback as it does for permissions (onRequestPermissionsResult)?

Intro
I am writing class that provides me current localization only once if its able to, and returns default coordinats if can not do it for any reason. Class will be used in many places so I wanted to make it as simple to implement for others as it can be. So code would look like
LocationFinder locationFinder = new LocationFinder(this);
locationFinder.setLocationResolvedCallback(new LocationFinder.LocationResolvedCallback() {
#Override
public void onLocationFound(double latitude, double longitude) {
Log.e("Activity", latitude + " " + longitude);
}
});
locationFinder.findCurrentLocation();
but there is a case when locations settings are turned off, and I have to request user to turn them on.
task.addOnFailureListener(activity, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case CommonStatusCodes.RESOLUTION_REQUIRED:
try {
// Show the dialog and check result
ResolvableApiException resolvable = (ResolvableApiException) e;
resolvable.startResolutionForResult(activity, REQUEST_LOCATION_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
break;
}
}
});
So now I have to go into activity and #Override onActivityResult(), handle it from activity level which makes my class less independent.
I wrote method that handle result code within my LocationFinder
public void onActivityResult(int requestCode, int resultCode) {
if (REQUEST_LOCATION_SETTINGS == requestCode) {
if (resultCode == Activity.RESULT_OK) {
requestCurrentLocation();
} else {
locationResolvedCallback.onLocationFound(DEFAULT_LAT, DEFAULT_LONG);
}
}
}
but I still have to #Override any activity that uses this class and call this method from it.
So my question is.
Why does android architects did not provide onActivityResult(...) callback as they did in case of permissions? So i could handle any request from within a class by just having reference to activity like
activity.onActivityResultCallback(...){///code}
There must be a reason but I may be missing something very obvious.
Activities have a lifecycle, and are therefore instantiated in a different way from an ordinary class.
However the functionality you are looking for can be provided by startActivityForResult(Intent). After the started activity is finished or removed from the stack, an intent is passed hack to the calling activity with a bundle you can use to pass back information
onActivityResult() called when you start activity for the result from the current Activity.
if you set the onActivityResult callback somewhere else following will happen.
Your fragments which are hosted in the activity can't get onActivityResult callback.
If you call multiple activities for the result you can't get a result properly (in one place).
For your reference see the below code. This will be never executed if you not called super.onActivityResult().
FragmentActivity onActivityResult:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mFragments.noteStateNotSaved();
int requestIndex = requestCode>>16;
if (requestIndex != 0) {
requestIndex--;
String who = mPendingFragmentActivityResults.get(requestIndex);
mPendingFragmentActivityResults.remove(requestIndex);
if (who == null) {
Log.w(TAG, "Activity result delivered for unknown Fragment.");
return;
}
Fragment targetFragment = mFragments.findFragmentByWho(who);
if (targetFragment == null) {
Log.w(TAG, "Activity result no fragment exists for who: " + who);
} else {
targetFragment.onActivityResult(requestCode & 0xffff, resultCode, data);
}
return;
}
Due to this factors android not provided anonymous callback of onActivityResult()
Suggestion: In my case, I have used BroadcastReceiver to get onActivityResult on my class.
Hope it helps:)

Avoid an item from Action Bar from being double clicked

I have designed an action bar for my Android app. In this action bar there's a button that launches a Dialog Activity used to configure my app's behavior. If I double click this button fast enough, I'm able to order the Dialog Activity to be launched twice before it actually appears, and then it appears duplicated and visually overlapped and I don't want this. I tried to create some sort of lock-down mechanism but it is not working because my Dialog Activity is launched only after all the code in my Main Activity calling method (onOptionsItemSelected) is executed. Is there a way to avoid this form happening?
My code is:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
//ensure only one element from the option menu is launched at once (if you double click fast you could launch two)
Log.e("test", "onOptionsItemSelected ");
if(optionItemAlreadySelected == false)
{
optionItemAlreadySelected = true;
int id = item.getItemId();
if (id == R.id.action_sound_mode) {
//item.setVisible(false);
Intent intent = new Intent(this, SoundConfigurationActivity.class);
startActivity(intent);
optionItemAlreadySelected = false; //this code is executed before the activity is started!!!
return true;
}
}
return super.onOptionsItemSelected(item);
}
Is there a way to know when the Dialog Activity has already being closed and lock the opportunity to open it once again until then.
Kotlin
It's a screen(Activity, Fragment) based solution to avoid a double tap on menu action.
Add below global variable to your activity/fragment containing onOptionsItemSelected function.
private var previousClickTimeMillis = 0L
Write below function anywhere in the project i.e Utils.
fun singleSafeClick(
previousClickTimeMillis: Long,
block: (previousClickTimeMillis: Long) -> Unit) {
val currentTimeMillis = System.currentTimeMillis()
if (currentTimeMillis < previousClickTimeMillis || currentTimeMillis >= previousClickTimeMillis + OnSingleClickListener.DELAY_MILLIS) {
block(currentTimeMillis)
}
}
Write your triggering code as below.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_delete -> {
singleSafeClick(previousClickTimeMillis) { tappedTime ->
previousClickTimeMillis = tappedTime
// Write Yyur code here
}
}
}
}
You can use a boolean variable to track the state of your Dialog. When you click the button you set mDialogShown = true to block any other show dialog requests.
Now when the user presses Back button and the Dialog is closed onActivityResult is called.
At this point your are sure that the Dialog was closed.
I assumed your code is inside an Activity:
class MainActivity extend Activity {
static final int SHOW_DIALOG_REQUEST = 1; // The request code
static boolean mDialogShown = false; // True if dialog is currently shown
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_sound_mode) {
showDialog();
return true;
}
return super.onOptionsItemSelected(item);
}
private void showDialog() {
if (!mDialogShown) {
mDialogShown = true;
Intent intent = new Intent(this, SoundConfigurationActivity.class);
startActivityForResult(intent, SHOW_DIALOG_REQUEST);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request we're responding to
if (requestCode == SHOW_DIALOG_REQUEST) {
mDialogShown = false;
}
}
}
Documentation
https://developer.android.com/training/basics/intents/result.html
https://developer.android.com/guide/topics/ui/dialogs.html#ActivityAsDialog

should I set the content view on activityResult when working with in-app-billing

I have a question about handling a purchase that the user makes. In my case, I want to remove the adds when user makes a purchase. I have two versions of my activity_main layout - one with adds and one without. I am wondering where and how to set the layout when the user makes a purchase.
I am thinking something like this:
if (adsDisabled == true){
setContentView(R.layout.mainNoAds)
} else{
setContentView(R.layout.main
}
the code I private variable listener:
private IabHelper.OnIabPurchaseFinishedListener mPurchasedFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
#Override
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
if (result.isFailure()) {
Log.d(TAG, "Error purchasing: " + result);
return;
}
else if (purchase.getSku().equals(SKU_REMOVE_ADDS)) {
// consume the purchase and update the UI
}
}
};
and I am calling it when my menu item is tapped:
public boolean onOptionsItemSelected(MenuItem item) {
if(id == R.id.action_remove_adds){
mHelper.launchPurchaseFlow(this,SKU_REMOVE_ADDS,1,mPurchasedFinishedListener,"");
}
return super.onOptionsItemSelected(item);
}
and this is my onActicityResult code:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
}
else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
This seems like a rather heavy-handed approach, as you're either duplicating quite a lot of your layout content between the two (ad/non-ad) definitions or include one layout in the other. If you're interested in just the AdView going away, why not simply set its visibility to View.GONE?
One thing worth nothing is that I'm not sure if hiding it away makes the ad requests stop and the AdView pause implicitly, so that might be worth taking a look at.

Android Google Plus SDK: how to get callback on the +1 button (PlusOneButton)

I added a +1 button in my Android app. I would like to add a callback in order to know what happened after the user clicked on the +1 button (did he validate its +1 ?, did he abort ? ...)
How can I do that ?
Thanks !
You can add a listener to check when the button is clicked and later check the result of the activity.
static final int PLUS_ONE_REQUEST = 1;
...
mPlusOneButton.setOnPlusOneClickListener(new PlusOneButton.OnPlusOneClickListener() {
#Override
public void onPlusOneClick(Intent intent) {
//here you can handle the initial click
//Start the activity to display the +1 confirmation dialog.
startActivityForResult(intent, PLUS_ONE_REQUEST);
}
});
...
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == PLUS_ONE_REQUEST) {
switch(resultCode) {
case RESULT_OK:
//here the operation was successful
break;
case RESULT_CANCELED:
//here the user backed out or failed
break;
}
}
}
Sources:
Handling the click
Getting a result from an activity
I hope that this is what your were asking, and more importantly that this was helpful.

Android: Unable to restart an ListActivity

First post, so please go easy.
I have an app with a handful of tabs, the first is opened on running the app.
One of the tabs is 'My Account' (a ListActivity) showing account options. I switch to this and if the user is not logged in, it, in turn, runs a UserLogon activity using the following:
Intent logonActivity = new Intent(getBaseContext(), UserLogon.class);
startActivityForResult(logonActivity, 0);
To catch the result, I use the following code:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 0){
MainBlock ta = (MainBlock) this.getParent();
TabHost th = ta.getMyTabHost();
th.setCurrentTab(0);
finish();
}
if (requestCode == 100)
{
showAccountOptions();
}
}
In the UserLogon class, I have the usual fare; TextView's and Button's. The intention is that if the user cancels the login, it will revert to the initial tab, or if login is successful, it will show the Account Options. And this is indeed what does happen.
All good so far.
The problem I'm having is that if I cancel the login and return to the first tab, when I select the Accounts tab again, I'm not presented with the UserLogon activity. I was under the impression that finish() would close the UserLogon activity, and the Accounts activity but it would appear not.
So, my question is simply, how do I, in effect, restart the Accounts activity so that the user would be presented with the option to login once more.
We're good people and all willing to help ;-) I'll give it a shot. Still, I'm not quite sure I get that all right.
Basically you have an TabActivity which you setup and where you do something like that:
myTabHost.setOnTabChangedListener(new OnTabChangeListener(){
#Override
public void onTabChanged(String tabId) {
if (tabId.equals("account") && !loggedIn) {
Intent logonActivity = new Intent(getBaseContext(), UserLogon.class);
startActivityForResult(logonActivity, 0);
}
}});
You're basically saying that the first Activity start of UserLogon works, but the second one doesn't, right? Did you debugged to that point to check whether you reach the code which starts the activity again?
Update based on comment
Your UserLogon should always provide a result information, here's a blueprint:
public class UserLogon extends Activity {
public void onCreate(Bundle bundle) {
// ... do something ...
// if activity is canceled this will be the "last" result
setResult(RESULT_CANCELED);
}
public void checkLoginOrSomethingLikeThat() {
Intent result = new Intent();
// put your results in this intent
setResult(RESULT_OK, intent);
// close activity since we have the information we need
finish();
}
}
The parent activity which is waiting for the result should do it like that:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// it's good practice to use a constant for 0 like LOGIN_REQUEST
// otherwise you will ask yourself later "What the hell did 0 stand for?"
if(requestCode == 0){
if (resultCode == RESULT_OK) {
// get needed data from data intent and react on that
} else {
// no success, react on that
}
}
// ... I don't know what your resultCode 100 is but handle itwith the same pattern
}

Categories

Resources