Android 12 - Beacon scanning... weirdest thing - bluetooth

Ok so here is my situation:
I have my app installed. It is now targeting Android 12.
I also have Kontakt.io Android sample app installed.
When I use Kontakt.io's sample app to scan for beacons, it works. Among other devices, I can see my beacons appear in the list and logs.
When I use the same exact code (from their sample app) in my app with exactly the same configuration and exactly the same permission scheme I am unable to scan my beacons. I can see in Logcat there are a lot of other devices that are being scanned and reported but none of my beacons are scanned.
Then - and here is the weird thing - while my app is in the background, I switch back to Kontakt.io sample app and initiate a new scan. The second I start that scan, MY app suddenly starts seeing my beacons and I can see them in the logs. If I shut down that Kontakt.io sample app scan, I can still see the beacons appear in my app's scan. If I kill both apps and try to scan again in my app alone, again, I cannot see my beacons any more.
I've been struggling with this for days now and it simply does not make any sense.
I'll add here that if I do not target API 31 (Android 12) everything is perfect. As it's been for the past few years.
Please! Any ideas?
EDIT1: adding some source code
The code is identical to the one in Kontakt.io's sample app. It is a simple copy paste:
In an activity, on a button click I call checkPermissions():
private void checkPermissions() {
String[] requiredPermissions = Build.VERSION.SDK_INT < Build.VERSION_CODES.S
? new String[]{Manifest.permission.ACCESS_FINE_LOCATION}
: new String[]{ Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.ACCESS_FINE_LOCATION };
if(isAnyOfPermissionsNotGranted(requiredPermissions)) {
ActivityCompat.requestPermissions(getScreen().getHostingActivity(), requiredPermissions, 100);
} else {
setupProximityManager();
setupSpaces();
}
}
private void setupProximityManager() {
proximityManager = ProximityManagerFactory.create(this);
//Configure proximity manager basic options
proximityManager.configuration()
//Using ranging for continuous scanning or MONITORING for scanning with intervals
.scanPeriod(ScanPeriod.RANGING)
//Using BALANCED for best performance/battery ratio
.scanMode(ScanMode.BALANCED)
//OnDeviceUpdate callback will be received with 5 seconds interval
.deviceUpdateCallbackInterval(TimeUnit.SECONDS.toMillis(5));
//Setting up iBeacon and Eddystone listeners
proximityManager.setIBeaconListener(createIBeaconListener());
proximityManager.setEddystoneListener(createEddystoneListener());
}
private void setupSpaces() {
//Setting up single iBeacon region. Put your own desired values here.
IBeaconRegion region = new BeaconRegion.Builder().identifier("My Region") //Region identifier is mandatory.
.proximity(UUID.fromString("f7826da6-4fa2-4e98-8024-bc5b71e0893e")) //Default Kontakt.io proximity.
//Optional major and minor values
//.major(1)
//.minor(1)
.build();
proximityManager.spaces().iBeaconRegion(region)
.forceResolveRegions(Collections.singleton(UUID.fromString("f7826da6-4fa2-4e98-8024-bc5b71e0893e")));
//Setting up single Eddystone namespace. Put your own desired values here.
IEddystoneNamespace namespace = new EddystoneNamespace.Builder().identifier("My Namespace") //Namespace identifier is mandatory.
.namespace("f7826da64fa24e988024") //Default Kontakt.io namespace.
//Optional instance id value
//.instanceId("instanceId")
.build();
proximityManager.spaces().eddystoneNamespace(namespace).forceResolveNamespaces(Collections.singletonList("f7826da64fa24e988024"));
}
On a different button click I call:
private void startScanning() {
//Connect to scanning service and start scanning when ready
proximityManager.connect(new OnServiceReadyListener() {
#Override
public void onServiceReady() {
//Check if proximity manager is already scanning
if (proximityManager.isScanning()) {
Toast.makeText(((Application)Application.getContextFromApplicationClass()).getActivityContext(), "Already scanning", Toast.LENGTH_SHORT).show();
return;
}
proximityManager.startScanning();
// progressBar.setVisibility(View.VISIBLE);
Toast.makeText(((Application)Application.getContextFromApplicationClass()).getActivityContext(), "Scanning started", Toast.LENGTH_SHORT).show();
}
});
}
androidmanifest.xml contains the needed permissions (copied from the sample app):
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
I already have a foreground service in my app if it makes any difference.
I also declared as instructed another service that is used by the Kontakt SDK:
<service
android:name="com.kontakt.sdk.android.ble.service.ProximityService"
android:exported="false" />
All the runtime permissions are requested in the same manner they are requested in the Kontakt.io sample app and the actual permissionCheck passes.

