April 8th, 2014

Native Printing with Android

The latest version of Android, KitKat, adds long-awaited printing support to the platform. Android applications can now provide low-level control of print jobs, in addition to print integration for applications incorporating web content. This makes KitKat particularly well-suited to hybrid applications built with Xamarin using Razor templates.

Android KitKat Printing

Printing with a WebView

First let’s look at the easy to use print support offered through the WebView control.

Printing requires 3 steps:

  1. In an Activity, get a reference to the PrintManager system service.
  2. Create an instance of a class that inherits from PrintDocumentAdapter.
  3. Call the PrintManager‘s Print method, passing it the print adapter.

The PrintDocumentAdapter is an abstract class that provides a contract to implement for supplying print content. For web content, the WebView class includes a PrintDocumentAdapter, making printing HTML from a WebView incredibly easy to do:

The following example shows a WebView built using the Android WebView template, which uses Razor as an HTML templating engine:

Android Printing from a Xamarin Razor Template

Although printing can be done using any WebView, integrating printing with Razor and this project template makes it really easy to build a hybrid application that can leverage native features such as KitKat printing.

Printing from the WebView with C# is as simple as adding these 2 lines of code in the activity:

var printMgr = (PrintManager)GetSystemService(Context.PrintService);
printMgr.Print("Razor HMTL Hybrid", webView.CreatePrintDocumentAdapter(), null);

When we call Print Android presents a system dialog, allowing the user to choose the print destination, as shown below:

Android Print Dialog

Custom Print Adapter

To print from native Android views, taking low-level control of the print layout, we can implement our own PrintDocumentAdapter.

For example, let’s say we would like to print the layout from the following screen:

Android Print Activity Low Level

In our implementation of PrintDocumentAdapter, the required methods to implement are:

  • OnLayout – Allows laying out print content based on the PrintAttributes.
  • OnWrite – Allows writing a PDF file with content to print.

In OnLayout, we create a PrintDocumentInfo instance, which contains metadata about the document being printed.

public override void OnLayout (PrintAttributes oldAttributes, PrintAttributes newAttributes, 
                               CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras)
{
  document = new PrintedPdfDocument (context, newAttributes);

  CalculateScale (newAttributes);

  var printInfo = new PrintDocumentInfo
    .Builder ("MyPrint.pdf")
    .SetContentType (PrintContentType.Document)
    .SetPageCount (1)
    .Build ();

  callback.OnLayoutFinished (printInfo, true);
}

In OnWrite, we implement the code to draw printed content and write it to the output stream to be printed.

public override void OnWrite (PageRange[] pages, ParcelFileDescriptor destination, 
                              CancellationSignal cancellationSignal, WriteResultCallback callback)
{
  PrintedPdfDocument.Page page = document.StartPage (0);

  page.Canvas.Scale (scale, scale);

  view.Draw (page.Canvas);

  document.FinishPage (page);

  WritePrintedPdfDoc (destination);

  document.Close ();

  document.Dispose ();

  callback.OnWriteFinished (pages);
}

Printing with our custom adapter is just like using the WebView‘s adapter. Simply pass an instance of the custom adapter, called GenericPrintAdapter in this case, to the PrintManager‘s Print method:

var printManager = (PrintManager)GetSystemService (Context.PrintService);
var content = FindViewById<LinearLayout> (Resource.Id.linearLayout1);
var printAdapter = new GenericPrintAdapter (this, content);

printManager.Print ("MyPrintJob", printAdapter, null);

When the user clicks print, the same system dialog is displayed. In addition to a local printer, you can select Google Cloud Print or print to a PDF file, resulting in the print shown below:

Android Printed to PDF

The printing support added to KitKat is a much welcome feature that is easy to get started with. You can download the code used in this post from my GitHub repo.

Discuss this post in the Xamarin forums.

Author

0 comments

Discussion are closed.

Feedback