Getting native device information from BluetoothLE device - xamarin

I'm using the Plugin.BLE nuget package in my Xamarin project to interrogate the BLE devices I have. It seems to be working fine, but there is an object returned as part of the overall device object when the found device event is triggered. The object is called NativeDevice.
Intellisense is showing that this is an object which can be manipulated on the platform which is what I am trying to do so I can store and handle within my mvvm framework.
The problem is that if I cast the object as a Device on the platform and store that in a var, the var is always null.
How am I supposed to get the values from the object on the platform so I can pass these back to my view model?
My code looks like this
(in the forms project)
adapter.DeviceDiscovered += (s, a) =>
{
var adList = new List<AdvertisingRecords>();
foreach (var r in a.Device.AdvertisementRecords)
{
adList.Add(new AdvertisingRecords { Data = r.Data, Type = (AdvertisingRecordType)r.Type });
}
var newbtd = new BluetoothDevice
{
AdvertisementRecords = adList,
NativeDevice = DependencyService.Get<INativeDevice>().ConvertToNative(a.Device.NativeDevice),
Name = a.Device.Name,
Rssi = a.Device.Rssi,
Id = a.Device.Id,
State = (BluetoothStates)a.Device.State
};
btd.Add(newbtd);
};
On the platform
[assembly: Xamarin.Forms.Dependency(typeof(NativeDeviceConverter))]
namespace MyApp.Droid.Injected
{
public class NativeDeviceConverter : INativeDevice
{
public NativeDevice ConvertToNative(object device)
{
var dev = device as Device;
if (dev != null)
return new NativeDevice { Name = !string.IsNullOrEmpty(dev.BluetoothDevice.Name) ? dev.BluetoothDevice.Name : string.Empty, Address = dev.BluetoothDevice.Address, Type = dev.BluetoothDevice.Type.ToString() };
else
return new NativeDevice();
}
}
}
NativeDevice is my abstracted class that I used within the VM

The Reason why device value null is that the type of a.Device.NativeDevice is not of Device type. It is NativeObject so for android it is of type BluetoothDevice and for ios, it is CBPeripheral.
As I understand from your code you want to pass a.Device which is in turn of type Device. So you just need to replace it this line
NativeDevice = DependencyService.Get<INativeDevice>().ConvertToNative(a.Device.NativeDevice)
with
NativeDevice = DependencyService.Get<INativeDevice>().ConvertToNative(a.Device)
Now you can use Device.BluethoothDevice in android.

Related

bannerview.ad unit is obsolete: use adunitid property instead