Ok... so I found the cause. For years our app used 2 libraries: RxBleClient for scanning and AltBeacon for parsing the result. Not entirely sure why use 2 libs but that was the case. When we targeted API 12, I assume both libs overwrote some of the androidmanifest.xml permission declarations during merge in some manner. I did not dive deep into the actual cause, but this seems to be the issue. At any rate, to resolve the issue, we removed ALL libs that relate to beacon scanning and put a single one. Currently we picked Kontakt.io SDK. Scanning is working now perfectly. This also explains why on their own, each sample app from each library was working as expected. But when you combine more than 1 lib and target api 31, they seem to interfere with each other and the "delicate" permissions required for BLE scanning in android. This problem took me waaaay to long to solve.

Related

Azure Speech Recognition not detecting microphone SPXERR_MIC_NOT_FOUND

I have a small sample application to test speech recog. It works in some machines but not in other machines. In my dev environment where I first installed the necessary packages, it all worked 100% with no issues. But, my team mates are unable to get it working with the installation of our software that has this code in it. We have mixed environments where in some cases we are using Remote Desktop with the application running on the remote machine (so with the device integration via RDP). And also locally without RDP. It does not detect the mic in both cases. Windows detects the mic. The recorder app works and testing all works so we know the mic is being recognized by windows.
However, the speech SDK does not recognize it.
I have tried 2 ways. First ,with using the FromDefaultMicrophoneInput But with that not working, i changed it to FromMicrophoneInput instead and specifed the microphone ID.
Using NAudio to enumerate the microphones, the mic is detected and listed:
var enumerator = new MMDeviceEnumerator();
string specifiedMicID = string.Empty;
foreach (var endpoint in
enumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active))
{
if (endpoint.FriendlyName != this.MicName)
continue;
else
{
specifiedMicID = endpoint.ID;
break;
}
}
audioConfig = AudioConfig.FromMicrophoneInput(specifiedMicID);
But, when trying to instantiate the SpeechRecognizer with that audio config:
using (var recognizer = new SpeechRecognizer(config, audioConfig))
{
...
}
We get the SPXERR_MIC_NOT_FOUND. Even thought it is clearly there and working in all other cases in windows and with Naudio detecting it fine.
Any ideas what is going on here?
Thank youj.
Are you creating a UWP application? If so, you'll need to retrieve the audio device IDs differently:
var devices = await DeviceInformation.FindAllAsync(DeviceClass.AudioCapture);
foreach (var device in devices)
{
Console.WriteLine($"{device.Name}, {device.Id}\n");
}
Please refer to the documentation here for more information:
https://learn.microsoft.com/en-us/azure/cognitive-services/speech-service/how-to-select-audio-input-devices#audio-device-ids-on-uwp
If you're still having issues, we'd need to get the SDK logs to debug further. Instructions on how to turn on logging can be found here:
https://learn.microsoft.com/en-us/azure/cognitive-services/speech-service/how-to-use-logging

Events not tracked in App Center

