I wrote an android utility that talks to a few custom device over USB using the android UsbHost API. This works fine in 4.4, but in 5.0 some of the devices are missing their interfaces (getInterfaceCount() == 0).
I've been using them on a Galaxy Note 3 with CM11 and they've been working fine, but since this version of CM is unstable I tried to upgrade to CM12. The problem appeared, and I thought it might be a CM bug so I tried a simple program that enumerates devices/interfaces on a Nexus 5 with google's 5.0 release and the problem exists there too.
I created a simple test app with a Button and TextView with an OnClickListener set up as:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_usb);
Button button = (Button) findViewById(R.id.butt);
final TextView text = (TextView) findViewById(R.id.text);
final UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String string = "";
if( manager == null )
string += "no usb manager";
else {
for(UsbDevice device : manager.getDeviceList().values()) {
string += device.toString() + "\n";
string += String.format(" ifc: %d\n", device.getInterfaceCount());
}
}
text.setText(string);
}
});
}
The devices are hooked into a hub which is plugged into the phone with an OTG cable. When this code is run on 5.0, the devices are listed but only one device in the list actually has interfaces (and it is not always the same device). If I shell into the phone with ADB, however, I can see all the devices and their interfaces with 'cat /sys/kernel/debug/usb/devices'.
Is this a bug in android 5.0, or has the usb api changed and I am missing something? I haven't been able to find any information online.
Turns out it is a bug introduced in 5.0. There's an issue on androids bug tracker:
https://code.google.com/p/android/issues/detail?id=159529&q=usb%20interface&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars
So it's been known about since 5.0, but currently there has been no work (or even comments) from google about it.
Related
I am working on Amazon FireTV. Is there any API so that i can differentiate whether its a FireTV or FireStick. like
String modal = android.os.Build.Modal;
if(modal.equals(FireTV)){ }else if(modal.equals(FireStick)){ }
Any help will be appreciated.
You can check the Model name:
public String MODELNAME = android.os.Build.MODEL;
public boolean ISFIRETV = MODELNAME.equalsIgnoreCase("AFT*");
public boolean ISFIRETVSTICK = MODELNAME.equalsIgnoreCase("AFTM");
All Fire TV devices have a model name which starts with "AFT":
FireTV (2nd Gen) is "AFTS"
FireTV (1st Gen) is "AFTB"
FireTV Stick is "AFTM".
ISFIRETV can then be used to ensure that it is a FireTV device of any kind (and not for instance sideloaded onto a non-Fire TV device), and then ISFIRETVSTICK can be used to specifically check if it is a FireStick or not.
Besides of answer below there is one more way to check it:
final String AMAZON_FEATURE_FIRE_TV = "amazon.hardware.fire_tv";
if (getPackageManager().hasSystemFeature(AMAZON_FEATURE_FIRE_TV)) {
Log.v(TAG, "Yes, this is a Fire TV device.");
} else {
Log.v(TAG, "No, this is not a Fire TV device.");
}
According to documentation this is the recommended way. But to use it you should have a Context.
After flashing my Nexus 5 to the Android 5.0 preview release hammerhead-lpx13d, the OS reports that it no longer supports Bluetooth LE advertising. If you call:
((BluetoothManager) this.getSystemService(Context.BLUETOOTH_SERVICE))
.getAdapter().getBluetoothLeAdvertiser()
always returns null. In addition, the new method:
((BluetoothManager) this.getSystemService(Context.BLUETOOTH_SERVICE))
.getAdapter().isMultipleAdvertisementSupported()
always returns false
The first method used to return a valid object on the first Android L preview release for the Nexus 5 back in June. It no longer does, after flashing the latest update.
Does anybody see otherwise?
EDIT: This has been reproduced by at least one person, who opened an issue with Google here: https://code.google.com/p/android-developer-preview/issues/detail?id=1570
Unfortunately, the official answer from Google is no, the Nexus 5 no longer supports advertising.
We introduced BLE peripheral mode in Android 5.0 Lollipop. Nexus 6 and
Nexus 9 are the first two production Nexus devices that support BLE
peripheral mode. Due to hardware chipset dependency, older Nexus
devices (4/5/7) will not have access to the feature on Lollipop.
See Comment #52 on issue 1570 by danielho...#google.com: BLE advertise mode not working
https://code.google.com/p/android-developer-preview/issues/detail?id=1570
That said, I have confirmed that advertising is supported by the Nexus 9 tablet. See here for details: http://developer.radiusnetworks.com/2014/11/18/beacon-transmission-with-android-5.html
This is not full a solution, but a proposed work-around posted by mattprec on Google Code. It allows you to get a BluetoothLeAdvertiser instance by calling the private constructor rather than using the public API. Unfortunately, reports of testing on a Nexus 5 and a Nexus 7 2013 edition say that even after you get an instance you can't use the object to make advertisements come out. Also, be warned that even if you can get it to work, it might break on any minor code release of Android because it is using a non-public API.
For the record, here's the code snippet copied from that page:
private static BluetoothLeAdvertiser getAdvertiserHack(BluetoothAdapter adapter) {
try {
Class<? extends BluetoothAdapter> adapterClass = adapter.getClass();
Field advertiserField = adapterClass.getDeclaredField("sBluetoothLeAdvertiser");
advertiserField.setAccessible(true);
Object advertiser = advertiserField.get(adapter);
if (advertiser == null) {
Field bluetoothManagerServiceField = adapterClass.getDeclaredField("mManagerService");
bluetoothManagerServiceField.setAccessible(true);
Object bluetoothManagerService = bluetoothManagerServiceField.get(adapter);
Constructor<?> constructor = BluetoothLeAdvertiser.class.getDeclaredConstructor(
bluetoothManagerServiceField.getType());
constructor.setAccessible(true);
advertiser = constructor.newInstance(bluetoothManagerService);
advertiserField.set(adapter, advertiser);
}
return (BluetoothLeAdvertiser) advertiser;
} catch (Exception e) {
return null;
}
}
That said, I have confirmed that advertising is supported by the Nexus
9 tablet. See here for details:
http://developer.radiusnetworks.com/2014/11/18/beacon-transmission-with-android-5.html
QuickBeacon app is working fine on Nexus 9. In app there is a Beacon Format option.#davidgyoung Could you give exact String for BeaconParser to make this library transmit in iBeacon format?
UPDATE:
Related question up to android-beacon-library/BLE Android SDK. Is there possibility - without calling startAdvertising method - to check if there is advertising service running in background?
UPDATE:
Recording to this : https://code.google.com/p/android-developer-preview/issues/detail?id=1570#c52
Now only Nexus 6 and Nexus 9 supports BLE Peripheal Mode in Android 5.0
UPDATE:
I work on Nexus 5 Android 5.0 build number LPX13D
according to this https://stackoverflow.com/a/26611779/1906420
After implementig your workaround bluetoothAdvertiser is not null. Calling startAdvertising from bluetoothAdvertiser
bluetoothAdvertiser.startAdvertising(settingsBuilder.build(), dataBuilder.build(), advertiseCallback);
where
private AdvertiseCallback advertiseCallback = new AdvertiseCallback() {
#Override
public void onStartSuccess(AdvertiseSettings settingsInEffec) {
}
#Override
public void onStartFailure(int result) {
if (result == ADVERTISE_FAILED_DATA_TOO_LARGE) {
Log.d(TAG, "Failed to start advertising as the advertise data to be broadcasted is larger than 31 bytes.");
}
else if(result == ADVERTISE_FAILED_TOO_MANY_ADVERTISERS){
Log.d(TAG, "Failed to start advertising because no advertising instance is available.");
}
else if(result == ADVERTISE_FAILED_ALREADY_STARTED){
Log.d(TAG, "Failed to start advertising as the advertising is already started.");
}
else if(result == ADVERTISE_FAILED_INTERNAL_ERROR){
Log.d(TAG, "Operation failed due to an internal error.");
}
else if(result == ADVERTISE_FAILED_FEATURE_UNSUPPORTED){
Log.d(TAG, "This feature is not supported on this platform.");
}
else {
Log.d(TAG, "There was unknown error.");
}
}
};
always give callback onStartFailure with error code 5 ( ADVERTISE_FAILED_FEATURE_UNSUPPORTED )
I need to use bluetooth headset with voice recognition, which almost works fine in some devices like S3, S4 and Samsung Grand. However, when I tried same on Nexus 7, I am getting
BluetoothHeadsetServiceJni : Failed to start voice recognition, status: 6
error when I am calling startVoiceRecognition() method. I am using the code from this SO page.
What are the possible reasons for this issue occur only in some devices? Is there any way to solve this issue?
Using shoe rat suggestion, modify the start method in the link and see if it will work.
public boolean start()
{
if (!mIsStarted)
{
mIsStarted = true;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB || "Nexus 7".equals(Build.MODEL)
{
mIsStarted = startBluetooth();
}
else
{
mIsStarted = startBluetooth11();
}
}
return mIsStarted;
}
I have been check as Narayan mentioned, I found BluetoothHeadset.STATE_AUDIO_CONNECTED does fire in nexus 7 as well some other ZTE devices, may be this is manufature fault or a that device does not support call and you are try to communicate via call_mode, I think there is only workaround to solve this issue
Nexus 7 does not support VoiceRecognition,becuase Nexus 7 does not support Bluetooth HFP(handsfreee profile) who contains VoiceRecognition.
You can find device Bluetooth info in https://www.bluetooth.org/tpg/listings.cfm.
Am i the only one having problems connecting to the bluetooth with startBluetoothSco? This works fine in all versions of Android except 4.4.2 (kitkat). Any suggestions? And yes, I have verified that I am connected to Bluetooth before I call this. Did something changed in 4.4.2?
Here is my code:
am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
am.setMode(AudioManager.MODE_IN_CALL);
am.setBluetoothScoOn(true);
am.startBluetoothSco();
Following your suggestion i did the following, but this is driving me nuts! What am I doing wrong. I have the listener in my MainActivity as follows...
private final BluetoothHandler.Listener mBluetoothListener = new BluetoothHandler.Listener() {
#Override
public void onConnectionComplete() {
final BluetoothHandler bluetoothHandler = mBluetoothHandler;
if (bluetoothHandler != null) {
am.setMode(AudioManager.MODE_IN_COMMUNICATION);
}
}
};
Then in my OnCreate I initialize the BluetoothHandler
if(mBluetoothHandler == null){
mBluetoothHandler = new BluetoothHandler(5000, mBluetoothListener);
} else {
mBluetoothHandler.stopSco();
mBluetoothHandler.stop();
mBluetoothHandler = null;
}
if (!mBluetoothHandler.isAudioConnected()) {
mBluetoothHandler.start(mContext);
}
The problem I'm having is that the listener doesn't detect when a BT device connects or even says that one is connected. Any suggestions? I appreciate your help...
The functionality of startBluetoothSco() changed between API 17 and API 18. In API 17, this function initiates a virtual call via SCO. In API 18, the function opens a raw SCO link. Some Bluetooth units will only respond to a virtual call.
Unfortunately it doesn't seem that Google have given us an option of choosing whether to open a virtual call or raw link so if you require a virtual call, you will need to ensure your app is built with API 17.
From the Android Developer reference:
"NOTE: up to and including API version JELLY_BEAN_MR1, this method
initiates a virtual voice call to the bluetooth headset. After API
version JELLY_BEAN_MR2 only a raw SCO audio connection is
established."
http://developer.android.com/reference/android/media/AudioManager.html#startBluetoothSco()
Which device do you use? I know that there is sometimes a Bluetooth problem with nexus devices (nexus 5 with kit at also) as described here:
http://www.androidpolice.com/2013/12/28/bug-watch-many-nexus-devices-still-suffer-from-assorted-bluetooth-issues/
Had the same problem with an app I was developming. Upong updating my phone to KitKat, the SCO connection to my car stopped working.
I finally come up with a solultion using a somehow private api in the bluetooth headset profile, while keeping my code compatible with API 19.
Fist I'm checking if current version is API 17, in that case, I use the standard startBluetoothSco from AudioManager, if not the case, I get the current BluetoothHeadset profile and use the following method to create the virtual call sco link (I can't take credit for this, I found it in the Google TalkBack application):
class BluetoothHeadsetCompatWrapper {
private static final Class<?> CLASS_BluetoothHeadset = BluetoothHeadset.class;
private static final Method METHOD_startScoUsingVirtualVoiceCall = CompatUtils.getMethod(
CLASS_BluetoothHeadset, "startScoUsingVirtualVoiceCall", BluetoothDevice.class);
private static final Method METHOD_stopScoUsingVirtualVoiceCall = CompatUtils.getMethod(
CLASS_BluetoothHeadset, "stopScoUsingVirtualVoiceCall", BluetoothDevice.class);
private final BluetoothHeadset mHeadset;
public BluetoothHeadsetCompatWrapper(BluetoothHeadset headset) {
mHeadset = headset;
}
public boolean startScoUsingVirtualVoiceCall(BluetoothDevice device) {
return (Boolean) CompatUtils.invoke(mHeadset, false, METHOD_startScoUsingVirtualVoiceCall,
device);
}
public boolean stopScoUsingVirtualVoiceCall(BluetoothDevice device) {
return (Boolean) CompatUtils.invoke(mHeadset, false, METHOD_stopScoUsingVirtualVoiceCall,
device);
}
}
I found this solution when I was looking into the BluetoothHeadset code and found out the method actually exists, but it's hidden to the compiler https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/bluetooth/BluetoothHeadset.java
I know my anwser may be late, but I posted anyway to help others.
After reading the dot42 comments and trolling Java examples I managed to setup a Bluetooth connection but fail to open the connection. I cannot determine the problem. I followed the docs step by step.
My target device is a HTC Explorer running on 2.3 Gingerbread. Here is my code.
//Target 2.3 (Gingerbread)
[assembly: Application("dot42Application1")]
[assembly: UsesPermission(Android.Manifest.Permission.BLUETOOTH)]
[assembly: UsesPermission(Android.Manifest.Permission.BLUETOOTH_ADMIN)]
namespace dot42Application1
{
[Activity]
public class MainActivity : Activity
{
private TextView txStatus;
protected override void OnCreate(Bundle savedInstance)
{
base.OnCreate(savedInstance);
SetContentView(R.Layouts.MainLayout);
// Find UI controls
txStatus = FindViewById<TextView>(R.Ids.txStatus);
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
var bt = BluetoothAdapter.GetDefaultAdapter();
if (bt != null) //If device has not Bluetooth this will be null
{
if (bt.IsEnabled()) //Is Bluetooth device enabled?
{
var BT_My_Addr = bt.Address; //Get the devices MAC
var BT_Bonded = bt.GetBondedDevices().ToList(); //Get a list of bonded devices- I bonded to a BT2TTL Board earlier.
txStatus.Text = BT_My_Addr + System.Environment.NewLine; //Shows my MAC on screen.
string BT_Remote_Address = string.Empty;
foreach (var BTDevice in BT_Bonded) //Just searchging for string in bonded list
{
if (BTDevice.Name.Contains("linvor"))
{
BT_Remote_Address = BTDevice.Address;
}
}
//Gets remote device
var BT_Remote_Device = bt.GetRemoteDevice(BT_Remote_Address);
//Create a RFCOMM Socket to remote device using popular UUID ofr BT Serial boards
var BTsocket = BT_Remote_Device.CreateInsecureRfcommSocketToServiceRecord(Java.Util.UUID.FromString("00001101-0000-1000-8000-00805F9B34FB"));
//Call anyway to make sure there is no discvoerry in the backgorund. It slows stuff down.
bt.CancelDiscovery();
//Exception here? Dont know why :(
BTsocket.Connect();
//Suppsoed to dump 0 to 99999 to my listening serial device but I never get this far.
var BT_Out = BTsocket.GetOutputStream();
for (int i = 0; i < 99999; i++)
{
BT_Out.Write(Encoding.ASCII.GetBytes(i.ToString()));
}
}
else
{
txStatus.Text = "Bluetooth is disabled :(";
}
}
}
}
And this is what it shows after the socket creation
and the error...
What am I doing wrong? :(
I seem to have solved the problem by analysing various code snippets on the internet. I think the problem was trying to do everything in the OnCreate method. The steps I followed are the following:
Created a button on the main view (MainActivity.xml) and attached a onClick method.
Moved all the code OUT of the OnCreate method. (I think this allows the application to fully initialise.) Created an event handler for the button with two methods.
The two methods are the same as the code I posted in my original question. Just they are separated out and called when the user clicks the button.
findBT() Gets the default adapter. Checks if Bluetooth is enabled if not does the intent filter. Or if it is it will cycle through the bonded list and match a device name and store the BluetoohDevice in a variable. This is another thing that is different from my code. I do not use GetRemoteDevice I just assign the device from the BondedList to my global variable.
openBT() creates the RFCOMM socket (this did not work with unsecure - it threw an exception but using the secure method worked!)
You have to pair to the remote device using the Androids Bluetooth control panel. This code will not scan or connect to devices that are not paired. It will just throw null exceptions.
Also I left the target SDK 2.3.x but I am using the 4.x API.
-Disclosure. I am not a seasoned Android developer and just learning about the life cycle of Java applications in the Android context. I hope this can help other C# developers trying to do the same.