Why would TextToSpeech.getLanguage() *sometimes* return null? - android

In my app, I call TextToSpeech.getLanguage() well after instantiating TextToSpeech (~800ms according to LogCat), yet it sometimes (not always) return null, despite the language set properly in the system's TextToSpeech settings:
System Settings > Language & input >
Text-to-speech output > Google Text-to-speech > English (United Kingdom)
This only happens in Jelly Bean (Android 4.1.1).
It doesn't happen in Android 2.2.
Is this a known Android bug?
Or am I doing something wrong?
I instantiate, BTW, TextToSpeech in my app's main activity with:
new TextToSpeech(this, this);
And both instantiation and the call to TextToSpeech.getLanguage() are made in the same thread (thus order of calls is guaranteed).

You have to call getLanguage () in onInit (), sometimes it takes a few second for onInit () to be called.

I also discovered this bug today on an Asus TF700T running Android 4.1.1. I tried to resolve the issue by calling getLanguage() again as Eternal Learner suggested in a comment, but it still returns null no matter how many times I call it.
The easiest workaround for me was to abandon the current broken instance of TextToSpeech and create a new instance. The second instance seems to work reliably.

Related

Making hands-free calls

In my application, I need to make a call to a number, but the call must be made hands-free. I tried many available methods, min the method from this link.
The application logs showed the action of switching to hands-free, but physically it had no effect.
I also tried to do it with the help of such code:
private void enableHandsFree() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, ClassNotFoundException {
Class audioSystemClass = Class.forName("android.media.AudioSystem");
Method setForceUse = audioSystemClass.getMethod("setForceUse", int.class, int.class);
// First 1 == FOR_MEDIA, second 1 == FORCE_SPEAKER. To go back to the default
// behavior, use FORCE_NONE (0).
setForceUse.invoke(null, 1, 1);
}
Unfortunately also without success. Is there any way to handle such a problem?
Tested on Android 10
Undocumented API calls have been progressively disallowed in the last few android versions. The code you posted may work on on older APIs (my guess would be <= 26), but it'll have no effect in the newer versions.
For security reasons, no app is allowed to control audio output used by other apps. The only app that can do that is the one that as audio focus. And you're specifically trying to control audio output of the Phone app

Android 7.0/API24: How to check for notification access (Settings.Secure.enabled_notification_listeners)

In Android 6.0/API23 and earlier, the following used to work:
String settingEnabled = android.provider.Settings.Secure.getString(this.getContentResolver(), "enabled_notification_listeners");
In Android 7.0 Nougat/API24 this seems to be no longer supported, because the code above returns null.
It actually was never mentioned here: https://developer.android.com/reference/android/provider/Settings.Secure.html
How do we check if our app has notification access in Android 7.0 Nougat API24?
Edit: It seems that actually that after you first gained the access in the settings, the code above returns the correct state. But not on the initial request after installation.
Use this:
Set<String> packageNames = NotificationManagerCompat.getEnabledListenerPackages (context);

MediaControllerCompat - java.lang.IllegalArgumentException: Bad direction 3

