PrinterToPrint without showing the print job Progress dialog - ios

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!

Related

Swift: Printing without alert box

I use the following codes for printing in the app:
init() {
self.printInfo.outputType = UIPrintInfoOutputType.photo
self.printInfo.orientation = UIPrintInfoOrientation.landscape
self.printController.printInfo = self.printInfo
self.printer = UIPrinter(url: URL(string: printIP)!)
// where printIP is a string that give the internal IP of the printer
debugPrint(printIP)
}
func print(image: UIImage) -> Bool {
self.printController.printingItem = image
printController.print(to: printer, completionHandler: {(controller, success, error) -> Void in
if success {
debugPrint("Printing Completed.")
} else {
debugPrint("Printing Failed.")
}
})
return true
}
It can print successfully. However, when the function is triggered, there is an alert box indicating that it is contacting to the Printer, and printing. Is there any method to avoid the pop up of this alert box? I want the printing done at the back without showing anything on the screen that interfere the user experience (I want to play a movie when the printer is working at the back).
Thanks.
From iOS 8 there is a way to print without any presentation of the
printing UI. Instead of presenting the UI each time the user presses a
print button, you can provide a way for your users to select a printer
somewhere in your app with the easy-to-use UIPrinterPickerController.
It accepts an optional UIPrinter instance in its constructor for a
pre-selection, uses the same presentation options as explained above,
and has a completion handler for when the user has selected her
printer:
Swift 3
let printerPicker = UIPrinterPickerController(initiallySelectedPrinter: savedPrinter)
printerPicker.present(animated: true) {
(printerPicker, userDidSelect, error) in
if userDidSelect {
self.savedPrinter = printerPicker.selectedPrinter
}
}
Now you can tell your UIPrintInteractionController to print directly by calling printToPrinter(:completionHandler:) with the saved printer instead of using one of the present... methods.
Source:- http://nshipster.com/uiprintinteractioncontroller/

Set timeout for notifications.notify FireFox Addon SDK

