Does anyone know a good way of programmaticaly checking if an Android device, phone or tablet, has voice capabilities?
By voice capabilities I mean capability to make phone calls. I know there are devices, like Galaxy tab in North America, that don't have this capability.
I haven't tried this myself, but it looks like the details you need would be in the TelephonyManager:
private boolean hasPhoneAbility()
{
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if(telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE)
return false;
return true;
}
I know this question was posted a long time ago, but I still thought I would post the solution I came up with that works for me so far, just so anyone with the same problem can benefit. (Because it seems like lots of people are having trouble finding a solution).
I just checked for the device's voicemail number, and obviously if it doesn't have one, then it is not a phone. In my code, to check this, it is tm.getVoiceMailNumber();
Here's what I did:
callButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String ableToMakePhoneCalls = tm.getVoiceMailNumber(); //check device for voicemail number (null means no voicemail number).
if(ableToMakePhoneCalls == null){ //If the device does not have voicemail, then it must not be a phone. So it can't call.
//I displayed an alert dialog box here
}
else{
String phoneNum = "tel:8885554444";
Intent intentPhone = new Intent(android.content.Intent.ACTION_CALL);
intentPhone.setData(Uri.parse(phoneNum));
startActivity(intentPhone);
}
}
});
In theory, you should be able to use Intent.resolveActivity to do this. There's a problem (described here) with Galaxy tabs in particular. They evidently report that they have calling capability. You can even resolve an intent successfully. Unfortunately, it resolves to a no-op activity.
I would assume that prepare() would fail if there is not mic available:
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setOutputFile(audio_file);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
mRecorder.prepare();
mRecorder.start();
} catch (Exception e) {}
Related
I have a xamarin project (API 28, soon to be 29), and I need to catch the event of bluetooth a2dp device.
I have a broadcast receiver with the following intent filter:
IntentFilter bluetoothFilter = new IntentFilter();
bluetoothFilter.AddAction(BluetoothDevice.ActionAclConnected);
bluetoothFilter.AddAction(BluetoothDevice.ActionAclDisconnectRequested);
bluetoothFilter.AddAction(BluetoothDevice.ActionAclDisconnected);
var btReciever = new BluetoothReceiver();
this.RegisterReceiver(btReciever, bluetoothFilter);
In my manisfest, I got the following permission:
<uses-permission android:name="android.permission.BLUETOOTH" />
In the Receiver.OnReceive, I got this code:
public override void OnReceive(Context context, Intent intent) {
String action = intent.Action;
BluetoothDevice device = (BluetoothDevice)intent.GetParcelableExtra(BluetoothDevice.ExtraDevice);
There I have a switch:
switch (action)
{
case BluetoothDevice.ActionFound:
Android.Util.Log.Debug(TAG, "Device Found");
//Device found
break;
case BluetoothDevice.ActionAclConnected:
Android.Util.Log.Debug(TAG, "Device Connected");
BluetoothAdapter.DefaultAdapter.GetProfileProxy(context, btsListener, ProfileType.A2dp);
Thread.Sleep(1500);
var manager = context.GetSystemService(Context.AudioService) as AudioManager;
var devices = manager.GetDevices(GetDevicesTargets.Outputs);
Android.Util.Log.Debug(TAG, "devices=" + devices.Length);
foreach (var dev in devices)
{
Android.Util.Log.Debug(TAG, "dev: id={0} name={1} type={2}", dev.Id, dev.ProductName, dev.Type);
if (dev.ProductName == device.Name)
{
if (dev.Type.ToString().Contains("a2dp"))
{
BluetoothAdapter.DefaultAdapter.GetProfileProxy(context, btsListener, ProfileType.A2dp);
}
Android.Util.Log.Debug(TAG, "Found output device");
}
}
//Device is now connected
break;
...
}
And I got a listener that implements the IBluetoothProfileServiceListener interface, and looks like this:
var btsListener = new BTServiceListener();
class BTServiceListener : AppCompatActivity, IBluetoothProfileServiceListener
{
public void OnServiceConnected([GeneratedEnum] ProfileType profile, IBluetoothProfile proxy)
{
if (profile == ProfileType.A2dp)
{
Android.Util.Log.Debug(TAG, "A2dp");
}
}
...
}
I need to catch the event onConnect of the bluetooth a2dp (and later headset), but I have no idea how exactly I should do it.
This code in the receiver, shows the bluetooth onConnect event (BluetoothDevice.ActionAclConnected in the switch), then I check the device list, there is not yet the connected device, then I wait 1500ms (I need somehow to improve this method, this cannot stay like this), for the audioService to add the actual a2dp device to the list, and in the for loop, I find the additional device via its name, and I am certain it is the right one. BUT, I have no programmaticaly way to find out what type of device was connected (remote, headset, a2bp...) other than to check is the name contains a2dp (see for loop)
After my research, I found this line:
BluetoothAdapter.DefaultAdapter.GetProfileProxy(context, btsListener, ProfileType.A2dp);
This uses the context, the listener, and the desierd type of device (see Listener: BTServiceListener ), the problem is, I don't know if the proxy in the listener is the same device as the device in the broadcast receiver onConnect, and I have no idea how to use that function.
So my questions:
How and when should I use the BluetoothAdapter.DefaultAdapter.GetProfileProxy function and be certain that I have the same device in the listener and in the onConnect function?
How to get all the devices from the manager without putting the thread to sleep? Because, without the Thread.Sleep, the actual device is not in the list because the onConnect function is called earlyer then the addition of the device to the audioService.
Thread.Sleep(1500); // <-- this needs to go
var manager = context.GetSystemService(Context.AudioService) as AudioManager;
var devices = manager.GetDevices(GetDevicesTargets.Outputs);
How should I distinguish between the device types? Because, I have a feeling that my method of String.Contains(string) is not the way to go
Sorry for the long question, thank you for your help and time.
Let me know, if you need anything else.
Is there any way in Java to detect if an Android device has an offline speech recognition language installed, and if it does not prompt the user to download it?
I know you can ask to speech to text to prefer offline speech to text, but how do you know if the device has the language installed?
This question is not on how to use offline speech, this works.
The question is "how to detect and download/install offline speech languages" from Java app code. i.e. have the app detect if they have offline German language installed, and if not prompt the user to download/install it.
This is not the answer you are hoping for, as at the time of writing, I don't believe there is a straight forward solution to this. I very much hope to be proved wrong.
I requested an enhancement to provide this information programmatically a long time ago - here
The enhancement suggested an additional parameter RecognizerIntent.EXTRA_SUPPORTED_OFFLINE_LANGUAGES:
It would surely be trivial for this to be added and used in the following way:
final Intent vrIntent = new Intent(RecognizerIntent.ACTION_GET_LANGUAGE_DETAILS);
getContext().sendOrderedBroadcast(vrIntent, null, new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
final ArrayList<String> vrStringLocales = intent.getExtras().getStringArrayList(
RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES);
// This would be nice
final ArrayList<String> vrStringOfflineLocales = intent.getExtras().getStringArrayList(
RecognizerIntent.EXTRA_SUPPORTED_OFFLINE_LANGUAGES);
}
}, null, 1234, null, null);
Alas, it has never happened.
You do have two other options to attempt to handle this gracefully.
In the unlikely event you application runs with root permissions, you can check the location of /data/data/com.google.android.googlequicksearchbox/app_g3_models/ which contains the offline files, labelled quite handily by their locale.
The second involves knowing when the user needs a prompt to install the missing offline files.
From my experience, the recognition error of SpeechRecognizer.ERROR_SERVER most often denotes this, but it is not foolproof.
#Override
public void onError(final int error) {
switch (error) {
case SpeechRecognizer.ERROR_SERVER:
// TODO - prompt to install offline files
break;
}
}
When detected, you can guide the user to the correct installation screen.
public static final String PACKAGE_NAME_GOOGLE_NOW = "com.google.android.googlequicksearchbox";
public static final String ACTIVITY_INSTALL_OFFLINE_FILES = "com.google.android.voicesearch.greco3.languagepack.InstallActivity";
public static boolean showInstallOfflineVoiceFiles(#NonNull final Context ctx) {
final Intent intent = new Intent();
intent.setComponent(new ComponentName(PACKAGE_NAME_GOOGLE_NOW, ACTIVITY_INSTALL_OFFLINE_FILES));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
ctx.startActivity(intent);
return true;
} catch (final ActivityNotFoundException e) {
} catch (final Exception e) {
}
return false;
}
Using hard-coded values such as this, is of course not ideal, but neither is this situation!
Once you've messed around with all of the above and think you have a good interim solution - think again! Regardless of whether the user has correctly installed the missing offline files, it is highly likely it still won't work.....
My answer here describes the process I still have to guide my user's with. It's very frustrating.
Finally one more bug to throw into the mix - RecognitionListener.onError(int) can be thrown when there isn't an error. Check my gist from the answer here to use a BugRecognitionListener so you can check the callbacks are being sent in the correct order and ignore those that aren't. This remains a problem, despite my answer suggesting a fix in a previous release.
The above should keep you busy! Good luck....
To detect whether needed Language(German) is available, please follow below :
Iterate the Locale list and check whether Locale available for German language.
If you didn't get any Locale object in return, you can conclude that German language is not available offline. Then you can write code to download and do other stuff.
I did below implementation for my project. Hope below code helps you !!!
private TextToSpeech t1;
private void setForOtherLangAudio() {
Locale[] locales = Locale.getAvailableLocales();
Locale loc = null;
for (Locale locale : locales) {
// Replace XXX with your German codes
if (locale.getDisplayCountry().equals("XXX") && locale.getDisplayLanguage().equals("XXX")) {
loc = locale ;
break;
}
}
final Locale germanLocale = loc;
t1 = new TextToSpeech(getContext(), new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status != TextToSpeech.ERROR) {
t1.setLanguage(germanLocale);
}
}
});
}
I have a application which uses camera functionality in it but part of its functionality can also run without camera feature. SO I have put this in my manifest.
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="false"/>
and in my code I check whether the device has camera or not using this
final boolean deviceHasCameraFlag = pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);
Now I am testing my code on a tablet which runs Android 4.0(ICS) and has no camera. But still I get True value for the deviceHasCameraFlag. Is this weird or am I missing something.
I tried different things and even tried the same thing on Bluetooth feature as Tablet even doesn't have Bluetooth feature. It works fine for Bluetooth but gives me true for camera.
Which device is it? The answer you get is a bug, and 4.0 is very old nowadays. Many tablets that still run this version were not crafted correctly, both hardware and software featuring multiple problems.
Regardless, you should always be prepared to handle failure on Camera.open() or Camera.open(0): for example, in some cases other software on your device will not release the camera gracefully.
So, in your case you have a false positive, you try to open the camera, it fails, and you continue as if there is no camera on the device, even if PackageManager thinks that PackageManager.FEATURE_CAMERA is availabe.
Though I have accepted Alex's answer I still want to put this one collectively as what can be the best solution in such condition.
What I found was in case of some low standard android devices
pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)
returns true even if camera doesn't exist and that seems to be a device bug for me which in unchecked.
So whenever there is scenario that you need to check if camera exists for a device or not best practice is something that I am putting below (best practice as per my knowledge if there is something more interesting and best solution that this you are welcome to put it here on this post)
int numberOfCameras = Camera.getNumberOfCameras();
context = this;
PackageManager pm = context.getPackageManager();
final boolean deviceHasCameraFlag = pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);
if( !deviceHasCameraFlag || numberOfCameras==0 )
{
Log.e(TAG, "Device has no camera" + numberOfCameras);
Toast.makeText(getApplicationContext(), "Device has no camera", Toast.LENGTH_SHORT).show();
captureButton.setEnabled(false);
}
else
{
Log.e(TAG, "Device has camera" + deviceHasCameraFlag + numberOfCameras);
}
In this I am checking both number of cameras as well as device has camera feature Boolean , so in any case it would not fail my condition.
In my case I had this code:
public boolean hasCameraSupport() {
boolean hasSupport = false;
if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) { //<- this constant caused problems
hasSupport = true;
}
return hasSupport;
}
and it kept returning false on a Genymotion device running Android 4.1.1 (API 16). Once I changed the constant PackageManager.FEATURE_CAMERA_ANY to PackageManager.FEATURE_CAMERA, my problems went away. I am guessing that not all devices/API levels support PackageManager.FEATURE_CAMERA_ANY.
I got it you will try this one definitely it will work....
import android.hardware.Camera;
int numCameras = Camera.getNumberOfCameras();
if (numCameras > 0) {
System.out.println("camera");
} else {
System.out.println("No Camera");
}
For CameraX, if the FEATURE_CAMERA_ANY method is still returning true when there is no Camera on device, you can add the below method. So whether FEATURE_CAMERA_ANY returns true or false when CameraX is getting initialized, Below method will make sure to do what you want if a camera is actually not available on device.
private CameraSelector cameraSelector;
private ProcessCameraProvider cameraAvailableCheck;
private ListenableFuture<ProcessCameraProvider> cameraAvailableCheckFuture;
private void checkIfAnyCameraExist()
{
cameraAvailableCheckFuture = ProcessCameraProvider.getInstance(context);
cameraAvailableCheckFuture.addListener(new Runnable() {
#Override
public void run() {
try {
cameraAvailableCheck = cameraAvailableCheckFuture.get();
if ((cameraAvailableCheck.hasCamera(cameraSelector.DEFAULT_BACK_CAMERA) || cameraAvailableCheck.hasCamera(cameraSelector.DEFAULT_FRONT_CAMERA) ))
{
//Do what you want if at least back OR front camera exist
}
else
{
//Do what you want if any camera does not exist
}
}
catch (ExecutionException | InterruptedException | CameraInfoUnavailableException e)
{
// No errors need to be handled for this Future.
// This should never be reached.
}
}
}, ContextCompat.getMainExecutor(this));
}
Please try this code:
private boolean isDeviceSupportCamera() {
if (getApplicationContext().getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CAMERA)) {
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
Still it does't work then please let me know
i want to set the system preference (by code) for just using 2g networks instead of using 3g. so far i haven't found anything that could have helped me. i suppose i need to set it via the ConnectionManager? can anyone point me in the right direction here?
Unfortunately, you can't do this. The best you can do is take the user to the relevant settings screen (Mobile Network Settings), where they can choose for themselves. There's no API to actually change the setting.
Some ROMs (e.g. CyanogenMod) build this into the system, and there may be options if you are rooted/installed as a system app, but if you want something standard/mass applicable then I'm afraid you're out of luck.
use the following code
public class CheckNetworkType extends Activity
{
private static final String tag = "CheckNetworkType";
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
if(tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_EDGE )
{
// Network type is 2G
Log.v(tag, "2G or GSM");
}
else
if(tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_CDMA)
{
// Network type is 2G
Log.v(tag, "2G or CDMA");
}
else
if(tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_UMTS)
{
// Network type is 3G
Log.v(tag, "3G Network available.");
}
}
}
I am trying to write an app that requires the LED flash to go into torch mode. The problem is, Android 2.1 does not support this mode and therefore I cannot support the platform yet. Wouldn't be an issue, but I am writing it for my fiance and her Epic 4G only has 2.1 right now. I found some code samples that use some undocumented API calls and therefore work on the Motorola Droid and such, but they do not work on the Epic. Does anyone have some suggestions on where to look to find code that should help me get this working?
I'm finding that torch mode is generally working fine on 2.1 but I had the same problem with the Samsung Epic and found a hack around it.
Looking at the params returned by Camera.getParameters() when run on the Samsung Epic, I noticed that the flash-modes it claims to support are: flash-mode-values=off,on,auto;
torch-mode is not listed, implying it's not supported.
However, I found that this model would still accept that mode and WOULD turn the LED on! The bad news was that when later setting the flash-mode back to auto or off left the LED still lit! It will not turn off until you call Camera.release().
I guess that's why Samsung dont include it in the list of supported!?!
So...the method I use to toggle torch in a CameraHelper class is...
/***
* Attempts to set camera flash torch/flashlight mode on/off
* #param isOn true = on, false = off
* #return boolean whether or not we were able to set it
*/
public boolean setFlashlight(boolean isOn)
{
if (mCamera == null)
{
return false;
}
Camera.Parameters params = mCamera.getParameters();
String value;
if (isOn) // we are being ask to turn it on
{
value = Camera.Parameters.FLASH_MODE_TORCH;
}
else // we are being asked to turn it off
{
value = Camera.Parameters.FLASH_MODE_AUTO;
}
try{
params.setFlashMode(value);
mCamera.setParameters(params);
String nowMode = mCamera.getParameters().getFlashMode();
if (isOn && nowMode.equals(Camera.Parameters.FLASH_MODE_TORCH))
{
return true;
}
if (! isOn && nowMode.equals(Camera.Parameters.FLASH_MODE_AUTO))
{
return true;
}
return false;
}
catch (Exception ex)
{
MyLog.e(mLOG_TAG, this.getClass().getSimpleName() + " error setting flash mode to: "+ value + " " + ex.toString());
}
}
The activities that use this call it as follows...
private void toggleFlashLight()
{
mIsFlashlightOn = ! mIsFlashlightOn;
/**
* hack to fix an issue where the Samsung Galaxy will turn torch on,
* even though it says it doesnt support torch mode,
* but then will NOT turn it off via this param.
*/
if (! mIsFlashlightOn && Build.MANUFACTURER.equalsIgnoreCase("Samsung"))
{
this.releaseCameraResources();
this.initCamera();
}
else
{
boolean result = mCamHelper.setFlashlight(mIsFlashlightOn);
if (! result)
{
alertFlashlightNotSupported();
}
}
}
The magic that makes this work in releaseCameraResources() is that it calls Camera.release()....and then I have to reinitialize all my camera stuff for Samsung devices.
Not pretty but seems to be working for plenty of users.
Note that I do have a report of torch mode not working at all with this code on Nexus one but have been able to dig into it. It definitely works on HTC EVO and Samsung Epic.
Hope this helps.
In my case for Samsung devices I needed to set focus mode to infinity and it started to work
params.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
mCamera.setParameters(params);
mCamera.startPreview();