I'm trying to print a label with a Star Micronics TSP650II printer in a monotouch app.
The problem is that session.OutputStream.HasSpaceAvailable() always returns false. What am I missing?
the C# code I have goes something like this (cut for simplicity):
var manager = EAAccessoryManager.SharedAccessoryManager;
var starPrinter = manager.ConnectedAccessories.FirstOrDefault (p => p.Name.IndexOf ("Star") >= 0); // this does find the EAAccessory correctly
var session = new EASession (starPrinter, starPrinter.ProtocolStrings [0]); // the second parameter resolves to "jp.star-m.starpro"
session.OutputStream.Schedule (NSRunLoop.Current, "kCFRunLoopDefaultMode");
session.OutputStream.Open ();
byte[] toSend = GetInitData(); // this comes from another project where the same printer with ethernet cable was used in a windows environment and worked, not null for sure
if (session.OutputStream.HasSpaceAvailable()) {
int bytesWritten = session.OutputStream.Write (toSend, (uint)stillToSend.Length);
if (bytesWritten < 0) {
Debug.WriteLine ("ERROR WRITING DATA");
} else {
Debug.WriteLine("Some data written, ignoring the rest, just a test");
}
} else
Debug.WriteLine ("NO SPACE"); // THIS ALWAYS PRINTS, the output stream is never ready to take any output
UPDATE:
I was able to work-around this problem by binding Star Micronics iOS SDK to my project, but that's less than ideal as it adds 700K to the package for something that should work without that binding.
UPDATE 2:
I've been getting requests for the binding code. I still strongly recommend you try to figure out the bluetooth connectivity and not use the binding but for those who are brave enough, here it is.
This is Kale Evans, Software Integration Engineer at Star Micronics.
Although Apple's EADemo doesn't show this, the following piece of code below is important for printing to EAAccessory.(Note, below code is Objective-C example).
if ([[_session outputStream] hasSpaceAvailable] == NO)
{
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
This gives OS time to process all input sources.
You say this does find the EAAccessory correctly
Could this be the reason the OutputStream returns false if the session is actually null?
Best Regards,
Star Support
Related
I am using iOs default PrinterToPrint in Xamarin to print without showing dialog to choose printer but then also it's showing one dialog which says printing to [PRINTER NAME]. Is there anyway to hide the dialog as well. Like complete silent print functionality?
I am not its possible but I have seen some apps which do that and I am not sure whether they are using the same function or not.
Thanks in advance.
Update:
UIPrinterPickerController comes from UIKit and as such there is no way to push the "printing" process to the background and off the main UI thread.
In the current UIPrintInteractionController.PrintToPrinter implementation (currently up to iOS 10.3 B4) there is no exposed way to disable the print progress (Connecting, Preparing, etc...) alart/dialog (w/ Cancel button) or to modify its appearance.
This interface is high level wrapper using AirPrint and thus Internet Print Protocol (IPP) at a lower level to preform the actual printing, job queue monitoring on the printer, etc... IPP is not currently exposed as a publicly available framework within iOS...
Programs that allow background printing are not using UIPrintInteractionController to do the printing. Most do use UIPrinterPickerController to obtain a UIPrinter selection from the user, but then use the UIPrinter.Url.AbsoluteUrl to "talk" directly to the printer via HTTP/HTTPS Post/Get. Depending upon the printers used, TCP-based sockets are also an option vs. IPP and even USB/serial for direct connected printers.
Re: https://en.wikipedia.org/wiki/Internet_Printing_Protocol
Original:
Pick a Printer:
if (allowUserToSelectDifferentPrinter || printerUrl == null)
{
UIPrinter uiPrinter = printerUrl != null ? null as UIPrinter : UIPrinter.FromUrl(new NSUrl(printerUrl));
var uiPrinterPickerController = UIPrinterPickerController.FromPrinter(uiPrinter);
uiPrinterPickerController.Present(true, (printerPickerController, userDidSelect, error) =>
{
if (userDidSelect)
{
uiPrinter = uiPrinterPickerController?.SelectedPrinter;
printerUrl = uiPrinter.Url.AbsoluteUrl.ToString();
Console.WriteLine($"Save this UIPrinter's Url string for later use: {printerUrl}");
}
});
}
Print using UIPrintInteractionController with an existing UIPrinter:
if (printerUrl != null)
{
// re-create a UIPrinter from a saved NSUrl string
var uiPrinter = UIPrinter.FromUrl(new NSUrl(printerUrl));
var printer = UIPrintInteractionController.SharedPrintController;
printer.ShowsPageRange = false;
printer.ShowsNumberOfCopies = false;
printer.ShowsPaperSelectionForLoadedPapers = false;
var printInfo = UIPrintInfo.PrintInfo;
printInfo.OutputType = UIPrintInfoOutputType.General;
printInfo.JobName = "StackOverflow Print Job";
var textFormatter = new UISimpleTextPrintFormatter("StackOverflow Rocks")
{
StartPage = 0,
ContentInsets = new UIEdgeInsets(72, 72, 72, 72),
MaximumContentWidth = 6 * 72,
};
printer.Delegate = new PrintInteractionControllerDelegate();
printer.PrintFormatter = textFormatter;
printer.PrintToPrinter(uiPrinter, (printInteractionController, completed, error) =>
{
if ((completed && error != null))
{
Console.WriteLine($"Print Error: {error.Code}:{error.Description}");
PresentViewController(
UIAlertController.Create("Print Error", "Code: {error.Code} Description: {error.Description}", UIAlertControllerStyle.ActionSheet),
true, () => { });
}
printInfo?.Dispose();
uiPrinter?.Dispose();
uiPrinter.
});
}
else
{
Console.WriteLine("User has not selected a printer...printing disabled");
}
I know this is a somewhat old thread but I had been struggling with implementing a silent printing in iOS for one of my customers and I finally came across an acceptable solution that is very easy to implement.
As mentioned in the accepted answer there is no way to get rid of the popup that displays printing progress. Yet there is a way of hiding it. You can simply change the UIWindowLevel of your key window to UIWindowLevel.Alert + 100. This will guarantee your current window will display above ANY alert view.
Be careful though, as I mentioned, it will be displayed over ANY alert view after the level has been changed. Luckily you can just switch this level back to "Normal" to get the original behavior.
So to recap my solution. I use UIPrintInteractionController.PrintToPrinter in order to print directly to a printer object I created using UIPrinter.FromUrl (this is Xamarin.iOS code btw). Before doing so, I adjust my window level to alert + 100 and once printing is complete I reset my window level to "Normal". Now my printing happens without any visual feedback to my user.
Hope this helps somebody!
I have an iOS app that makes some small network requests on app launch (resource updates, etc). If the user turns off cellular access for the app in iOS Settings, they get a prompt from iOS about network usage every time they launch. Is there a way to know programmatically that cellular data for this app has been disabled, so that I can disable the requests at startup?
So I found this on the apple dev forums from an Apple engineer (https://devforums.apple.com/message/1059332#1059332).
Another developer wrote in to DTS and thus I had a chance to
investigate this in depth. Alas, the news is much as I expected:
there is no supported way to detect that your app is in this state.
Nor is there a way to make a "no user interaction" network connection,
that is, request that the connection fail rather than present UI like
this. If these limitations are causing problems for your app, I
encourage you to file a bug describing your specific requirements.
https://developer.apple.com/bug-reporting/
So it looks like it is not possible to detect if cellular data for your app has been turned off.
Edit
I filed a radar for this requesting that it be added. I just got this notification in my radar
We believe this issue has been addressed in the latest iOS 9 beta.
I looked through the API diffs, but so far I can't find the new API.
As of iOS9, the capability to check the setting to enable/disable use of cellular data for your app (Settings/Cellular/AppName) is available using Apple's CTCellularData class. The following code will set cellularDataRestrictedState when it is run initially and then set it and log whenever it changes:
import CoreTelephony
var cellularDataRestrictedState = CTCellularDataRestrictedState.restrictedStateUnknown
let cellState = CTCellularData.init()
cellState.cellularDataRestrictionDidUpdateNotifier = { (dataRestrictedState) in
if cellularDataRestrictedState != .restrictedStateUnknown { // State has changed - log to console
print("cellularDataRestrictedState: " + "\(dataRestrictedState == .restrictedStateUnknown ? "unknown" : dataRestrictedState == .restricted ? "restricted" : "not restricted")")
}
cellularDataRestrictedState = dataRestrictedState
}
Unfortunately (as of iOS11) this seems to check only the state of the app's switch - if your app's switch is set to enabled and the user switches the Cellular Data master switch to disabled, this API will return the app's state as being "not restricted".
Just wanted to add an Objective C version of the above Swift code for future travellers.
- (void)monitorCanUseCellularData {
if (GCIsiOS9) {
CTCellularData *cellularData = [[CTCellularData alloc] init];
NSLog(#"%ld", cellularData.restrictedState);
// 0, kCTCellularDataRestrictedStateUnknown
[cellularData setCellularDataRestrictionDidUpdateNotifier:^(CTCellularDataRestrictedState state) {
NSLog(#"%ld", state);
self.canUseCellularData = cellularData.restrictedState ==2?true:false;
}];
}
}
I have found that the CTCellularData class needs some time to get to the correct value. In my implementation I call the didUpdateNotifier very early after appDidFinishLaunching. By the time my networking call are returning with errors I definitely have a correct value for the restricted state.
class CellularRestriction: NSObject {
private static var cellularData = CTCellularData()
private static var currentState = CTCellularDataRestrictedState.restrictedStateUnknown
static var isRestricted: Bool {
currentState = cellularData.restrictedState
return currentState == .restricted
}
static func prepare() {
if currentState == .restrictedStateUnknown {
cellularData.cellularDataRestrictionDidUpdateNotifier = { state in
currentState = cellularData.restrictedState // This value may be inconsistent, however the next read of isRestricted should be correct.
}
}
}
}
You can detect if cellular data disabled using NWPathMonitor class. (https://developer.apple.com/documentation/network/nwpathmonitor)
let cellMonitor = NWPathMonitor(requiredInterfaceType: .cellular)
cellMonitor.pathUpdateHandler = { path in
self.isCellConnected = path.status == .satisfied
}
Adding to dirkgroten's answer, you can use the Apple Reachability class, found here:
https://developer.apple.com/Library/ios/samplecode/Reachability/Introduction/Intro.html
It uses SCNetworkReachability, and is very straight forward to use, it will detect connectivity via Cell and WiFi as you will need to check both at start up.
There are lots of frameworks out there that will give you the status of your network connectivity, and of course you can roll your own. I've found AFNetworking to be one of the best. It has a singleton class called AFNetworkReachabilityManager that abstracts some of the complexities for you. Specifically you'll want to look at the two boolean properties:
reachableViaWWAN
reachableViaWiFi
There is also a reachability changed status block that you can set:
– setReachabilityStatusChangeBlock:
AFNetworking Github
AFNetworkReachabilityManager
I have an iOS app that makes some small network requests on app launch (resource updates, etc). If the user turns off cellular access for the app in iOS Settings, they get a prompt from iOS about network usage every time they launch. Is there a way to know programmatically that cellular data for this app has been disabled, so that I can disable the requests at startup?
So I found this on the apple dev forums from an Apple engineer (https://devforums.apple.com/message/1059332#1059332).
Another developer wrote in to DTS and thus I had a chance to
investigate this in depth. Alas, the news is much as I expected:
there is no supported way to detect that your app is in this state.
Nor is there a way to make a "no user interaction" network connection,
that is, request that the connection fail rather than present UI like
this. If these limitations are causing problems for your app, I
encourage you to file a bug describing your specific requirements.
https://developer.apple.com/bug-reporting/
So it looks like it is not possible to detect if cellular data for your app has been turned off.
Edit
I filed a radar for this requesting that it be added. I just got this notification in my radar
We believe this issue has been addressed in the latest iOS 9 beta.
I looked through the API diffs, but so far I can't find the new API.
As of iOS9, the capability to check the setting to enable/disable use of cellular data for your app (Settings/Cellular/AppName) is available using Apple's CTCellularData class. The following code will set cellularDataRestrictedState when it is run initially and then set it and log whenever it changes:
import CoreTelephony
var cellularDataRestrictedState = CTCellularDataRestrictedState.restrictedStateUnknown
let cellState = CTCellularData.init()
cellState.cellularDataRestrictionDidUpdateNotifier = { (dataRestrictedState) in
if cellularDataRestrictedState != .restrictedStateUnknown { // State has changed - log to console
print("cellularDataRestrictedState: " + "\(dataRestrictedState == .restrictedStateUnknown ? "unknown" : dataRestrictedState == .restricted ? "restricted" : "not restricted")")
}
cellularDataRestrictedState = dataRestrictedState
}
Unfortunately (as of iOS11) this seems to check only the state of the app's switch - if your app's switch is set to enabled and the user switches the Cellular Data master switch to disabled, this API will return the app's state as being "not restricted".
Just wanted to add an Objective C version of the above Swift code for future travellers.
- (void)monitorCanUseCellularData {
if (GCIsiOS9) {
CTCellularData *cellularData = [[CTCellularData alloc] init];
NSLog(#"%ld", cellularData.restrictedState);
// 0, kCTCellularDataRestrictedStateUnknown
[cellularData setCellularDataRestrictionDidUpdateNotifier:^(CTCellularDataRestrictedState state) {
NSLog(#"%ld", state);
self.canUseCellularData = cellularData.restrictedState ==2?true:false;
}];
}
}
I have found that the CTCellularData class needs some time to get to the correct value. In my implementation I call the didUpdateNotifier very early after appDidFinishLaunching. By the time my networking call are returning with errors I definitely have a correct value for the restricted state.
class CellularRestriction: NSObject {
private static var cellularData = CTCellularData()
private static var currentState = CTCellularDataRestrictedState.restrictedStateUnknown
static var isRestricted: Bool {
currentState = cellularData.restrictedState
return currentState == .restricted
}
static func prepare() {
if currentState == .restrictedStateUnknown {
cellularData.cellularDataRestrictionDidUpdateNotifier = { state in
currentState = cellularData.restrictedState // This value may be inconsistent, however the next read of isRestricted should be correct.
}
}
}
}
You can detect if cellular data disabled using NWPathMonitor class. (https://developer.apple.com/documentation/network/nwpathmonitor)
let cellMonitor = NWPathMonitor(requiredInterfaceType: .cellular)
cellMonitor.pathUpdateHandler = { path in
self.isCellConnected = path.status == .satisfied
}
Adding to dirkgroten's answer, you can use the Apple Reachability class, found here:
https://developer.apple.com/Library/ios/samplecode/Reachability/Introduction/Intro.html
It uses SCNetworkReachability, and is very straight forward to use, it will detect connectivity via Cell and WiFi as you will need to check both at start up.
There are lots of frameworks out there that will give you the status of your network connectivity, and of course you can roll your own. I've found AFNetworking to be one of the best. It has a singleton class called AFNetworkReachabilityManager that abstracts some of the complexities for you. Specifically you'll want to look at the two boolean properties:
reachableViaWWAN
reachableViaWiFi
There is also a reachability changed status block that you can set:
– setReachabilityStatusChangeBlock:
AFNetworking Github
AFNetworkReachabilityManager
I have recently started using Microsoft Kinect for Windows SDK to program some stuff using the Kinect the device.
I am busting my ass to find a way to detect whether a certain hand is closed or opened.
I saw the Kinect for Windows Toolkit but the documentation is none existent and I can't find a way to make it work.
Does anyone knows of a simple way to detect the hand's situation? even better if it doesn't involve the need to use the Kinect toolkit.
This is how I did it eventually:
First things first, we need a dummy class that looks somewhat like this:
public class DummyInteractionClient : IInteractionClient
{
public InteractionInfo GetInteractionInfoAtLocation(
int skeletonTrackingId,
InteractionHandType handType,
double x,
double y)
{
var result = new InteractionInfo();
result.IsGripTarget = true;
result.IsPressTarget = true;
result.PressAttractionPointX = 0.5;
result.PressAttractionPointY = 0.5;
result.PressTargetControlId = 1;
return result;
}
}
Then, in the main application code we need to announce about the interactions events handler like this:
this.interactionStream = new InteractionStream(args.NewSensor, new DummyInteractionClient());
this.interactionStream.InteractionFrameReady += InteractionStreamOnInteractionFrameReady;
Finally, the code to the handler itself:
private void InteractionStreamOnInteractionFrameReady(object sender, InteractionFrameReadyEventArgs e)
{
using (InteractionFrame frame = e.OpenInteractionFrame())
{
if (frame != null)
{
if (this.userInfos == null)
{
this.userInfos = new UserInfo[InteractionFrame.UserInfoArrayLength];
}
frame.CopyInteractionDataTo(this.userInfos);
}
else
{
return;
}
}
foreach (UserInfo userInfo in this.userInfos)
{
foreach (InteractionHandPointer handPointer in userInfo.HandPointers)
{
string action = null;
switch (handPointer.HandEventType)
{
case InteractionHandEventType.Grip:
action = "gripped";
break;
case InteractionHandEventType.GripRelease:
action = "released";
break;
}
if (action != null)
{
string handSide = "unknown";
switch (handPointer.HandType)
{
case InteractionHandType.Left:
handSide = "left";
break;
case InteractionHandType.Right:
handSide = "right";
break;
}
if (handSide == "left")
{
if (action == "released")
{
// left hand released code here
}
else
{
// left hand gripped code here
}
}
else
{
if (action == "released")
{
// right hand released code here
}
else
{
// right hand gripped code here
}
}
}
}
}
}
SDK 1.7 introduces the interaction concept called "grip". You read about all the KinectInteraction concepts at the following link: http://msdn.microsoft.com/en-us/library/dn188673.aspx
The way Microsoft has implemented this is via an event from an KinectRegion. Among the KinectRegion Events are HandPointerGrip and HandPointerGripRelease, which fire at the appropriate moments. Because the event is coming from the element the hand is over you can easily take appropriate action from the event handler.
Note that a KinectRegion can be anything. The base class is a ContentControl so you can place something as simple as an image to a complex Grid layout within the region to be acted on.
You can find an example of how to use this interaction in the ControlBasics-WPF example, provided with the SDK.
UPDATE:
KinectRegion is simply a fancy ContentControl, which in turn is just a container, which can have anything put inside. Have a look at the ControlBasics-WPF example, at the Kinect for Windows CodePlex, and do a search for KinectRegion in the MainWindow.xaml file. You'll see that there are several controls inside it which are acted upon.
To see how Grip and GripRelease are implemented in this example, it is best to open the solution in Visual Studio and do a search for "grip". They way they do it is a little odd, in my opinion, but it is a clean implementation that flows very well.
For what i know Microsoft kinect for windows SDK does not best to detect open and close hands. Microsoft provides tracking of 20 body parts and does not include the fingers of the hand. You can take advantage of the kinect interactions for that in an inderect way. This tutorial shows how:
http://dotneteers.net/blogs/vbandi/archive/2013/05/03/kinect-interactions-with-wpf-part-iii-demystifying-the-interaction-stream.aspx
But i think the best solution when tracking finger movements would be using OpenNI SDK.
Some of the MiddleWares of OpenNI allow finger tracking.
You can use something like this
private void OnHandleHandMove(object source, HandPointerEventArgs args)
{
HandPointer ptr = args.HandPointer;
if (ptr.HandEventType==HandEventType.Grip)
{
// TODO
}
}
I have some trouble tring to print graphics from Java3d some computer (Intel based Graphic cards) crash completly when printing. I got this exception.
javax.media.j3d.IllegalRenderingStateException: GL_VERSION
at javax.media.j3d.NativePipeline.createNewContext(Native Method)
at javax.media.j3d.NativePipeline.createNewContext(NativePipeline.java:2736)
at javax.media.j3d.Canvas3D.createNewContext(Canvas3D.java:4895)
at javax.media.j3d.Canvas3D.createNewContext(Canvas3D.java:2421)
at javax.media.j3d.Renderer.doWork(Renderer.java:895)
at javax.media.j3d.J3dThread.run(J3dThread.java:256)
DefaultRenderingErrorListener.errorOccurred:
CONTEXT_CREATION_ERROR: Renderer: Error creating Canvas3D graphics context
graphicsDevice = Win32GraphicsDevice[screen=0]
canvas = visualization.show3D.show.print.OffScreenCanvas3D[canvas0,0,0,3000x2167,invalid]
Java 3D ERROR : OpenGL 1.2 or better is required (GL_VERSION=1.1)
Java Result: 1
I know it said i have to upgrade to OpenGL 1.2 but after checking i already have 1.5 installed (error message is not accurate)
String glVersion = (String)getCanvas3D().queryProperties().get("native.version");
I tried to catch IllegalRenderingStateException but it doesn't work, JVM just crash in any case.
Doesnt anyone know how to have a printing function to work on Intel based Graphic cards ?
I found out the cause of my problem.
Some computer haven't OffScreenRendering support needed by PrintCanvas3D.java.
So i used robot to create a screen capture
public BufferedImage canvasCapture(Dimension size, Point locationOnScreen) {
Rectangle bounds = new Rectangle(locationOnScreen.x, locationOnScreen.y, size.width, size.height);
try{
Robot robot = new Robot(this.getGraphicsConfiguration().getDevice());
return robot.createScreenCapture(bounds);
}catch (Exception e){
e.printStackTrace();
return null;
}
}
Last tricky part was to detect when to switch from proper printing method to ScreenCapture method (since catching the raised exception doesn't work), after some search i found out that queryProperties() could give me this information
here is the code in my Frame3D to choose proper method
Boolean OffScreenRenderingSupport = (Boolean)getCanvas3D().queryProperties().get("textureLodOffsetAvailable");
if (OffScreenRenderingSupport){
bImage = getOffScreenCanvas3D().doRender(dim.width, dim.height);
}else{
bImage = getOffScreenCanvas3D().canvasCapture(getCanvas3D().getSize(), getCanvas3D().getLocationOnScreen());
}
If anyone can find a better way to handle this, please let me know ;)