Merge "docs: Print API training for KitKat release" into klp-dev

This commit is contained in:
Joe Fernandez
2013-10-31 03:45:32 +00:00
committed by Android (Google) Code Review
5 changed files with 702 additions and 0 deletions

View File

@@ -0,0 +1,362 @@
page.title=Printing Custom Documents
parent.title=Printing Content
parent.link=index.html
trainingnavtop=true
next.title=
next.link=
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#print-manager">Connect to the Print Manager</a></li>
<li><a href="#print-adapter">Create a Print Adapter</a>
<ol>
<li><a href="#doc-info">Compute print document info</a></li>
<li><a href="#write-file">Write a print document file</a></li>
</ol>
</li>
<li><a href="#draw-content">Drawing PDF Page Content</a></li>
</ol>
</div>
</div>
<p>For some applications, such as drawing apps, page layout apps and other apps that focus on
graphic output, creating beautiful printed pages is a key feature. In this case, it is not enough
to print an image or an HTML document. The print output for these types of applications requires
precise control of everything that goes into a page, including fonts, text flow, page breaks,
headers, footers, and graphic elements.</p>
<p>Creating print output that is completely customized for your application requires more
programming investment than the previously discussed approaches. You must build components that
communicate with the print framework, adjust to printer settings, draw page elements and
manage printing on multiple pages.</p>
<p>This lesson shows you how you connect with the print manager, create a print adapter and
build content for printing.</p>
<h2 id="print-manager">Connect to the Print Manager</h2>
<p>When your application manages the printing process directly, the first step after receiving a
print request from your user is to connect to the Android print framework and obtain an instance
of the {@link android.print.PrintManager} class. This class allows you to initialize a print job
and begin the printing lifecycle. The following code example shows how to get the print manager
and start the printing process.</p>
<pre>
private void doPrint() {
// Get a PrintManager instance
PrintManager printManager = (PrintManager) getActivity()
.getSystemService(Context.PRINT_SERVICE);
// Set job name, which will be displayed in the print queue
String jobName = getActivity().getString(R.string.app_name) + " Document";
// Start a print job, passing in a PrintDocumentAdapter implementation
// to handle the generation of a print document
printManager.print(jobName, new MyPrintDocumentAdapter(getActivity()),
null); //
}
</pre>
<p>The example code above demonstrates how to name a print job and set an instance of the {@link
android.print.PrintDocumentAdapter} class which handles the steps of the printing lifecycle. The
implementation of the print adapter class is discussed in the next section.</p>
<p class="note">
<strong>Note:</strong> The last parameter in the {@link android.print.PrintManager#print print()}
method takes a {@link android.print.PrintAttributes} object. You can use this parameter to
provide hints to the printing framework and pre-set options based on the previous printing cycle,
thereby improving the user experience. You may also use this parameter to set options that are
more appropriate to the content being printed, such as setting the orientation to landscape
when printing a photo that is in that orientation.
</p>
<h2 id="print-adapter">Create a Print Adapter</h2>
<p>A print adapter interacts with the Android print framework and handles the steps of the
printing process. This process requires users to select printers and print options before creating
a document for printing. These selections can influence the final output as the user chooses
printers with different output capabilities, different page sizes, or different page orientations.
As these selections are made, the print framework asks your adapter to lay out and generate a
print document, in preparation for final output. Once a user taps the print button, the framework
takes the final print document and passes it to a print provider for output. During the printing
process, users can choose to cancel the print action, so your print adapter must also listen for
and react to a cancellation requests.</p>
<p>The {@link android.print.PrintDocumentAdapter} abstract class is designed to handle the
printing lifecycle, which has four main callback methods. You must implement these methods
in your print adapter in order to interact properly with the print framework:</p>
<ul>
<li>{@link android.print.PrintDocumentAdapter#onStart onStart()} - Called once at the
beginning of the print process. If your application has any one-time preparation tasks to
perform, such as getting a snapshot of the data to be printed, execute them here. Implementing
this method in your adapter is not required.</li>
<li>{@link android.print.PrintDocumentAdapter#onLayout onLayout()} - Called each time a
user changes a print setting which impacts the output, such as a different page size,
or page orientation, giving your application an opportunity to compute the layout of the
pages to be printed. At the minimum, this method must return how many pages are expected
in the printed document.</li>
<li>{@link android.print.PrintDocumentAdapter#onWrite onWrite()} - Called to render printed
pages into a file to be printed. This method may be called one or more times after each
{@link android.print.PrintDocumentAdapter#onLayout onLayout()} call.</li>
<li>{@link android.print.PrintDocumentAdapter#onFinish onFinish()} - Called once at the end
of the print process. If your application has any one-time tear-down tasks to perform,
execute them here. Implementing this method in your adapter is not required.</li>
</ul>
<p>The following sections describe how to implement the layout and write methods, which are
critical to the functioning of a print adapter.</p>
<p class="note">
<strong>Note:</strong> These adapter methods are called on the main thread of your application. If
you expect the execution of these methods in your implementation to take a significant amount of
time, implement them to execute within a separate thread. For example, you can encapsulate the
layout or print document writing work in separate {@link android.os.AsyncTask} objects.
</p>
<h3 id="doc-info">Compute print document info</h3>
<p>Within an implementation of the {@link android.print.PrintDocumentAdapter} class, your
application must be able to specify the type of document it is creating and calculate the total
number of pages for print job, given information about the printed page size.
The implementation of the {@link android.print.PrintDocumentAdapter#onLayout onLayout()} method in
the adapter makes these calculations and provides information about the expected output of the
print job in a {@link android.print.PrintDocumentInfo} class, including the number of pages and
content type. The following code example shows a basic implementation of the {@link
android.print.PrintDocumentAdapter#onLayout onLayout()} method for a {@link
android.print.PrintDocumentAdapter}:
<pre>
&#64;Override
public void onLayout(PrintAttributes oldAttributes,
PrintAttributes newAttributes,
CancellationSignal cancellationSignal,
LayoutResultCallback callback,
Bundle metadata) {
// Create a new PdfDocument with the requested page attributes
mPdfDocument = new PrintedPdfDocument(getActivity(), newAttributes);
// Respond to cancellation request
if (cancellationSignal.isCancelled() ) {
callback.onLayoutCancelled();
return;
}
// Compute the expected number of printed pages
int pages = computePageCount(newAttributes);
if (pages > 0) {
// Return print information to print framework
PrintDocumentInfo info = new PrintDocumentInfo
.Builder("print_output.pdf")
.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
.setPageCount(pages);
.build();
// Content layout reflow is complete
callback.onLayoutFinished(info, true);
} else {
// Otherwise report an error to the print framework
callback.onLayoutFailed("Page count calculation failed.");
}
}
</pre>
<p>The execution of {@link android.print.PrintDocumentAdapter#onLayout onLayout()} method can
have three outcomes: completion, cancellation, or failure in the case where calculation of the
layout cannot be completed. You must indicate one of these results by calling the appropriate
method of the {@link android.print.PrintDocumentAdapter.LayoutResultCallback} object.</p>
<p class="note">
<strong>Note:</strong> The boolean parameter of the
{@link android.print.PrintDocumentAdapter.LayoutResultCallback#onLayoutFinished
onLayoutFinished()} method indicates whether or not the layout content has actually changed
since the last request. Setting this parameter properly allows the print framework to avoid
unnecessarily calling the {@link android.print.PrintDocumentAdapter#onWrite onWrite()} method,
essentially caching the previously written print document and improving performance.
</p>
<p>The main work of {@link android.print.PrintDocumentAdapter#onLayout onLayout()} is
calculating the number of pages that are expected as output given the attributes of the printer.
How you calculate this number is highly dependent on how your application lays out pages for
printing. The following code example shows an implementation where the number of pages is
determined by the print orientation:</p>
<pre>
private int computePageCount(PrintAttributes printAttributes) {
int itemsPerPage = 4; // default item count for portrait mode
MediaSize pageSize = printAttributes.getMediaSize();
if (!pageSize.isPortrait()) {
// Six items per page in landscape orientation
itemsPerPage = 6;
}
// Determine number of print items
int printItemCount = getPrintItemCount();
return (int) Math.ceil(printItemCount / itemsPerPage);
}
</pre>
<h3 id="write-file">Write a print document file</h3>
<p>When it is time to write print output to a file, the Android print framework calls the {@link
android.print.PrintDocumentAdapter#onWrite onWrite()} method of your application's {@link
android.print.PrintDocumentAdapter} class. The method's parameters specify which pages should be
written and the output file to be used. Your implementation of this method must then render each
requested page of content to a multi-page PDF document file. When this process is complete, you
call the {@link android.print.PrintDocumentAdapter.WriteResultCallback#onWriteFinished
onWriteFinished()} method of the callback object.</p>
<p class="note">
<strong>Note:</strong> The Android print framework may call the {@link
android.print.PrintDocumentAdapter#onWrite onWrite()} method one or more times for every
call to {@link android.print.PrintDocumentAdapter#onLayout onLayout()}. For this reason, it is
important to set the boolean parameter of
{@link android.print.PrintDocumentAdapter.LayoutResultCallback#onLayoutFinished
onLayoutFinished()} method to {@code false} when the print content layout has not changed,
to avoid unnecessary re-writes of the print document.
</p>
<p class="note">
<strong>Note:</strong> The boolean parameter of the
{@link android.print.PrintDocumentAdapter.LayoutResultCallback#onLayoutFinished
onLayoutFinished()} method indicates whether or not the layout content has actually changed
since the last request. Setting this parameter properly allows the print framework to avoid
unnecessarily calling the {@link android.print.PrintDocumentAdapter#onLayout onLayout()} method,
essentially caching the previously written print document and improving performance.
</p>
<p>The following sample demonstrates the basic mechanics of this process using the {@link
android.print.pdf.PrintedPdfDocument} class to create a PDF file:</p>
<pre>
&#64;Override
public void onWrite(final PageRange[] pageRanges,
final ParcelFileDescriptor destination,
final CancellationSignal cancellationSignal,
final WriteResultCallback callback) {
// Iterate over each page of the document,
// check if it's in the output range.
for (int i = 0; i < totalPages; i++) {
// Check to see if this page is in the output range.
if (containsPage(pageRanges, i)) {
// If so, add it to writtenPagesArray. writtenPagesArray.size()
// is used to compute the next output page index.
writtenPagesArray.append(writtenPagesArray.size(), i);
PdfDocument.Page page = mPdfDocument.startPage(i);
// check for cancellation
if (cancellationSignal.isCancelled()) {
callback.onWriteCancelled();
mPdfDocument.close();
mPdfDocument = null;
return;
}
// Draw page content for printing
drawPage(page);
// Rendering is complete, so page can be finalized.
mPdfDocument.finishPage(page);
}
}
// Write PDF document to file
try {
mPdfDocument.writeTo(new FileOutputStream(
destination.getFileDescriptor()));
} catch (IOException e) {
callback.onWriteFailed(e.toString());
return;
} finally {
mPdfDocument.close();
mPdfDocument = null;
}
PageRange[] writtenPages = computeWrittenPages();
// Signal the print framework the document is complete
callback.onWriteFinished(writtenPages);
...
}
</pre>
<p>This sample delegates rendering of PDF page content to <code>drawPage()</code>
method, which is discussed in the next section.
</p>
<p>As with layout, execution of {@link android.print.PrintDocumentAdapter#onWrite onWrite()}
method can have three outcomes: completion, cancellation, or failure in the case where the
the content cannot be written. You must indicate one of these results by calling the
appropriate method of the {@link android.print.PrintDocumentAdapter.WriteResultCallback} object.
</p>
<p class="note">
<strong>Note:</strong> Rendering a document for printing can be a resource-intensive operation. In
order to avoid blocking the main user interface thread of your application, you should consider
performing the page rendering and writing operations on a separate thread, for example
in an {@link android.os.AsyncTask}.
For more information about working with execution threads like asynchronous tasks,
see <a href="{@docRoot}guide/components/processes-and-threads.html">Processes
and Threads</a>.
</p>
<h2 id="draw-content">Drawing PDF Page Content</h2>
<p>When your application prints, your application must generate a PDF document and pass it to
the Android print framework for printing. You can use any PDF generation library for this
purpose. This lesson shows how to use the {@link android.print.pdf.PrintedPdfDocument} class
to generate PDF pages from your content.</p>
<p>The {@link android.print.pdf.PrintedPdfDocument} class uses a {@link android.graphics.Canvas}
object to draw elements on an PDF page, similar to drawing on an activity layout. You can draw
elements on the printed page using the {@link android.graphics.Canvas} draw methods. The following
example code demonstrates how to draw some simple elements on a PDF document page using these
methods:</p>
<pre>
private void drawPage(PdfDocument.Page page) {
Canvas canvas = page.getCanvas();
// units are in points (1/72 of an inch)
int titleBaseLine = 72;
int leftMargin = 54;
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(36);
canvas.drawText("Test Title", leftMargin, titleBaseLine, paint);
paint.setTextSize(11);
canvas.drawText("Test paragraph", leftMargin, titleBaseLine + 25, paint);
paint.setColor(Color.BLUE);
canvas.drawRect(100, 100, 172, 172, paint);
}
</pre>
<p>When using {@link android.graphics.Canvas} to draw on a PDF page, elements are specified in
points, which is 1/72 of an inch. Make sure you use this unit of measure for specifying the size
of elements on the page. For positioning of drawn elements, the coordinate system starts at 0,0
for the top left corner of the page.</p>
<p>
<strong>Tip:</strong> While the {@link android.graphics.Canvas} object allows you to place print
elements on the edge of a PDF document, many printers are not able to print to the edge of a
physical piece of paper. Make sure that you account for the unprintable edges of the page when
you build a print document with this class.
</p>

View File

@@ -0,0 +1,175 @@
page.title=Printing HTML Documents
parent.title=Printing Content
parent.link=index.html
trainingnavtop=true
next.title=Printing Custom Documents
next.link=custom-docs.html
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#load-html">Load an HTML Document</a></li>
<li><a href="#print-job">Create a Print Job</a></li>
</ol>
</div>
</div>
<p>Printing out content beyond a simple photo on Android requires composing text and graphics in a
print document. The Android framework provides a way to use HTML to compose a document and
print it with a minimum of code.</p>
<p>In Android 4.4 (API level 19), the {@link android.webkit.WebView} class has been updated to
enable printing HTML content. The class allows you to load a local HTML resource or download
a page from the web, create a print job and hand it off to Android's print services.</p>
<p>This lesson shows you how to quickly build an HTML document containing text and graphics and
use {@link android.webkit.WebView} to print it.</p>
<h2 id="load-html">Load an HTML Document</h2>
<p>Printing an HTML document with {@link android.webkit.WebView} involves loading an HTML
resource or building an HTML document as a string. This section describes how to build an HTML
string and load it into a {@link android.webkit.WebView} for printing.</p>
<p>This view object is typically used as part of an activity layout. However, if your application
is not using a {@link android.webkit.WebView}, you can create an instance of the class
specifically for printing purposes. The main steps for creating this custom print view are:</p>
<ol>
<li>Create a {@link android.webkit.WebViewClient} that starts a print job after
the HTML resource is loaded.</li>
<li>Load the HTML resource into the {@link android.webkit.WebView} object.</li>
</ol>
<p>The following code sample demonstrates how to create a simple {@link
android.webkit.WebViewClient} and load an HTML document created on the fly:</p>
<pre>
private WebView mWebView;
private void doWebViewPrint() {
// Create a WebView object specifically for printing
WebView webView = new WebView(getActivity());
webView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}
&#64;Override
public void onPageFinished(WebView view, String url) {
Log.i(TAG, "page finished loading " + url);
createWebPrintJob(view);
mWebView = null;
}
});
// Generate an HTML document on the fly:
String htmlDocument = "&lt;html&gt;&lt;body&gt;&lt;h1&gt;Test Content&lt;/h1&gt;&lt;p&gt;Testing, " +
"testing, testing...&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;";
webView.loadDataWithBaseURL(null, htmlDocument, "text/HTML", "UTF-8", null);
// Keep a reference to WebView object until you pass the PrintDocumentAdapter
// to the PrintManager
mWebView = webView;
}
</pre>
<p class="note">
<strong>Note:</strong> Make sure your call for generating a print job happens in the {@link
android.webkit.WebViewClient#onPageFinished onPageFinished()} method of the {@link
android.webkit.WebViewClient} you created in the previous section. If you don't wait until page
loading is finished, the print output may be incomplete or blank, or may fail completely.
</p>
<p class="note">
<strong>Note:</strong> The example code above holds an instance of the
{@link android.webkit.WebView} object so that is it not garbage collected before the print job
is created. Make sure you do the same in your own implementation, otherwise the print process
may fail.
</p>
<p>
If you want to include graphics in the page, place the graphic files in the {@code assets/}
directory of your project and specify a base URL in the first parameter of the
{@link android.webkit.WebView#loadDataWithBaseURL loadDataWithBaseURL()} method, as shown in the
following code example:
</p>
<pre>
webView.loadDataWithBaseURL("file:///android_asset/images/", htmlBody,
"text/HTML", "UTF-8", null);
</pre>
<p>You can also load a web page for printing by replacing the
{@link android.webkit.WebView#loadDataWithBaseURL loadDataWithBaseURL()} method with
{@link android.webkit.WebView#loadUrl loadUrl()} as shown below.</p>
<pre>
// Print an existing web page (remember to request INTERNET permission!):
webView.loadUrl("http://developer.android.com/about/index.html");
</pre>
<p>When using {@link android.webkit.WebView} for creating print documents, you should be aware of
the following limitations:</p>
<ul>
<li>You cannot add headers or footers, including page numbers, to the document.</li>
<li>The printing options for the HTML document do not include the ability to print page
ranges, for example: Printing page 2 to 4 of a 10 page HTML document is not supported.</li>
<li>An instance of {@link android.webkit.WebView} can only process one print job at a time.</li>
<li>An HTML document containing CSS print attributes, such as landscape properties, is not
supported.</li>
<li>You cannot use JavaScript in a HTML document to trigger printing.</li>
</ul>
<p class="note">
<strong>Note:</strong> The content of a {@link android.webkit.WebView} object that is included in
a layout can also be printed once it has loaded a document.
</p>
<p>If you want to create a more customized print output and have complete control of the content
draw on the printed page, jump to the next lesson:
<a href="custom-docs.html">Printing a Custom Document</a> lesson.</p>
<h2 id="print-job">Create a Print Job</h2>
<p>After creating a {@link android.webkit.WebView} and loading your HTML content, your
application is almost done with its part of the printing process. The next steps are accessing
the {@link android.print.PrintManager}, creating a print adapter, and finally, creating a print
job. The following example illustrates how to perform these steps:</p>
<pre>
private void createWebPrintJob(WebView webView) {
// Get a PrintManager instance
PrintManager printManager = (PrintManager) getActivity()
.getSystemService(Context.PRINT_SERVICE);
// Get a print adapter instance
PrintDocumentAdapter printAdapter = webView.createPrintDocumentAdapter();
// Create a print job with name and adapter instance
String jobName = getString(R.string.app_name) + " Document";
PrintJob printJob = printManager.print(jobName, printAdapter,
new PrintAttributes.Builder().build());
// Save the job object for later status checking
mPrintJobs.add(printJob);
}
</pre>
<p>This example saves an instance of the {@link android.print.PrintJob} object for use by the
application, which is not required. Your application may use this object to track the progress of
the print job as it's being processed. This approach is useful when you want to monitor the status
of the print job in you application for completion, failure, or user cancellation. Creating an
in-app notification is not required, because the print framework automatically creates a system
notification for the print job.</p>

View File

@@ -0,0 +1,57 @@
page.title=Printing Content
page.tags="print","navigation","gesturedetector","scroller"
trainingnavtop=true
startpage=true
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>Dependencies and prerequisites</h2>
<ul>
<li>Android 4.4 (API Level 19) or higher</li>
</ul>
</div>
</div>
<p>
Android users frequently view content solely on their devices, but there are times when
showing someone a screen is not an adequate way to share information. Being able to print
information from your Android application gives users a way to see a larger version of the
content from your app or share it with another person who is not using your application.
Printing also allows them to create a snapshot of information that does not depend on having a
device, sufficient battery power, or a wireless network connection.
</p>
<p>
In Android 4.4 (API level 19) and higher, the framework provides services for printing images and
documents directly from Android applications. This training describes how to enable printing in
your application, including printing images, HTML pages and creating custom documents for
printing.
</p>
<h2>Lessons</h2>
<dl>
<dt>
<strong><a href="photos.html">Printing a Photo</a></strong>
</dt>
<dd>This lesson shows you how to print an image.</dd>
<dt>
<strong><a href="html-docs.html">Printing an HTML Document</a></strong>
</dt>
<dd>This lesson shows you how to print an HTML document.</dd>
<dt>
<strong><a href="custom-docs.html">Printing a Custom Document</a></strong>
</dt>
<dd>This lesson shows you how you connect to the Android print manager, create a print adapter
and build content for printing.</dd>
</dl>

View File

@@ -0,0 +1,84 @@
page.title=Printing Photos
parent.title=Printing Content
parent.link=index.html
trainingnavtop=true
next.title=Printing HTML Documents
next.link=html-docs.html
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#image">Print an Image</a></li>
</ol>
</div>
</div>
<p>
Taking and sharing photos is one of the most popular uses for mobile devices. If your application
takes photos, displays them, or allows users to share images, you should consider enabling printing
of those images in your application. The <a href="{@docRoot}tools/support-library/index.html"
>Android Support Library</a> provides a convenient function for enabling image printing using a
minimal amount of code and simple set of print layout options.
</p>
<p>This lesson shows you how to print an image using the v4 support library {@link
android.support.v4.print.PrintHelper} class.</p>
<h2 id="image">Print an Image</h2>
<p>The Android Support Library {@link android.support.v4.print.PrintHelper} class provides
a simple way to print of images. The class has a single layout option, {@link
android.support.v4.print.PrintHelper#setScaleMode setScaleMode()}, which allows you to print with
one of two options:</p>
<ul>
<li>{@link android.support.v4.print.PrintHelper#SCALE_MODE_FIT SCALE_MODE_FIT} - This
option sizes the image so that the whole image is shown within the printable area of the page.
</li>
<li>{@link android.support.v4.print.PrintHelper#SCALE_MODE_FILL SCALE_MODE_FILL} - This
option scales the image so that it fills the entire printable area of the page. Choosing this
setting means that some portion of the top and bottom, or left and right edges of the image is
not printed. This option is the default value if you do not set a scale mode.</li>
</ul>
<p>Both scaling options for {@link android.support.v4.print.PrintHelper#setScaleMode
setScaleMode()} keep the existing aspect ratio of the image intact. The following code example
shows how to create an instance of the {@link android.support.v4.print.PrintHelper} class, set the
scaling option, and start the printing process:</p>
<pre>
private void doPhotoPrint() {
PrintHelper photoPrinter = new PrintHelper(getActivity());
photoPrinter.setScaleMode(PrintHelper.SCALE_MODE_FIT);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.droids);
photoPrinter.printBitmap("droids.jpg - test print", bitmap);
}
</pre>
<p>
This method can be called as the action for a menu item. Note that menu items for actions that are
not always supported (such as printing) should be placed in the overflow menu. For more
information, see the <a href="{@docRoot}design/patterns/actionbar.html">Action Bar</a> design
guide.
</p>
<p>After the {@link android.support.v4.print.PrintHelper#printBitmap printBitmap()} method is
called, no further action from your application is required. The Android print user interface
appears, allowing the user to select a printer and printing options. The user can then print the
image or cancel the action. If the user chooses to print the image, a print job is created and a
printing notification appears in the system bar.</p>
<p>If you want to include additional content in your printouts beyond just an image, you must
construct a print document. For information on creating documents for printing, see the
<a href="html-docs.html">Printing an HTML Document</a> or
<a href="custom-docs.html">Printing a Custom Document</a>
lessons.</p>

View File

@@ -335,6 +335,30 @@ include the action bar on devices running Android 2.1 or higher."
</li>
</ul>
</li>
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/printing/index.html"
description=
"How to print photos, HTML documents, and custom documents from your app."
>Printing Content</a>
</div>
<ul>
<li><a href="<?cs var:toroot ?>training/printing/photos.html">
Photos
</a>
</li>
<li><a href="<?cs var:toroot ?>training/printing/html-docs.html">
HTML Documents
</a>
</li>
<li><a href="<?cs var:toroot ?>training/printing/custom-docs.html">
Custom Documents
</a>
</li>
</ul>
</li>
</ul>
</li>
<!-- End multimedia -->