Xamarin Bluetooth Scan - c#

today i started developing with C# and i tried to scan for a beacon.
This is how far i came..
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
BluetoothAdapter oBluetoothAdapter = BluetoothAdapter.DefaultAdapter;
BluetoothLeScanner oScanner = oBluetoothAdapter.BluetoothLeScanner;
ScanCallback oCallback;
if(!oBluetoothAdapter.IsEnabled)
{
StartActivity(new Intent(BluetoothAdapter.ActionRequestEnable));
}
else
{
oScanner.StartScan(oCallback);
}
}
The Problem is that i dont know how to use the Callback Parameter of the StartScan function. Can sombody please tell me how to use the callback right ?

On android the implementation would be something like this:
_Manager = (BluetoothManager)appContext.GetSystemService("bluetooth");
_Adapter = _Manager.Adapter;
_LeScanner = _Adapter.BluetoothLeScanner;
_BluetoothScanCallback = new BluetoothScanCallback();
Then when you start your scan it would be something like this:
_LeScanner.StartScan(_BluetoothScanCallback);
where BluetoothScanCallback would be implemented using something like:
public class BluetoothScanCallback : ScanCallback
{
public override void OnScanResult([GeneratedEnum] ScanCallbackType callbackType, ScanResult result)
{
base.OnScanResult(callbackType, result);
}
}

Related

Xamarin Android: Set ExpandableListView.SetOnGroupExpandListener

I want to set a listener for ExpandableList. I have searched around but found only android specific following code. How can I convert the following android code to Xamarin.
ExpandableList expListView; // suppose it is initilized
expListView.setOnGroupExpandListener(new IOnGroupExpandListener() {
int previousItem = -1;
#Override
public void onGroupExpand(int groupPosition)
{
if (groupPosition != previousItem)
expandableList.collapseGroup(previousItem);
previousItem = groupPosition;
}
});
You can implement the interface ExpandableListView.IOnGroupExpandListener on the Activity (or Fragment) or as a separate Java-based object.
Activity Example:
public class MainActivity : Activity, ExpandableListView.IOnGroupExpandListener
{
~~~
ExpandableListView expListView;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
expListView.SetOnGroupExpandListener(this);
}
~~~
public void OnGroupExpand(int groupPosition)
{
// implement your onexpand code
}
~~~
}
Separate Class:
public class MyExpander : Java.Lang.Object, ExpandableListView.IOnGroupExpandListener
{
public void OnGroupExpand(int groupPosition)
{
// implement your onexpand code
}
}

Discovering list of Bluetooth devices in Xamarin.Android

Following multiple forums and sites telling the same thing on how to discover Bluetooth devices (paired or unpaired) I wrote down this piece of code.
class MainActivity: Activity
{
BluetoothAdapter btAdapter;
static ArrayAdapter<string> newDevicesArrayAdapter;
public static List<string> mDeviceList = new List<string>();
DeviceDiscoveredReceiver receiver;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
receiver = new DeviceDiscoveredReceiver(this);
IntentFilter filter = new IntentFilter(BluetoothDevice.ActionFound);
RegisterReceiver(receiver, filter);
btAdapter = BluetoothAdapter.DefaultAdapter;
}
class DeviceDiscoveredReceiver : BroadcastReceiver
{
Activity mainActivity;
public DeviceDiscoveredReceiver(Activity activity)
{
this.mainActivity = activity;
}
public override void OnReceive(Context context, Intent intent)
{
String action = intent.Action;
if (BluetoothDevice.ActionFound.Equals(action))
{
BluetoothDevice device = (BluetoothDevice)intent.GetParcelableExtra(BluetoothDevice.ExtraDevice);
mDeviceList.Add(device.Name + ";" + device.Address);
var path = Android.OS.Environment.ExternalStorageDirectory + Java.IO.File.Separator + "Download";
string filename = Path.Combine(path, "myfile.txt");
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
using (StreamWriter objStreamWriter = new StreamWriter(filename, true))
{
objStreamWriter.WriteLine(mDeviceList.Last());
objStreamWriter.Close();
}
}
}
}
}
Here, the Activity class has a BroadcastReceiver class where any discovered Bluetooth device's Name with MAC address gets written down to a .txt file. I am very new to Xamarin and new to android and here are the things I am confused with:
I am wondering how can I get a list containing all the Bluetooth
devices?
How can I start the "get Bluetooth devices" event?
Am I missing something in the codes? because nothing happens when I
launch it inside my android smartphone.
My main goal here is to just start discovering the Bluetooth devices but how?
Ok, it was easy but as I was new, it took some time to get it around my head. I missed the SetContentView(Resources.Layout.Main) inside the OnCreate method so simply change the OnCreate method to this:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resources.Layout.Main); //add this line
receiver = new DeviceDiscoveredReceiver(this);
IntentFilter filter = new IntentFilter(BluetoothDevice.ActionFound);
RegisterReceiver(receiver, filter);
btAdapter = BluetoothAdapter.DefaultAdapter;
}