I'm trying to archive my iOS app and problem shows to me because of Google Mobile Ads .
bannerview.adunit is obsolete: use adunitid property instead
I'm trying to find solution to it
private BannerView CreateBannerView()
{
if (_bannerView != null)
return _bannerView;
var origin = new CGPoint(0, UIScreen.MainScreen.Bounds.Size.Height - AdSizeCons.Banner.Size.Height);
_bannerView = new BannerView(AdSizeCons.SmartBannerPortrait, origin)
{
AdUnitID = Element.AdUnitId,
RootViewController = GetVisibleViewController()
};
_bannerView.LoadRequest(GetRequest());
return _bannerView;
}
private Request GetRequest()
{
var request = Request.GetDefaultRequest();

Player Notifications with Xamarin MediaManager plugin

I'm using the media manager nuget plugin and it's great, but for the life of me, I can't get the lock screen or car bluetooth to show the notifications. I'm using the following to display the notifications (set within OnAppearing)
ViewModel.PropertyChanged += (sender, e) =>
{
switch (e.PropertyName)
{
case "RadioSchedule":
if (listData != null)
{
listData.ItemsSource = null;
var first = ViewModel.RadioSchedule[0];
Device.BeginInvokeOnMainThread(() =>
{
listData.ItemsSource = ViewModel.RadioSchedule;
MediaFile.Metadata.Artist = MediaFile.Metadata.DisplaySubtitle = MediaFile.Metadata.AlbumArtist = first.Artist;
MediaFile.Metadata.Title = MediaFile.Metadata.DisplayTitle = first.Track;
MediaFile.Metadata.DisplayIcon = new Image { Source = "icon".CorrectedImageSource() };
MediaFile.Metadata.BluetoothFolderType = "1";
MediaFile.Type = MediaFileType.Audio;
MediaFile.Url = Constants.RadioStream;
MediaFile.Availability = ResourceAvailability.Remote;
MediaFile.MetadataExtracted = true;
MediaFile.Metadata.Date = DateTime.Now;
MediaFile.Metadata.Duration = 300;
MediaFile.Metadata.Genre = "Rock";
MediaFile.Metadata.TrackNumber = MediaFile.Metadata.NumTracks = 1;
MediaFile.Metadata.DisplayDescription = "Radio Station";
if (!ViewModel.NotificationStarted)
{
if (CrossMediaManager.Current.MediaNotificationManager != null)
CrossMediaManager.Current.MediaNotificationManager.StartNotification(MediaFile);
ViewModel.NotificationStarted = true;
}
CrossMediaManager.Current.MediaNotificationManager?.UpdateNotifications(MediaFile, MediaPlayerStatus.Playing);
});
}
break;
The code itself is being hit (I can set break points and they are hit). I've tried it on and off the UI thread as well.
The playlist comes from a webapi which works fine. The notifier gives unknown/unknown on the device media player (both iOS and Android) and nothing in-car. For Android, the permissions the readme file says to use have also been set.
Is there some sort of magic I have to do to get this to work? This is a Xam.Forms package rather than something native.
The MediaPlayer is started further in the class using the following code
CrossMediaManager.Current.Play(Constants.RadioStream, MediaFileType.Audio, ResourceAvailability.Remote);
Where Constants.RadioStream is the URL of the radio stream.

How to get IEditorOperations from IVsTextView?

I'm developing my first Visual Studio (2015 Community) Command Menu and I'm trying to get access to IEditorOperations to delete text, send backspace etc. but I'm not sure how to. I can do:
var Service = Provider.GetService(typeof(IEditorOperationsFactoryService)) as IEditorOperationsFactoryService;
Service.GetEditorOperations(???);
I'm not sure what to pass in the ??? since I don't have access to an ITextView instead what I have is a IVsTExtView via:
IVsTextView View;
IVsTextManager Manager = (IVsTextManager)ServiceProvider.GetService(typeof(SVsTextManager));
int MustHaveFocus = 1;
Manager.GetActiveView(MustHaveFocus, null, out View);
When creating the Command Menu, VS generates a template for me with a private ctor creating the command service, binding it to the command set id etc. An overridden Initialize method, and a bunch of properties.
Any ideas?
EDIT: After help from Sergey, I managed to get a bit further. But now I get a null when I try to get the IEditorOperationsFactoryService, all the other values are valid.
static IEditorOperations GetEditorService(IServiceProvider Provider, IVsTextView VsView)
{
IEditorOperations Result;
try
{
var Model = (IComponentModel)Provider.GetService(typeof(SComponentModel));
var Editor = (IEditorOperationsFactoryService)Provider.GetService(typeof(IEditorOperationsFactoryService)); // returns null
var Adaptor = Model.GetService<IVsEditorAdaptersFactoryService>();
IWpfTextView TextView = Adaptor.GetWpfTextView(VsView);
Result = Editor.GetEditorOperations(TextView);
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.ToString());
Result = null;
}
return (Result);
}
You can get IEditorOperationsFactoryService instance from variable named Model, like this:
var Model = (IComponentModel)this.ServiceProvider.GetService(typeof(SComponentModel));
var Editor = (IEditorOperationsFactoryService)Model.GetService<IEditorOperationsFactoryService>();
You can get IWpfTextView (that implements ITextView) from IVsTextView using:
IVsTextView textView = ...;
IWpfTextView v = GetEditorAdaptersFactoryService().GetWpfTextView(textView);
private Microsoft.VisualStudio.Editor.IVsEditorAdaptersFactoryService GetEditorAdaptersFactoryService()
{
Microsoft.VisualStudio.ComponentModelHost.IComponentModel componentModel =
(Microsoft.VisualStudio.ComponentModelHost.IComponentModel)serviceProvider.GetService(
typeof(Microsoft.VisualStudio.ComponentModelHost.SComponentModel));
return componentModel.GetService<Microsoft.VisualStudio.Editor.IVsEditorAdaptersFactoryService>();
}

Developing iTunes like application in c#

I need to develop an application in c# that could automatically detect an iPhone when it is connected to the system and read a particular file for the iPhone file system. I basically want this file to be downloaded automatically from device to the PC. I used USBpcap tool that suggests that iTunes connects to phone using some XML format. Any help or insight greatly appreciated. Is there any documentation of Third party APIs that can get me started? There are some applications that can replicate iTunes functionality e.g Copytrans
Is there any protocol or APIs provided by Apple?
I have been digging the internet and found this link Layered communication for iPhone.
Also I am using the LibUsbDotNet libraries for communicating to the usb device(Example). Can any one suggest which EndPoints should be used.
It seems to me that I have to implement usbmuxd in windows application. It is a multilayer protocol. There must be some libraries that implement usbmuxd(I dont think I have to implement the protocol all by my self)
I dont have much idea about iTunes communication as well as USB communication. I am adding as much information as I can(of course with the things I come up with in my R&D). Any help is highly appreciated.
public static DateTime LastDataEventDate = DateTime.Now;
public static UsbDevice MyUsbDevice;
#region SET YOUR USB Vendor and Product ID!
public static UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(1452, 4768);
#endregion
private void LibUSB()
{
ErrorCode ec = ErrorCode.None;
try
{
// Find and open the usb device.
MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);
// If the device is open and ready
if (MyUsbDevice == null)
throw new Exception("Device Not Found.");
// If this is a "whole" usb device (libusb-win32, linux libusb)
// it will have an IUsbDevice interface. If not (WinUSB) the
// variable will be null indicating this is an interface of a
// device.
IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
// This is a "whole" USB device. Before it can be used,
// the desired configuration and interface must be selected.
// Select config #1
wholeUsbDevice.SetConfiguration(1);
// Claim interface #0.
wholeUsbDevice.ClaimInterface(0);
}
// open read endpoint 1.
UsbEndpointReader reader = MyUsbDevice.OpenEndpointReader(ReadEndpointID.Ep03);
// open write endpoint 1.
UsbEndpointWriter writer = MyUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep02);
int bytesWritten;
ec = writer.Write(usbmux_header.GetBytes(), 2000, out bytesWritten);
if (ec != ErrorCode.None)
throw new Exception(UsbDevice.LastErrorString);
byte[] readBuffer = new byte[1024];
while (ec == ErrorCode.None)
{
int bytesRead;
// If the device hasn't sent data in the last 100 milliseconds,
// a timeout error (ec = IoTimedOut) will occur.
ec = reader.Read(readBuffer, 10000, out bytesRead);
if (ec == ErrorCode.Win32Error)
throw new Exception("port not open");
if (bytesRead == 0)
throw new Exception("No more bytes!");
// Write that output to the console.
Console.Write(Encoding.Default.GetString(readBuffer, 0, bytesRead));
}
}
catch (Exception ex)
{
Console.WriteLine();
Console.WriteLine((ec != ErrorCode.None ? ec + ":" : String.Empty) + ex.Message);
}
finally
{
if (MyUsbDevice != null)
{
if (MyUsbDevice.IsOpen)
{
// If this is a "whole" usb device (libusb-win32, linux libusb-1.0)
// it exposes an IUsbDevice interface. If not (WinUSB) the
// 'wholeUsbDevice' variable will be null indicating this is
// an interface of a device; it does not require or support
// configuration and interface selection.
IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
// Release interface #0.
wholeUsbDevice.ReleaseInterface(0);
}
MyUsbDevice.Close();
}
MyUsbDevice = null;
// Free usb resources
UsbDevice.Exit();
}
}
}
class usbmux_header
{
public static UInt32 length = 10; // length of message, including header
public static UInt32 reserved = 0; // always zero
public static UInt32 type = 3; // message type
public static UInt32 tag = 2; // responses to this query will echo back this tag
public static byte[] GetBytes()
{
byte[] lgth = BitConverter.GetBytes(length);
byte[] res = BitConverter.GetBytes(reserved);
byte[] tpe = BitConverter.GetBytes(type);
byte[] tg = BitConverter.GetBytes(tag);
byte[] retArray = new byte[16];
lgth.CopyTo(retArray, 0);
res.CopyTo(retArray, 4);
tpe.CopyTo(retArray, 8);
tg.CopyTo(retArray, 12);
return retArray;
}
};
I have been trying to send hello packet bytes to iPhone but I am not able to read any response from phone.
To play with ipod you can use SharePodLib
As I understand it, only one client can use the USB connection to iOS at one time. On both macOS and Windows, that one client is usbmux. That library multiplexes TCP connections with higher-level clients, including iTunes, Photos, and (on macOS) the open-source peertalk library.
So on Windows, you wouldn't want to implement your own usbmux, but rather a client that sits on top of that, analogous to peertalk. I haven't seen anything open-source that does this, but a number of developers have accomplished it with their own proprietary software.
If anybody else has pointers about using usbmux on Windows, I'd love to hear about it.
—Dave
You can use imobiledevice-net. It provides a C# API to connect to iOS devices using your PC.
For example, to list all iOS devices connected to your PC, you would run something like this:
ReadOnlyCollection<string> udids;
int count = 0;
var idevice = LibiMobileDevice.Instance.iDevice;
var lockdown = LibiMobileDevice.Instance.Lockdown;
var ret = idevice.idevice_get_device_list(out udids, ref count);
if (ret == iDeviceError.NoDevice)
{
// Not actually an error in our case
return;
}
ret.ThrowOnError();
// Get the device name
foreach (var udid in udids)
{
iDeviceHandle deviceHandle;
idevice.idevice_new(out deviceHandle, udid).ThrowOnError();
LockdownClientHandle lockdownHandle;
lockdown.lockdownd_client_new_with_handshake(deviceHandle, out lockdownHandle, "Quamotion").ThrowOnError();
string deviceName;
lockdown.lockdownd_get_device_name(lockdownHandle, out deviceName).ThrowOnError();
deviceHandle.Dispose();
lockdownHandle.Dispose();
}