I'm issuing a simple command to my mediaControllerCompat:
controller.adjustVolume(-1, 0);
Yet my app FCs with...
java.lang.IllegalArgumentException: Bad direction 3
at android.os.Parcel.readException(Parcel.java:1469)
at android.os.Parcel.readException(Parcel.java:1419)
at android.media.IAudioService$Stub$Proxy.adjustStreamVolume(IAudioService.java:1097)
at android.media.AudioManager.adjustStreamVolume(AudioManager.java:952)
at android.support.v4.media.session.MediaSessionCompat$MediaSessionImplBase.adjustVolume(MediaSessionCompat.java:1376)
at android.support.v4.media.session.MediaSessionCompat$MediaSessionImplBase.access$1700(MediaSessionCompat.java:963)
at android.support.v4.media.session.MediaSessionCompat$MediaSessionImplBase$MediaSessionStub.adjustVolume(MediaSessionCompat.java:1602)
at android.support.v4.media.session.MediaControllerCompat$MediaControllerImplBase.adjustVolume(MediaControllerCompat.java:969)
at android.support.v4.media.session.MediaControllerCompat.adjustVolume(MediaControllerCompat.java:252)
at pl.qus.xenoamp.NewMainActivity.onKeyDown(NewMainActivity.java:1149)
MainActivity being the caller of mentioned line... What is WRONG?!
This was an internal bug in the Android Support Library has been fixed as of version 23.1.0.
Previous Answer
This is a bug in the support library that affects pre-API 21 devices that use local playback (i.e., have not called setPlaybackToRemote()) - the order of parameters sent to AudioManager.adjustStreamVolume() as per the source code is incorrect - hence why the direction appearing as 3 - the value for STREAM_MUSIC.
You may be able to temporarily work around it by always calling setPlaybackToRemote() on pre-API 21 devices, passing in a VolumeProviderCompat that does correctly call AudioManager.adjustStreamVolume(), but you must also handle the other methods of VolumeProviderCompat such as retrieving the max volume (via getStreamMaxVolume()) and current volume (via getStreamVolume()) as well as setting the volume (via setStreamVolume()).
I came across the same error using API 23 (not the Support Library) and running on an M device. I solved it by listening for the error and calling an API 1 method in its place, when necessary.
try {
...
} catch (IllegalArgumentException e) {
audioManager.setStreamVolume(STREAM, VOLUME, FLAGS);
}
Since the Compat interface calls the internal methods for system volume control, you could also instantiate an instance AudioManager if you are not directly declaring one already.

MediaRouter connect second time

I am using Android's MediaRouter / Presentation API (the support.v7 version).
Everything works fine so far. The only thing that doesn't is:
When I quit my activity (e.g.teardown & remove the callbacks), everything still works fine.
However, when starting this activity (the previous mediarouter-activity was forcefully finished, thus onPause/onDestroy was called FOR SURE => so those callbacks in there are gone too, as also shown in my debug messages) again at some later point in time, the callbacks get created and added and everything. Just, that there is no more onRouteAdded called, only onProviderChanged (With the default provider and thus useless).
It does always work like that (with wifi display [miracast], emulated secondary display, chromecast secondary display..). Are there any resolutions which are not in the examples?
Would you like to look at some code? Which special cases? (Can't post it all..)
I couldn't find anything so far, thanks for your help, in advance.
If you change the Google Cast sample app to support MediaRouter.Callback:
https://github.com/googlecast/CastPresentation-android
Then I'm getting the onRouteAdded called every time.
Using getSelectedRoute()instead of the RouteInfo (which is provided by the callbacks) did the job for me.
MediaRouter.RouteInfo selectedRoute = getHelper().getMediaRouter().getSelectedRoute();
if(provider != null && getCurrentRoute() != null && getCurrentRoute().equals(selectedRoute)){
Log.d(TAG, "only provider changes, dont do anything");
return false;
}
if (selectedRoute != null) {
setCurrentRoute(selectedRoute);
}
return updateContents();
this is definetly weird (as the rest of the code looks exactly as in the provided google android developer samples), but it works.
I know this problem was resolved over 1 year ago, but probably it isn't the perfect solution. Maybe it will be useful for somebody else.
I had similar problem with exactly the same symptoms (no more onRouteAdded called). In my situation it was caused by improperly implemented deactivation of MediaRouter: to deactivate it properly you should not only remove all of callbacks, but select default MediaRoute as well.
if (!mMediaRouter.getDefaultRoute().isSelected()) {
mMediaRouter.getDefaultRoute().select();
}

In what circumstances does TextToSpeech.isSpeaking() return true?

The documentation says "Checks whether the TTS engine is busy speaking."
But I just implemented a call to isSpeaking() in an onUtteranceCompletedListener, where I have at least 10 pending utterances and in none of them did I received true.
Assuming that isSpeaking() actually works as documented, I must conclude that I am calling it incorrectly.
What are the points in which calling TextToSpeech.isSpeaking() returns a valid result?
Answering myself, thanks to coming across this question (also unanswered):
Problem with isSpeaking() when using Text-to-Speech on Android
The source code of the TtsService class shows:
public boolean isSpeaking() {
return (mSelf.mIsSpeaking && (mSpeechQueue.size() < 1));
}
Which means the TTS engine not only must be speaking but its utterances queue size must be greater than 0.

Categories

Resources