Passing a string from an event to MainActivity in Android Xamarin Visual Studio

The project is done in Visual Studio with Xamarin and targeted for Android.
In my simple project I have 1 activity (MainActivity). Here I create an instance of a Scanner object that will sit in background and listen for iBeacons. Once the scanner has been created I call a Start method on the scanner object.
In the constructor of the Scanner object, there will be setup an instance of a Listener object. This instance is called when ever a beacon is detected.
Cut short – my main activity makes an instance of a scanner object. On creation of the scanner object a listener object is created. This listener object will be activated when a beacon is detected.
In my MainActivity I have a multiline TextView. I want it to show the beacons found in the listener object.
What is the best way to pass this beacon ID (string) to the TextView in the main activity?
I’m new to programming in Android, so all the different concepts with blocks, intents and what have you, are a bit confusing. I would have thought it was straight forward passing data from a listener event to the TextView but this has proven more difficult then expected.
I don’t mind going slow – so please feel free to elaborate and consider me the novice I am :-D
UPDATE:
I have edited the code to make it as short as possible, and pasted it below. Hope this gives an idea.
[Activity(Label = "DeviceScanSample", MainLauncher = true, Icon = "#mipmap/icon")]
public class MainActivity : Activity
{
KontaktScanner scanner;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
// Initialize Scanner
scanner = new KontaktScanner(this);
// Button actions
startScanButton.Click += delegate
{
if (CheckPermission(Manifest.Permission.AccessCoarseLocation))
{
// Start devices scan
scanner.Start();
}
else
{
// Ask for permissions if needed
...
}
};
}
}
public class KontaktScanner : Java.Lang.Object, IOnServiceReadyListener
{
IProximityManager proximityManager;
public KontaktScanner(Context context)
{
// Set Space listener
proximityManager.SetSpaceListener(new KontaktSimpleSpaceListener());
}
public void Start()
{
proximityManager.Connect(this);
}
}
class KontaktSimpleSpaceListener : SimpleSpaceListener
{
public void OnRegionEntered(IBeaconRegion beaconRegion)
{
Log.Info(TAG, string.Format("Entered {0} region", beaconRegion.Identifier));
}
public void OnRegionAbandoned(IBeaconRegion beaconRegion)
{
Log.Info(TAG, string.Format("Abandoned {0} region", beaconRegion.Identifier));
}
}
Try something like this:
Pass the context here:
public KontaktScanner(Activity activity)
{
// Set Space listener
proximityManager.SetSpaceListener(new KontaktSimpleSpaceListener(activity));
}
Then:
class KontaktSimpleSpaceListener : SimpleSpaceListener
{
Activity context
public KontaktSimpleSpaceListener(Activity activity)
{
this.context = activity;
}
public void OnRegionEntered(IBeaconRegion beaconRegion)
{
Log.Info(TAG, string.Format("Entered {0} region", beaconRegion.Identifier));
MainActivity myActivity = (MainActivity) context;
myActivity.updateTextView("My Data");// pass the string here.
}
public void OnRegionAbandoned(IBeaconRegion beaconRegion)
{
Log.Info(TAG, string.Format("Abandoned {0} region", beaconRegion.Identifier));
MainActivity myActivity = (MainActivity) context;
myActivity.updateTextView("My another data");// pass the string here.
}
}
Then create method in MainActivity:
public void updateTextView(string s)
{
RunOnUiThread(() =>
{
yourTextView.Text = s;//set your TextView here
});
}
I have not checked the syntax but something like this should work.

You MUST call Xamarin.Forms.Init(); prior to using it