I am trying new Visual Studio App Center platform for mobile apps. It gives me the crashes and the installed versions OK, so the app secret and SDK are configured OK.
But when I try to track custom Events, according to this tutorial I get "No events found" in the Mobile Center dashboard. I try with my app in release and debug mode, without results.
My code (Xamarin.Forms):
public MyClass()
{
InitializeComponent();
Analytics.SetEnabledAsync(true);
Analytics.TrackEvent("Video clicked", new Dictionary<string, string> {
{ "Category", "Music" },
{ "FileName", "favorite.avi"}
});
}
There is the constructor, so I am sure that these lines are executed.
MobileCenter.Start needs to be called before Analytics.TrackEvent or Analytics.SetEnabledAsync.
If you are using constructor, then you need to move MobileCenter.Start to constructor as well.
Your solution is working probably because you made that code execute later (and thus after MobileCenter.Start) with async but you don't need to do that (and you don't need to call SetEnabledAsync at all, it's true by default and persisted).
Solved. I need to execute the lines in an async method, not in the constructor.

AppInsights instrumentation key is replaced when win universal app is published to Windows Store

I have a simple Windows Univeral Application with Azure Application Insights enabled in it. First published version worked well - all telemetry data was visible in AppInsights dashboard. But after I updated the app, strange thing happened - no telemetry data is generated at all.
After installing the version of the application from Windows Store, and tracing web requests with Fiddler, I've found out VERY strange thing - instrumentation key (iKey) sent in AppInsights requests is UNKNOWN for me. I mean that this is not a one of my AppInsights instances!
On the other hand, when I sideload the same package I've used for publish, than correct (expected) iKey is used in traced web requests.
This makes me think that my iKey is somehow replaced in published version of application. How is this possible?
IMPORTANT NOTE: AppInsights initialization code is the following (in App class):
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
var instrumentationKey =
#if DEBUG
Current.Resources["ApplicationInsights.InstrumentationKey.Debug"].ToString();
#else
Current.Resources["ApplicationInsights.InstrumentationKey.Release"].ToString();
#endif
Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync(instrumentationKey);
// ...
}
And one more time - this worked well in first version of the application and was broken only after update (wich did not touch any AppInsights related stuff).
UPDATE (2016-03-21): Following recommendations in the answers, I've done the following:
Moved release iKey into ApplicationInsights.config file
Changed initialization logic to replace the iKey only in case of Debug mode:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
var instrumentationKey = Current.Resources["ApplicationInsights.InstrumentationKey.Debug"].ToString();
await Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync(instrumentationKey);
#else
await Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync()
#endif
// ...
}
Republished the application to Windows Store.
Now AppInsights is working correctly - my iKey is used in AppInsights web requests and data appears in admin panel.
do you have an applicationinsights.config file in your project?
if you do not, I believe the store will create one for you so that the reports work, because it doesn't know you're setting the key in code. you might want to add an applicationinsights.config file, and put in one of your ikeys, even if you are then setting the key explicitly in code.
The ApplicationInsights SDK for Store apps, only works with ApplicationInsights.config.
The Store looks for this file, and if no instrumentation key is set, it injects one.
The SDK on the other hand, will always respect instrumentation key coming from the configuration file.

How do I get telemetry into a Windows 10 UWP App?