Please help me with Notification in my Firefox add-on.
var notifications = require("sdk/notifications");
function showNotifcation(title, text) {
notifications.notify({
iconURL: data.url("img/icon.png"),
title: title,
text: text
});
setTimeout(notifications.close(), 1000);
}
Not work.
Without more information from you it is not possible to be sure as to what your problem/issue is.
However, a brief look at the sdk/notifications documentation, and source code, indicates that you are attempting to use a non-existent method: notifications.close(). There is no such method in sdk/notifications.
One possible reason for your attempt to use this method is that you are conflating the Web Notification API, more detail, with the Add-on SDK sdk/notifications.
The Add-on SDK, sdk/notifications, has no way for you to programmatically close the notification from your code. Thus, there is no way for you to set a timeout for the notification using this interface. However, in some operating systems/windowing systems there is already a default timeout for these notifications.
You will need to either display a panel on your own, or use the chrome interfaces described in User Notifications and Alerts.
In addition, it would be unusual for you to be able to just call setTimeout(). That will, under most contexts, not be defined. You would normally need to use sdk/timers with:
var { setTimeout } = require("sdk/timers");
In some contexts, you might be able to use window.setTimeout(), when window is appropriately defined (which you will probably have to set yourself).
Modifying the code from my answer to Prevent XUL notificationBox from closing when button is hit (if you want buttons, that answer will show you how to do it), and other answers of mine: Something along the lines of what I believe you desire would be (code for the timeout is at the bottom):
function showNotificationBox(text) {
//Create some common variables if they do not exist.
if (window === null || typeof window !== "object") {
// Add/remove a "/" to comment/un-comment the code appropriate for your add-on:
//* Add-on SDK:
var window = require('sdk/window/utils').getMostRecentBrowserWindow();
//*/
/* Overlay and bootstrap (from almost any context/scope):
var window=Components.classes["#mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator)
.getMostRecentWindow("navigator:browser");
//*/
}
if (typeof gBrowser === "undefined") {
var gBrowser = window.gBrowser;
}
let notifyBox = gBrowser.getNotificationBox();
//appendNotification( label , value , image (URL) , priority , buttons, eventCallback )
let theNotification = notifyBox.appendNotification(text, "Test notification unique ID",
"chrome://browser/content/aboutRobots-icon.png",
notifyBox.PRIORITY_INFO_HIGH, [], null);
//* Add-on SDK:
var { setTimeout } = require("sdk/timers");
setTimeout(theNotification.close(), 10000);
//*/
/* Overlay and bootstrap:
let timerCallback = {
notify:function notify() {theNotification.close(); }
}
let closeNotificationTimer = Components.classes["#mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
closeNotificationTimer.initWithCallback(timerCallback,10000,
Components.interfaces.nsITimer.TYPE_ONE_SHOT);
//*/
}
Note: I changed the timeout to 10 seconds from the 1 second which is in the code in your question. One second is a unreasonable amount of time to expect to show anything which you actually desire the user to see and understand.
The above implements the user notification in a notificationBox. As such it shows up within the Firefox window:
It is also possible to use the nsIAlertsService which is what sdk/notifications uses. This will normally display an alert box in the bottom right of the screen, potentially outside of the Firefox window (see image on nsIAlertsService for example). The notification may show up elsewhere depending on how you have your windowing system set up (this is OS dependent). However, the documentation did not have a method to clear the notification, or set a timeout. However, the interface definition does show that a closeAlert() method does exist. The source code for the sdk/notifications does not expose this to the Add-on SDK. Thus, you would need to use the chrome interfaces. I have updated the documentation to show closeAlert().
Such as (some code taken and modified from nsIAlertsService):
//* Add-on SDK:
var {Cc, Ci} = require("chrome");
//*/
/* Overlay and bootstrap:
const Cc = Components.classes;
const Ci = Components.interfaces;
//*/
function showNotifcation(title, text) {
var alertsService = Cc["#mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
try {
//The second use of title is the alert name.
alertsService.showAlertNotification(icon, title, text, false, "", null, title);
} catch (e) {
// This can fail on Mac OS X
}
//* Add-on SDK:
var { setTimeout } = require("sdk/timers");
setTimeout(alertsService.closeAlert(title), 10000);
//*/
/* Overlay and bootstrap:
let alertTimerCallback = {
notify:function notify() {alertsService.closeAlert(title); }
}
let closeAlertTimer = Cc["#mozilla.org/timer;1"].createInstance(Components.interfaces
.nsITimer);
closeAlertTimer.initWithCallback(alertTimerCallback,10000,Ci.nsITimer.TYPE_ONE_SHOT);
//*/
}
I have only tested the above code with a bootstrapped/restartless Firefox add-on. Thus, the Add-on SDK code may be slightly off.

Star Micronics TSP650II bluetooth printer, can't write to EASession.OutputStream

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

Strange behaviour of Geolocator.GetGeopositionAsync() after first launch

I'm writing Windows Phone 8 app that needs to get location of device (do not track changes, just get location). I added next code to the method OnNavigatedTo() of my start page but after launching app, the progress indicator does not hide even after 10 seconds timeout. But if I navigate to another page and then go back, everything works fine. This happens on the emulator, I don't have a real device. What am I doing wrong?
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
if(_geoPosition == null)
{
try
{
var geolocator = new Geolocator();
geolocator.DesiredAccuracyInMeters = 50;
_progressIndicator = new ProgressIndicator
{
IsIndeterminate = true,
Text = "Getting current location, please wait...",
IsVisible = true
};
SystemTray.SetIsVisible(this, true);
SystemTray.SetProgressIndicator(this, _progressIndicator);
_geoPosition = await geolocator.GetGeopositionAsync(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10));
_progressIndicator.IsVisible = false;
SystemTray.SetIsVisible(this, false);
}
catch (UnauthorizedAccessException)
{
MessageBox.Show("Location is disabled in phone settings");
}
}
}
Thanks!
UPD: just tried to add this code to empty project and it works fine. Tried to comment out some parts of OnNavigatedTo that I did not include to the snippet and found out that the reason somewhere in initialization of data source for this page. I'm sorry for false alarm.
Your code works fine for me, try the classic restart VS and the projecy!
The code should work, tested it with an emulator and a device (nokia 820).
Best of luck

firefox extensions, make notification box appear in all tabs

Firefox has a native notification box system:
https://developer.mozilla.org/en/Code_snippets/Alerts_and_Notifications#Using_notification_box
I'd like to use this system in a way that it appears in all opened tabs when it is supposed to appear. The code I have only warns you in the currently opened tab.
var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebNavigation).QueryInterface(Components.interfaces.nsIDocShellTreeItem).rootTreeItem.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindow);
var nb = mainWindow.gBrowser.getNotificationBox();
//...
outdatedNotification = nb.appendNotification("Your information outdated",
'outdate-warn',
'chrome://checksistem/skin/checksistem.png',
priority, buttons);
Each tab has it's own notification box. You just need to loop over all the browsers and add the notification to each one. One thing you should know is the gBrowser.getNotificationBox can take a browser element:
http://mxr.mozilla.org/mozilla-central/source/browser/base/content/tabbrowser.xml#337
If you don't pass a browser, the code returns the notification box for the active tab.
Try this:
var browsers = mainWindow.gBrowser.browsers;
for (var i=0; i<browsers.length; i++) {
var nb = mainWindow.gBrowser.getNotificationBox(browsers[i]);
outdatedNotification = nb.appendNotification("Your information outdated",
'outdate-warn',
'chrome://checksistem/skin/checksistem.png',
priority, buttons);
}

Resources