How to know which one fired eventListener

I am loading images for a game before the game begin. So the main function sends links of images to an image loading object. This is what happen in my image loading object when I do image.load(link) in my main :
public function charge(str:String, img_x:int, img_y:int, layer:Sprite):void
{
trace("load");
urlRequest = new URLRequest(str);
loaderArray[cptDemande] = new Loader();
loaderArray[cptDemande].contentLoaderInfo.addEventListener(Event.COMPLETE, loading_done);
loaderArray[cptDemande].load(urlRequest);
posX[cptDemande] = img_x;
posY[cptDemande] = img_y;
layerArray[cptDemande] = layer;
cptDemande++;
}
The parameters img_x:int, img_y:int and layer:Sprite are related to displaying the images afterward. I am using arrays to be able to add the images to the stage when the loading is all done.
The event listener fire this function :
public function loading_done(evt:Event):void
{
cptLoaded++;
evt.currentTarget.contentLoaderInfo.removeEventListener(Event.COMPLETE, loading_done);
if((cptDemande == cptLoaded) && (isDone == true))
{
afficher();
}
}
what I want is to be able to target the good loader to remove the event listener. What I am currently using(evt.currentTarget) doesn't work and generate an error code :
1069 Property data not found on flash.display.LoaderInfo and there is no default value
Tracing evt.currentTarget shows that currentTarget is the LoaderInfo property. Try updating your code as follows:
public function loading_done(evt:Event):void
{
cptLoaded++;
// Current target IS the contentLoaderInfo
evt.currentTarget.removeEventListener(Event.COMPLETE, loading_done);
//evt.currentTarget.contentLoaderInfo.removeEventListener(Event.COMPLETE, loading_done);
if((cptDemande == cptLoaded) && (isDone == true))
{
afficher();
}
}
Just a wee tip for you while I'm at it, you could make life a lot easier for yourself by storing all the properties of your images on an Object and then pushing these onto a single Array, rather than managing a separate Array for each property.
Something like this:
private var loadedImages:Array = new Array();
public function charge(str:String, img_x:int, img_y:int, layer:Sprite):void
{
var urlRequest:URLRequest = new URLRequest(str);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loading_done);
loader.load(urlRequest);
var imageData:Object = { };
imageData.loader = loader;
imageData.posX = img_x;
imageData.posY = img_y;
imageData.layer = layer;
// Now we have a single Array with a separate element for
// each image representing all its properties
loadedImages.push(imageData);
cptDemande++;
}

Resources