Making hands-free calls - android

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

Related

Android: Possible maximum number of audiosessions or effect engines for audio? (EQ, REV...)

for awhile now, I am working on a media playing app. In this app, I also programmed a little 5 Band EQ using mainly this code:
try
{
AppPreferencesClass ap = new AppPreferencesClass(ctx);
if (Activity_Player.eq != null)
{
Activity_Player.eq.Dispose();
}
Activity_Player.eq = new Android.Media.Audiofx.Equalizer(0, Activity_Player.mediaPlayerSessionId);
Activity_Player.eq.SetEnabled(true);
await Task.Run(() =>
{
if (Activity_Player.EqActive)
{
if (ap.getAwesomeSound())
{
Activity_Player.eq.SetBandLevel(0, Convert.ToInt16(Activity_Equalizer.awesomesound0));
Activity_Player.eq.SetBandLevel(1, Convert.ToInt16(Activity_Equalizer.awesomesound1));
Activity_Player.eq.SetBandLevel(2, Convert.ToInt16(Activity_Equalizer.awesomesound2));
Activity_Player.eq.SetBandLevel(3, Convert.ToInt16(Activity_Equalizer.awesomesound3));
Activity_Player.eq.SetBandLevel(4, Convert.ToInt16(Activity_Equalizer.awesomesound4));
}
else
{
Activity_Player.eq.SetBandLevel(0, Convert.ToInt16(ap.getEQ0()));
Activity_Player.eq.SetBandLevel(1, Convert.ToInt16(ap.getEQ1()));
Activity_Player.eq.SetBandLevel(2, Convert.ToInt16(ap.getEQ2()));
Activity_Player.eq.SetBandLevel(3, Convert.ToInt16(ap.getEQ3()));
Activity_Player.eq.SetBandLevel(4, Convert.ToInt16(ap.getEQ4()));
}
}
});
}
catch
{
}
For many days, this worked just fine but out of NO WHERE, the catch block sometimes gets activated. But only occasionally.On other times, try works fine but there are just no more changes to the audio being played. This is odd enough, since I never changed anything on this code after it starting working.
I then tried another phone (Samsung S4) on my code and the eq worked just perfectly.
So this got me googleing and I think I might have heard that there can only be as many audiosession IDs after you just would run out. I tested and the audio session ID used here is somewhere at 74,000.
So this could be an issue I thought but this would easialy be tested because I already had this very app running in the google play store just an older version of it. I am 100 percent positive, that in this version the EQ worked on my phone. Otherwise I would have not uploaded that version.
Anyway, I downloaded my old app from the play store and here we go:
It doesnt work anymore. The EQ in the old version also has simply NO effect on the audio. While ofcourse on my other phones this old version works perfectly.
Before I am going to reset my own personal phone I wanted to ask you guys if this could be infact the case.
Another thing is, that I am using many static variables in order to get the EQ to work right. Actually, the variable EQ itself is static. Do maybe static variables sort of leave a "trace" behind and maybe I have set the eq up just "too" many times? Although I am disposing of the object before intialising it again (see in my code).
Summing up:
1.) Can there maybe be a maxmium number of EQ or AudioSessionIDs and I have passed those?
2.) Can creating static variables over and over again in my code cause a memory leak so big, even deinstalling the app doesnt do anything?
Thank you!
This is the error log:
11-20 12:16:43.736 E/AudioEffect(16990): set(): AudioFlinger could not create effect, status: -38
11-20 12:16:43.736 E/AudioEffects-JNI(16990): Error setting AudioEffect
11-20 12:16:43.737 E/AudioEffect-JAVA(16990): Error code -19 when initializing AudioEffect.
Thread started: #311-20 12:16:43.745 V/MediaPlayerNative(16990): unrecognized message: (6, 0, 0)
After 2 days of googeling and trying evetything out, here is the issue:
NOT CALLING RELEASE() will have you eventually have to REBOOT your phone. It wont allow too many instances of an EQ to be set.
Solution:
if (eq != null)
{
eq.Release();
}

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.

PhoneStateListener - what can I expect from onCellInfoChanged?