The Azure documentation for App Insights doesn't appear to have fresh articles relating to Windows 10 UWP Apps specifically. This appears to be endemic throughout all services (Notification Hub, Mobile Apps, Azure AD, etc.). So far I have found only references to Windows 8/8.1 Universal apps. I'm not sure how applicable they are but some code snippets do seem to compile at least.
My problem is that I have just setup a new App Insights instance for a 'WindowsStore App'. This is intended for a Windows 10 UWP app.
In my app, I have done the following:
Ingested the nuget package for App Insights which has created an ApplicationInsights.config file.
Updated the Instrumentation Key with the one from my WindowsStore App Insights Instance in the Azure Portal.
Added Internet (Client) capability in application manifest.
Created a static TelemetryClient that I use throughout all my Views / View Models.
private static TelemetryClient telemetry = new TelemetryClient();
public static TelemetryClient Telemetry
{
get { return telemetry; }
}
Updated the WindowsAppInitializer to include several WindowsCollectors.
Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync(
WindowsCollectors.Metadata |
WindowsCollectors.Session |
WindowsCollectors.PageView |
WindowsCollectors.UnhandledException
);
Added an event handler within App.xaml.cs for Unhandled Exception and call TelemetryClient.TrackException on the exception.
private void App_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
ViewModelDispatcher.Telemetry.TrackException(e.Exception);
}
Added TelemetryClient.TrackPageViews to OnNavigatedTo overrides in my views.
But so far, after doing all that, my App Insights dashboard in the Azure Portal is showing zip, zilch, nada. :\
This makes me think one of two things is going on. Either I am missing some critical piece of this recipe or I'm still within the refresh window for the App Insights Dashboard.
Have you tried to include your instrumentation key to the call of InitializeAsync?
I'm using the following code at the constructor of App class.
Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync(
"YOURINST-RUME-NTAT-IONK-EY012345678",
WindowsCollectors.Metadata |
WindowsCollectors.PageView |
WindowsCollectors.Session |
WindowsCollectors.UnhandledException);
I haven't confirmed the current specs (yes...the documentation of ApplicationInsight is an labyrinth :( ), but from AI v1.0, you have not to include your instrumentation key to your applicationinsight.config. Instead of it, you can specify the key with the call of initializer.
Recently found this (i work on the AI team and it still happened to me!).
If you manually added the applicationinsights.config file, make sure it is set to "Content" and "Copy if newer" in the project settings. If it isn't, then the sdk can't find the instrumentation key at runtime, since the applicationinsights.config file didn't get deployed to the device.
Update 1/11/2016: i just learned of another issue that can cause this: comments in the xml file that look like xml tags.
If your config file has any comments of the form:
<!-- <InstrumentationKey>anything</InstrumentationKey> -->
Or
<!--
Learn more about Application Insights configuration with ApplicationInsights.config here:
http://go.microsoft.com/fwlink/?LinkID=513840
Note: If not present, please add <InstrumentationKey>Your Key</InstrumentationKey> to the top of this file.
-->
(Like is common in examples you might have gotten online, or migrating from a previous version of the AI SDK's)
If those comments appear in your config file before your real key, then the win10 sdk startup code will find those in the comments instead of your real key.
So if you see debug output that says it is using the literal string "YourKey" instead your actual key, that's the reason. (The win10 sdk uses a regex to find your key instead of loading system.xml assemblies to parse the file)

API Breaks past 8-9 Devices?

It would seem that streaming breaks when there is too many devices in the account. After about 8 or 9 it just stops streaming data to me all together.
Are you using Firebase? I came on here to post a similar issue myself. If I change the temp through the nest device or the web tool, my Firebase listeners are updated. If I try to set a value, the value that I try to set is echoed back to my listener (like there has been an update on the thermostat even though it wasn't changed successfully) then, the correct value (unchanged) comes immediately after.
The weird thing is that it works.... then it just doesn't. Is this similar to what you've been experiencing?
Update:
Now it appears as if my listeners are not working either. I can query the server using REST successfully.
Update #2:
Now my listeners are working again but still no control.
Update#3:
Well... I think I see my problem at least. I don't know if it will help you (or me for that matter) but here it is...
protected void setHighTemp(int value){
fb.child("target_temperature_high_f").setValue(value, new CompletionListener() {
public void onComplete(FirebaseError arg0, Firebase arg1) {
System.out.println("Communicaiton error: " + arg0);
}
});
Output:
Communicaiton error: FirebaseError: Too many requests
I remember reading the following paragraph in https://developer.nest.com/documentation/glossary#client
Client
An integration of your application or service with Nest
devices. When you create a Nest account and sign up for the Developer
Program, you can add up to 10 clients to the account.
This might be your problem.

Resources