In my app.xaml.cs I create a new page.
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new WrapLayoutPage());
}
This page calls a static class, which uses the DependencyService to perform some tasks.
The line which throws the error:
var tmpTable = SqLiteHelper.GetItem<TableX>("someId");
SqLiteHelper:
public static class SqLiteHelper
{
private static readonly SQLiteConnection DatabaseConnection = DependencyService.Get<ISqLite>().GetConnection();
private static readonly object Locker = new object();
public static DbObjectV3 GetItem<T>(Guid inId) where T : DbObjectV3, new()
{
lock (Locker)
{
var tmpItem = DatabaseConnection.Table<T>().FirstOrDefault(inItem => inItem.Id == inId);
tmpItem.IsNewObject = false;
return tmpItem;
}
}
}
This throws me a TypeInitializationException with the InnerException:
You MUST call Xamarin.Forms.Init(); prior to using it
It's somehow related to the static helper class, because prior to that call, I can use the DependencyService without any problems!
As mainlauncher I'm using a splash screen. In this class I do some startup work, which relies on the DependencyService.
SplashScreen:
[Activity(Theme = "#style/MyTheme.Splash", NoHistory = true, MainLauncher = true)]
public class SplashScreen : Activity
{
static readonly string TAG = "X:" + typeof(SplashScreen).Name;
public override void OnCreate(Bundle savedInstanceState, PersistableBundle persistentState)
{
base.OnCreate(savedInstanceState, persistentState);
Log.Debug(TAG, "SplashActivity.OnCreate");
}
}
My MainActivity:
[Activity(Label = "FrameworkForms", Icon = "#drawable/icon", ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation, Theme = "#style/MainActivityTheme", MainLauncher = false)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
Xamarin.Forms.Forms.Init(this, bundle);
App.ScreenWidth = (double)(Resources.DisplayMetrics.WidthPixels / Resources.DisplayMetrics.Density);
LoadApplication(new App());
}
}
Now after changing the Activity in SplashScreen to FormsAppCompatActivity, I get another error.
Call Forms.Init() before Hide Keyboard
What's the thing here?
This is pretty unfortunate. I used the wrong OnCreate() method in my SplashScreen.
I changed SplashScreen to:
[Activity(Theme = "#style/MyTheme.Splash", NoHistory = true, MainLauncher = true)]
public class SplashScreen : Activity
{
static readonly string TAG = "X:" + typeof(SplashScreen).Name;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Forms.Forms.Init(this, savedInstanceState);
Log.Debug(TAG, "SplashActivity.OnCreate");
}
protected override void OnResume()
{
base.OnResume();
Task tmpStartupWork = new Task(() =>
{
Log.Debug(TAG, "Performing some startup work that takes a bit of time.");
StartUpTasks.InitializeDatabaseCreation();
Log.Debug(TAG, "Working in the background - important stuff.");
});
tmpStartupWork.ContinueWith(inT =>
{
Log.Debug(TAG, "Work is finished - start MainActivity.");
StartActivity(new Intent(Application.Context, typeof(MainActivity)));
}, TaskScheduler.FromCurrentSynchronizationContext());
tmpStartupWork.Start();
}
}
Unfortunately, the documentation on Xamarin about creating a splash screen uses the OnCreate() method with 2 parameters!
I also came across this mistake. The cause of the error was that I wanted to change my namespace. From
public partial class AppDelegate :
global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
I changed it to:
using Xamarin.Forms.Platform.iOS;
public partial class AppDelegate : FormsApplicationDelegate
Then I saw the following:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
I thought, it would be useful to adjust that as well... without thinking more exactly about it. And I wrote:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
this.Init();
A while later, I got the mistake and had to laboriously search for the cause. Finally I found and fixed it. Maybe it can help someone :-) Cheers...

Mono for Android Location using C# & VS 2010

I am trying to create a simple app to get user coordinates on an Android phone using VS 2010 and Mono for Android. All samples seem to be in java which, as I'm not a java developer, is confusing. If anyone has some sample code using only C# it would be much appreciated.
You can create a listener by implementing the ILocationListener interface. This is a sample for an activity that also acts as a location listener (though it can be a separate class if you want too):
[Activity(Label = "Location Demo")]
public class LocationActivity : Activity, ILocationListener
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
var locationManager = (LocationManager)GetSystemService(LocationService);
var criteria = new Criteria { Accuracy = Accuracy.NoRequirement };
string bestProvider = locationManager.GetBestProvider(criteria, true);
locationManager.RequestLocationUpdates(bestProvider, 5000, 2, this);
}
public void OnLocationChanged(Location location)
{
}
public void OnProviderDisabled(string provider)
{
}
public void OnProviderEnabled(string provider)
{
}
public void OnStatusChanged(string provider, Availability status, Bundle extras)
{
}
}
I have a similar sample up here that reads in the coordinates and prints them to the screen.

Categories

Resources