I posted this on Android dev group. I'm hoping I can get some feedback here.
The PhoneStateListener's callbacks onCellLocationChanged and onSignalStrengthsChanged were the goto methods for when I wanted to handle cell and signal data changes in GSM and CDMA. With API 17+, I can see that there's a new callback (onCellInfoChanged) for handling both cell and signal changes.
Looking at the documentation, it's not clear what I can expect from the introduction of this new callback.
Will LTE changes always and only trigger onCellInfoChanged?
Will GSM/CDMA changed remain on the older callbacks?
Does one overlap with the other? (i.e. Both old and new get triggered for LTE or GSM/CDMA.)
It may very well be that different OEMs will have different implementations (sigh!), but I'm hoping there are guidelines that everyone's supposed to follow.
Can anyone shed some light on this?
Thanks,
Sebouh
I didn't test if but it looks from the code that both will be called.
I downloaded code source of Android 4.3(API 18) using the SDK Manager.
The following observations made me think that both would be called.
The class that triggers these events is: com.android.server.TelephonyRegistry
It notifies the listener though:
public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow)
This same function calls for both type of notifications(Location and CellInfo) in a non exclusive way.
On line 256:
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
try {
if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation=" + mCellLocation);
r.callback.onCellLocationChanged(new Bundle(mCellLocation));
} catch (RemoteException ex) {
remove(r.binder);
}
}
This one will call onCellLocationChanged even on new LTE phone since there is nothing from the above code that would prevent this. This needs double checking that there is no upper layer that filters the events themselves
On line 300 in the same code:
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
try {
if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo=" + mCellInfo);
r.callback.onCellInfoChanged(mCellInfo);
} catch (RemoteException ex) {
remove(r.binder);
}
}
There are other things from the code that look like CDMA will be calling the newer API. For example com.android.internal.telephony.cdma.CdmaLteServiceStateTracker seems to be dealing with CDMA and LTE. Again it would require a more careful look but that should give you a good place to start.
You can also try to simulate that with the emulator.

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

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.

How to prevent name caching and detect bluetooth name changes on discovery

I'm writing an Android app which receives information from a Bluetooth device. Our client has suggested that the Bluetooth device (which they produce) will change its name depending on certain conditions - for the simplest example its name will sometimes be "xxx-ON" and sometimes "xxx-OFF". My app is just supposed to seek this BT transmitter (I use BluetoothAdapter.startDiscovery() ) and do different things depending on the name it finds. I am NOT pairing with the Bluetooth device (though I suppose it might be possible, the app is supposed to eventually work with multiple Android devices and multiple BT transmitters so I'm not sure it would be a good idea).
My code works fine to detect BT devices and find their names. Also, if the device goes off, I can detect the next time I seek, that it is not there. But it seems that if it is there and it changes name, I pick up the old name - presumably it is cached somewhere. Even if the bluetooth device goes off, and we notice that, the next time I detect it, I still see the old name.
I found this issue in Google Code: here but it was unclear to me even how to use the workaround given ("try to connect"). Has anyone done this and had any luck? Can you share code?
Is there a simple way to just delete the cached names and search again so I always find the newest names? Even a non-simple way would be good (I am writing for a rooted device).
Thanks
I would suggest 'fetchUuidsWithSdp()'. It's significance is that, unlike the similar getUuids() method, fetchUuidsWithSdp causes the device to update cached information about the remote device. And I believe this includes the remote name as well as the SPD.
Note that both the methods I mentioned are hidden prior to 4.0.3, so your code would look l ike this:
public static void startServiceDiscovery( BluetoothDevice device ) {
// Need to use reflection prior to API 15
Class cl = null;
try {
cl = Class.forName("android.bluetooth.BluetoothDevice");
} catch( ClassNotFoundException exc ) {
Log.e(CTAG, "android.bluetooth.BluetoothDevice not found." );
}
if (null != cl) {
Class[] param = {};
Method method = null;
try {
method = cl.getMethod("fetchUuidsWithSdp", param);
} catch( NoSuchMethodException exc ) {
Log.e(CTAG, "fetchUuidsWithSdp not found." );
}
if (null != method) {
Object[] args = {};
try {
method.invoke(device, args);
} catch (Exception exc) {
Log.e(CTAG, "Failed to invoke fetchUuidsWithSdp method." );
}
}
}
}
You'll then need to listen for the BluetoothDevice.ACTION_NAME_CHANGED intent, and extract BluetoothDevice.EXTRA_NAME from it.
Let me know if that helps.

Categories

Resources